feature plus ux rearrangements
This commit is contained in:
@@ -10,9 +10,10 @@
|
||||
|
||||
## Stack
|
||||
|
||||
- SvelteKit (SSR frontend, internal :2080) + Hono proxy (internal :3456) + nginx (container :3001)
|
||||
- SvelteKit monolith (SSR frontend + all services, internal :2080; nginx in prod container :3001). The Hono proxy was deleted — everything lives in SvelteKit server routes/services.
|
||||
- PocketBase (separate Coolify service at `pb.chores.app.com`, :8090)
|
||||
- Stripe payments (subscriptions) — **planned in SvelteKit server routes** (`/account` + `/account/webhook`), NOT the Hono proxy. Not yet implemented (only `settings.webhookUrl` + `fams.stripeCustomerId` exist).
|
||||
- Stripe payments (subscriptions) — implemented in **SvelteKit server routes** (public `/pricing` + inline signup checkout via `PricingPlans`, billing portal from settings Billing section, `/api/webhooks/stripe`). Dev webhook listener: `pnpm stripe:listen` (root script). Embedded Checkout needs a secure context (HTTPS/localhost) — over Tailscale/LAN HTTP use `ssh -L 2080:localhost:2080`.
|
||||
- Access gating — `fams.paymentMode` (`none|code|sub|canceled`) + `fams.active`; codes in superuser-only `accesscodes` (seeded `dev123`). Core logic in `frontend/src/lib/server/access.ts`, exposed as `data.famAccess` from `[fam]/+layout.server.ts`; disabled fams get a blurred overlay + locked member kanban (frontend-only); `/settings` stays unlocked so admins can apply a code.
|
||||
- Coolify CRON → `GET /api/weekly-cron` — **not implemented** (weekly settlement is manual via `complete-week`/`simulateEow`)
|
||||
- Deployment: Coolify, Cloudflare DNS
|
||||
|
||||
@@ -34,7 +35,9 @@
|
||||
|
||||
- `users` — auth collection; famId, role (`parent`|`child`), username (`{famSlug}:{handle}`), name, color, email (admin only)
|
||||
- `otp` — famId, userId, otp, updatedAt (OTP gate for child join; display colour lives on `users.color`)
|
||||
- `fams` — name, slug, stripeCustomerId, featureFlags
|
||||
- `accesscodes` — value (unique), name, duration, expiry, active, createdAt (superuser-only; platform access codes)
|
||||
- `platform` — label (`global` singleton), flags (json) — platform feature flags; **public read** (empty list/view rules), superuser-only writes. Loaded on every page via root `+layout.server.ts` as `page.data.platformFlags`; toggle via `/admin` Platform Flags card. The `debug` flag gates dev-only CTAs (e.g. settings "Revoke code").
|
||||
- `fams` — name, slug, stripeCustomerId, paymentMode (`none|code|sub|canceled`), active, accessCodeId, accessCodeEnteredAt
|
||||
- `chore_templates` — famId, name, defaultValue, defaultFrequency
|
||||
- `assigned_chores` — famId, userId, templateId, frequency, value
|
||||
- `completions` — famId, userId, assignedChoreId, date
|
||||
@@ -51,8 +54,8 @@
|
||||
/ Landing (SaaS marketing)
|
||||
/admin Platform super-admin stats dashboard (and any donations)
|
||||
/login · /logout Parent email/password login / logout
|
||||
/signup Parent + family signup
|
||||
/{famSlug}/join/{username} Member invite (OTP join), auto-fills from ?code=
|
||||
/signup Parent + family signup (wizard: fam → child → code → plan)
|
||||
/{fam}/join/{username} Member invite (OTP join), auto-fills from ?code=
|
||||
/{fam} Fam dashboard
|
||||
/{fam}/{username} Parent → admin overview, Child → member kanban (role from session)
|
||||
/{fam}/{username}/chores Chore templates & assignment grid
|
||||
@@ -60,10 +63,9 @@
|
||||
/{fam}/{username}/bonuses Bonus configs & evaluation
|
||||
/{fam}/{username}/preferences User preferences (parent→users, member→users)
|
||||
/{fam}/{username}/settings Family admin settings (parent only) — includes Stripe connect/manage + pause
|
||||
/account Account/billing — payment setup & subscription management (Stripe)
|
||||
/subscriptions 3-tier plan page (trial | monthly | yearly), access via settings
|
||||
/account/webhook Stripe webhook handler (server route)
|
||||
/api/* Hono proxy (data layer; CRON not implemented)
|
||||
/pricing 3-tier public plan page (trial | monthly | yearly), entry via settings or logged-out
|
||||
/api/webhooks/stripe Stripe webhook handler (server route)
|
||||
/api/* SvelteKit API endpoints (data layer; CRON not implemented)
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
@@ -76,12 +78,12 @@
|
||||
|
||||
### Writes
|
||||
|
||||
- **Chore toggle:** Browser → Hono proxy → PB (member auth via `Authorization: Bearer <pb_token>`)
|
||||
- **Admin CRUD:** Form actions / `hono.admin.*` → Hono proxy → PB (admin JWT via `sessionHeaders`)
|
||||
- **Member updates:** Browser → Hono proxy → PB (auth via `Bearer <pb_token>`)
|
||||
- **Reward creation:** After completion toggle, Hono proxy creates reward if threshold met
|
||||
- **Chore toggle:** Browser → SvelteKit `/api/completions/toggle` → PB (session cookie auth)
|
||||
- **Admin CRUD:** Form actions / `/api/admin/*` endpoints → PB via services (`servicesFor(event)`); PB collection rules are the security boundary
|
||||
- **Member updates:** Browser → SvelteKit `/api/*` routes → PB
|
||||
- **Reward creation:** After completion toggle, service layer creates reward if threshold met
|
||||
- **Weekly settlement:** NOT via CRON — manual `complete-week` action or `simulateEow` preview in settings. `/api/weekly-cron` (Coolify) is not implemented.
|
||||
- **Stripe:** implemented in SvelteKit server routes — `/account` (setup/manage subscription) + `/account/webhook`. Lives in the frontend app, NOT the Hono proxy. **WhatsApp:** not implemented.
|
||||
- **Stripe:** implemented in SvelteKit server routes — `/pricing` (public plan picker; logged-in users checkout inline) + settings Billing section (billing portal) + `/api/webhooks/stripe`. **WhatsApp:** not implemented.
|
||||
|
||||
### UI reactivity
|
||||
|
||||
@@ -203,20 +205,19 @@ All admin and member pages use the following pattern:
|
||||
- Every collection query includes `famId = @request.auth.famId` filter
|
||||
- Super admin bypasses famId filter (access via PB admin API)
|
||||
- Child PB passwords are derived (`MEMBER_SECRET + famSlug + username`); the child join gate is a transient OTP in `otp`. No device tokens. Never log raw tokens/secrets.
|
||||
- **Admin → Proxy**: `hono.admin.*` in `$lib/server/hono.ts` — uses `sessionHeaders(event)` (server-side only, requires `RequestEvent`)
|
||||
- **Member → Proxy (server)**: `memberApi.*` in `$lib/client/api.ts` — use inside `+page.server.ts` load/actions; `BASE_URL` resolves to Hono port on server
|
||||
- **Member → Proxy (browser)**: `memberApi.*` in `$lib/client/api.ts` — use inside `+page.svelte`; `BASE_URL` is empty, Vite proxies `/api/*` to Hono
|
||||
- **Server data access**: `servicesFor(event)` / `createServices(pb)` in `$lib/server/services/`; superuser ops via `pbAdmin` facade (`$lib/server/pocketbase.ts`)
|
||||
- **Browser data access**: fetch to same-origin `/api/*` SvelteKit endpoints; httpOnly `pb_token` cookie is the auth
|
||||
- **`$page`**: import `{ page }` from `$app/state` (NOT `$app/stores` — that's the old Svelte 4 API). Reference as `page.params.fam`, `page.url.pathname` etc. without `$` prefix
|
||||
- **Dates**: all user-facing dates are DDMMYY (compact, e.g. `040826` for 4 Aug 2026). Use the shared `formatDDMMYY()` helper in `frontend/src/lib/format.ts`. Never render raw `YYYY-MM-DD` to users. Exception: single human-readable dates like todo **due dates** should use `formatShortDate()` (also in `format.ts`, renders `5 Aug` / `5 Aug 26`) — the compact DDMMYY code is ambiguous and bad UI for those.
|
||||
- `config.ts` at root for dev/build-time shared config (e.g. `PROXY_PORT`); runtime config via env vars
|
||||
- `.env` at root tracks port values (`PROXY_PORT`, `PORT`); `.env.example` committed as template
|
||||
- Docker: `docker/Dockerfile` (prod, multi-stage + nginx) + `docker/Dockerfile.dev` (PocketBase)
|
||||
- Nginx routes in prod: `/api/*` → Hono (`:3456`), `/*` → SvelteKit (`:2080`)
|
||||
- Nginx routes in prod: `/*` → SvelteKit (`:2080`), `/pb/*` → PocketBase
|
||||
- Ports: frontend `2080`, proxy `3456`, container ext `3001` (port `3000` is reserved)
|
||||
- **Dev servers: NEVER start your own.** Always reuse the running dev servers — proxy `192.168.1.225:3456` (tsx watch, reloads on edit), frontend `localhost:2080` (vite HMR). Don't spawn `nohup pnpm dev` / `tsx watch` / extra vite instances. Only restart when the user explicitly asks.
|
||||
- Environment: `FRONTEND_PORT`, `PROXY_PORT`, `PB_PORT`, `PB_EMAIL`, `PB_PASSWORD`, `DEBUG_RECORD_ID`, `STRIPE_SECRET_KEY`, `DONATION_MODAL_INTERVAL`
|
||||
- Seed via JSON dump (portable for dev)
|
||||
- Monorepo: SvelteKit in `frontend/`, Hono in `proxy/`, two Dockerfiles
|
||||
- Monorepo: SvelteKit in `frontend/` (+ root `shared/`), single app Dockerfile + PB Dockerfile.dev
|
||||
- Decisions tracked in `MEMORY.md`
|
||||
|
||||
## Build Phases (must validate each before next)
|
||||
@@ -247,7 +248,7 @@ All admin and member pages use the following pattern:
|
||||
3.5 Reward claim flow + admin CRUD
|
||||
3.6 Monthly bonus evaluation
|
||||
3.7 CRON handler (Coolify → Hono)
|
||||
3.8 Stripe checkout + webhook (SvelteKit `/account` server routes, not Hono)
|
||||
3.8 Stripe checkout + webhook (SvelteKit server routes, not Hono)
|
||||
3.9 Notification interface (WhatsApp deferred)
|
||||
|
||||
### Phase 4 — Frontend App
|
||||
|
||||
Reference in New Issue
Block a user