# persona-community-5

AI Persona Generation Community

## Find Your Guide

| If you need to... | Read this |
|-------------------|-----------|
| **Set up local dev** | [local/setup.md](.claude/guides/local/setup.md) |
| **Build a feature** | [feature-development.md](.claude/guides/feature-development.md) |
| **Backend API patterns** | [backend/api-patterns.md](.claude/guides/backend/api-patterns.md) |
| **Frontend design system** | [frontend/design-system.md](.claude/guides/frontend/design-system.md) |
| **Auth & user management** | [auth.md](.claude/guides/auth.md) |
| **Event channels** | [events.md](.claude/guides/events.md) |
| **Media pipeline** | [media.md](.claude/guides/media.md) |
| **Album generation** | [album.md](.claude/guides/album.md) |
| **Generate personas** | [personagen.md](.claude/guides/personagen.md) |
| **Deploy** | [ops/deploying.md](.claude/guides/ops/deploying.md) |

## Quick Reference

```bash
# Start local dev
./scripts/dev.sh

# Run quality checks
./scripts/quality.sh

# List all components
./scripts/discover.sh
```

## Critical Rules

- **Handler pattern:** All handlers return `error`, wrapped with `app.Wrap()`. HTTPErrors map to status codes; raw errors become 500.
- **Request binding:** Always use `app.Bind()` or `app.BindAndValidate()`. Never use raw `json.NewDecoder`.
- **URL parameters:** Use brace syntax `{param}` for chi URL parameters. NEVER use colon syntax `:param` - it won't work and will cause 404s. Extract with `chi.URLParam(r, "param")`.
- **Error types:** Use `httperror.BadRequest`, `httperror.NotFound`, etc. Never bare `http.Error()`.
- **Response envelope:** Use `httpresponse.OK`, `httpresponse.Created`, `httpresponse.NoContent`. All responses use `{data, meta}` envelope.
- **Auth middleware:** Auth is opt-in. Use `auth.Middleware()` in route groups for protected endpoints.
- **OpenAPI first:** Document endpoints in `spec.go` using `openapi.*` helpers. Mount with `application.EnableDocs(spec)`.
- **CSS variables:** All UI components use CSS custom properties (`var(--background)`, `var(--accent)`, etc.). Never hardcode colors.
- **Monorepo imports:** Go packages from `git.threesix.ai/jordan/persona-community-5/pkg/*`, TypeScript from `@persona-community-5/*`.
- **Database:** Production uses **CockroachDB** (provisioned by the platform). Local dev uses **PostgreSQL** via docker-compose. Both are wire-compatible via `lib/pq`. Write SQL compatible with both — avoid PostgreSQL-only features (advisory locks, listen/notify, tsvector).
- **NO WEBSOCKETS. EVER.** All real-time communication uses HTTP2 + SSE. User → server is HTTP2 POST. Server → user is SSE. This includes chat, notifications, progress, everything.
- **Event flow:** `POST → Service (enqueue) → Queue → Worker (generate) → Redis pub/sub → Service SSE subscriber → User`. Service is thin, worker does AI work.
- **Channel naming:** `user:<id>` = events for a specific user. `channel:<id>` = events for a topic/room/resource. Document all channels in `./docs/channels.md`.
- **Media uploads:** POST returns job ID immediately. Progress and result come via SSE events. Never wait synchronously.
- **Media generation:** Same pattern - POST queues job, returns ID, results via SSE. Video takes 2-5 min; never block HTTP. Text generation streams `ai_chat_chunk` events token-by-token.
- **Media storage:** Backend returns complete URLs. Never construct storage paths in frontend. Variants (thumbnail, optimized) auto-generated.
- **No fake progress:** Never simulate progress with timers. Real progress comes from real events.
- **Auth tokens:** 15-minute access tokens with embedded session ID (`sid`). Refresh via POST `/auth/refresh`. Session revocation invalidates all tokens for that session.
- **Passwords:** Bcrypt cost 12, min 8 chars, max 72. Hashing lives in `pkg/auth/password.go`. Never store plaintext.
- **Auth codes:** OTP/magic link/reset codes are single-use and time-limited. In standalone dev mode (no `DATABASE_URL`), the code is **always** logged to stdout as `[DEV] auth code created — use this code to log in code=XXXXXX` — check the server terminal to get it. This works even when `NOTIFY_URL` is set. In production (with `DATABASE_URL`), emails go through the notify service (`NOTIFY_URL`/`NOTIFY_API_KEY`/`NOTIFY_HOST`/`NOTIFY_FROM`).
- **Dev user:** Set `DEV_USER_EMAIL=you@example.com` (and optionally `DEV_USER_PASSWORD`) to seed your account into the in-memory store on startup so it survives restarts without re-registering.

## Architecture

```
persona-community-5/
├── services/     # Go API services (port 8001+)
├── workers/      # Background workers (no port)
├── apps/         # Frontend applications (port 3001+)
├── cli/          # CLI tools (no port)
├── packages/     # Shared TypeScript packages
│   ├── ui/       # UI components (@persona-community-5/ui)
│   ├── layout/   # Dashboard layout (@persona-community-5/layout)
│   ├── auth/     # Auth provider (@persona-community-5/auth)
│   ├── api-client/ # Typed API client (@persona-community-5/api-client)
│   └── logger/   # HTTP/console logger (@persona-community-5/logger)
├── pkg/          # Shared Go packages
│   ├── app/      # Service bootstrapper (Wrap, Bind, Health)
│   ├── chassis/  # Facade re-exporting app types
│   ├── openapi/  # OpenAPI 3.0 spec builder + Scalar docs
│   ├── httperror/ # Typed HTTP errors
│   ├── httpresponse/ # Response envelope helpers
│   ├── httpvalidation/ # Struct validation
│   ├── middleware/ # RequestID, CORS, Recovery, Logger
│   ├── auth/     # JWT, API key, middleware
│   ├── config/   # Viper-based configuration
│   ├── httpclient/ # Resilient HTTP client
│   └── logging/  # slog wrapper
└── scripts/      # Development & CI scripts
```

| Slot | Language | Port Range | Purpose |
|------|----------|------------|---------|
| services/ | Go | 8001+ | REST APIs, backend services |
| workers/ | Go | none | Background jobs, queue consumers |
| apps/ | TypeScript | 3001+ | React, Next.js, Astro frontends |
| cli/ | Go | none | CLI tools, scripts |
| packages/ | TypeScript | none | Shared frontend packages |
| pkg/ | Go | none | Shared backend packages |

## Components

| Component | Type | Path |
|-----------|------|------|
| **persona-api** | API service | `services/persona-api/` |
| **media-worker** | Background worker | `workers/media-worker/` |
| **creator-ui** | React app | `apps/creator-ui/` |

