Files
famdone/MEMORY.md
T
2026-07-29 09:41:52 +01:00

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 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.
  • 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.