5.3 KiB
5.3 KiB
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 viacolspropCard— 1/2/3 col span, micro-layout per pageAccordion— for settings / log sectionsButton— consistent CTAs withvariant(primary/secondary/ghost/danger) andsize(sm/md/lg)
Components (frontend/src/lib/components/)
Sidebar.svelte,TopNav.svelte,Footer.svelteViewHeader.svelte,Card.svelte,CardGrid.svelteButton.svelte,Accordion.svelteicons.ts— SVG icon strings (no icon library dep)
Role-Based Auth (Jul 2026)
- Members have
rolefield ('parent' | 'child', added tomemberscollection) - Parents authenticate via email/password (PB session JWT), children via device token
/api/admin/signupnow creates a member record for the parent withrole: 'parent'/api/admin/loginreturnsmemberName,memberColor,rolealongside session info/api/members/verify-tokenreturnsrolefor the frontendrequireAdminmiddleware unchanged (still checksfam_admins)- Frontend sidebar is role-aware:
isParent = session !== null - No more
/adminprefix — admin pages live under/{fam}/{parent-username}/choresetc.
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. Port3000reserved/conflict. - Shared config:
config.tsat root for dev/build-time values (e.g.PROXY_PORT). Runtime config via env vars..envtracks ports,.env.examplecommitted. - Docker: 2 Dockerfiles —
Dockerfile(prod, multi-stage with nginx) andDockerfile.dev(PocketBase for dev). - Nginx: Prod container uses nginx to route
/api/*→ Hono (:3456),/*→ SvelteKit (:2080). - Dev workflow:
pnpm devat root runs SvelteKit + Hono in parallel. PocketBase viaDockerfile.dev. - Proxy runtime: Uses
process.env.PROXY_PORTinstead of importingconfig.ts(avoidsrootDirissues intsc).
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
/debugpage's PB SDKsubscribe()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.tsandjoin/[code]/[member]/+page.server.tscalledsetSessionCookie()withuserId: memberId(the child's PB record ID). This madeevent.locals.sessiontruthy for children, causing[username]/+page.server.tsto enter the admin branch and callhono.admin.*endpoints. The proxy'srequireAdmincheckedfam_adminsfor the child's member ID (which doesn't exist) and returned 401. - Fix: Removed
setSessionCookie()from both join pages. Children only get adevice_tokencookie. The session cookie is only for email/password-authenticated parents, set by/loginand/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.