# 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:` = events for a specific user. `channel:` = 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/` |