# FamChore v2 — Development Memory ## UI Component Architecture (Jul 2026) ### Layout Hierarchy ``` +layout.svelte ← global styles, meta, favicon ├── /login, /signup, /join/* ← auth pages (no shell) └── [fam]/+layout.svelte ← Shell: Sidebar + TopNav + Footer + claim toast ├── [fam]/+page.svelte ← fam dashboard ├── [fam]/{username}/+page.svelte ← parent=admin overview, child=kanban ├── [fam]/{username}/chores/+page.svelte ← parent only ├── [fam]/{username}/rewards/+page.svelte ← parent only ├── [fam]/{username}/bonuses/+page.svelte ← parent only ├── [fam]/{username}/settings/+page.svelte ← parent only └── [fam]/{username}/preferences/+page.svelte ← both roles ``` ### Sidebar (collapsible to mini-mode) - Header: app name (FamChore) - Admin CTAs: Dashboard, Chores, Rewards (badge count), Bonuses - Member CTAs: Dashboard, Preferences - Footer: family name, Settings (admin only), Log out - Role-aware: items differ based on admin vs member route ### TopNav - Slot `announcement` (center) — system/family messages - Slot `actions` (right) — user status, claim/message ### Page Content - `ViewHeader` — title + subtitle + tool bar (tabs, weeknav, sort) - `CardGrid` — 3-column grid, Cards span columns via `cols` prop - `Card` — 1/2/3 col span, micro-layout per page - `Accordion` — for settings / log sections - `Button` — consistent CTAs with `variant` (primary/secondary/ghost/danger) and `size` (sm/md/lg) ### Components (frontend/src/lib/components/) - `Sidebar.svelte`, `TopNav.svelte`, `Footer.svelte` - `ViewHeader.svelte`, `Card.svelte`, `CardGrid.svelte` - `Button.svelte`, `Accordion.svelte` - `icons.ts` — SVG icon strings (no icon library dep) ### Role-Based Auth (Jul 2026) - Members have `role` field (`'parent' | 'child'`, added to `members` collection) - Parents authenticate via email/password (PB session JWT), children via device token - `/api/admin/signup` now creates a member record for the parent with `role: 'parent'` - `/api/admin/login` returns `memberName`, `memberColor`, `role` alongside session info - `/api/members/verify-token` returns `role` for the frontend - `requireAdmin` middleware unchanged (still checks `fam_admins`) - Frontend sidebar is role-aware: `isParent = session !== null` - **No more `/admin` prefix** — admin pages live under `/{fam}/{parent-username}/chores` etc. ### Routes (Jul 2026) ``` / Landing (SaaS marketing) /signup Signup (creates parent user + member) /login Login (returns member info, redirects to /{fam}/{memberName}) /join/:code Member invite (child) /join/:code/:member Member invite with pre-selected name /admin Super admin dashboard (unchanged) /{fam} Fam dashboard /{fam}/{username} Parent → admin overview, Child → kanban /{fam}/{username}/chores Parent: chore management /{fam}/{username}/rewards Parent: reward ledger /{fam}/{username}/bonuses Parent: bonus configs /{fam}/{username}/settings Parent: family settings /{fam}/{username}/preferences Both: edit name/color /api/* Hono proxy ``` ### Architecture Decisions ### 2026-06-23 — Monorepo & Docker Setup - **Ports**: Frontend = `2080`, Proxy = `3456`, Container ext = `3001`. Port `3000` reserved/conflict. - **Shared config**: `config.ts` at root for dev/build-time values (e.g. `PROXY_PORT`). Runtime config via env vars. `.env` tracks ports, `.env.example` committed. - **Docker**: 2 Dockerfiles — `Dockerfile` (prod, multi-stage with nginx) and `Dockerfile.dev` (PocketBase for dev). - **Nginx**: Prod container uses nginx to route `/api/*` → Hono (`:3456`), `/*` → SvelteKit (`:2080`). - **Dev workflow**: `pnpm dev` at root runs SvelteKit + Hono in parallel. PocketBase via `Dockerfile.dev`. - **Proxy runtime**: Uses `process.env.PROXY_PORT` instead of importing `config.ts` (avoids `rootDir` issues in `tsc`). ### 2026-06-23 — Hono Proxy for All Data; Svelte Reactivity Only - **All data operations** (reads and writes) go through the Hono proxy, never directly to PB SDK. - **UI reactivity** is purely Svelte `$state` / `$derived` / `$effect` — no PB SDK `.subscribe()` / SSE. - The `/debug` page's PB SDK `subscribe()` was experimental only; final apps fetch via Hono proxy and update Svelte state reactively. ### 2026-07-28 — Auth Bug: Join Flow Set Session Cookie for Children - **Bug**: Both `join/[code]/+page.server.ts` and `join/[code]/[member]/+page.server.ts` called `setSessionCookie()` with `userId: memberId` (the child's PB record ID). This made `event.locals.session` truthy for children, causing `[username]/+page.server.ts` to enter the admin branch and call `hono.admin.*` endpoints. The proxy's `requireAdmin` checked `fam_admins` for the child's member ID (which doesn't exist) and returned 401. - **Fix**: Removed `setSessionCookie()` from both join pages. Children only get a `device_token` cookie. The session cookie is only for email/password-authenticated parents, set by `/login` and `/signup`. - **Lesson**: Children must never get a session cookie. The auth table in AGENTS.md says "Member → device token, no expiry" — the code must match.