consolodate migrate schema
This commit is contained in:
@@ -43,6 +43,8 @@
|
|||||||
- `monthly_bonuses` — famId, month, prizeType, prizeValue, winnerUserId
|
- `monthly_bonuses` — famId, month, prizeType, prizeValue, winnerUserId
|
||||||
- `settings` — famId, pointsThreshold, weeklyBonus, webhookUrl
|
- `settings` — famId, pointsThreshold, weeklyBonus, webhookUrl
|
||||||
|
|
||||||
|
> **Schema/migrations:** `shared/pb/schema.ts` (`SCHEMA_PLAN`) is the single source of truth for base collections. `frontend/src/lib/server/migrate.ts` only **bootstraps** a fresh/wiped PB (idempotent, skips if `fams` exists) — it has no incremental history. The native `users` auth fields/rules and the superuser-only `otp` collection are applied in `migrate.ts` (`ensureUsers`/`ensureOtp`), not `SCHEMA_PLAN`. Data is disposable (app not live), so a schema change = update `SCHEMA_PLAN` + wipe PB + reboot.
|
||||||
|
|
||||||
## Routes
|
## Routes
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# FamChore v2 — Development Memory
|
# FamChore v2 — Development Memory
|
||||||
|
|
||||||
|
## 2026-08-17 — Schema collapse to single source of truth (Option 1)
|
||||||
|
|
||||||
|
- **Decision**: abandoned incremental migration history. `SCHEMA_PLAN` (`shared/pb/schema.ts`) is now the true, current schema; `migrate.ts` collapsed from 2096 → 183 lines to a **fresh-only bootstrap** (`ensureSchema()` skips if `fams` exists — no incremental steps). The app isn't live and data is disposable, so there's nothing to preserve; a schema change = update `SCHEMA_PLAN` + wipe PB + reboot.
|
||||||
|
- **Folded the net effect of ~40 hand-written steps into `SCHEMA_PLAN`** (verified against the live PB): `fams.{payday,lastIssued,paydayTime,timezone}` (dropped stale `seasons`), `settings.simulateEow`, `messages.clientId`, `assigned_chores.{isTodo,startDate,completeBy}`. `bonus_configs.memberId`, `weekly_history/rewards/assigned_chores/completions.memberId` → `users`.
|
||||||
|
- **Out of `SCHEMA_PLAN`** (handled in `migrate.ts`): the native `users` auth collection (custom `famId`/`role`/`username`/`color` fields + `username` unique index + password-auth identity + famId-scoped rules, via `ensureUsers`) and the superuser-only `otp` collection (null rules — `col()` can't express `null`, via `ensureOtp`).
|
||||||
|
- **Gotcha**: `col()` coerces `rules.listRule ?? ""` → can't emit `null` rules, so `otp` stays out of the plan. `ensureSchema` needs the live PB to confirm the true schema (SCHEMA_PLAN was stale before this).
|
||||||
|
- Verify path: wipe dev PB + restart frontend (needs user OK) so `migrateOnBoot` rebuilds from `SCHEMA_PLAN`.
|
||||||
|
|
||||||
## 2026-08-17 — Hono proxy removed: everything runs in SvelteKit services
|
## 2026-08-17 — Hono proxy removed: everything runs in SvelteKit services
|
||||||
|
|
||||||
- **Decision**: deleted the `proxy/` Hono service entirely. All business logic (admin CRUD, member kanban, weekly summary/EOW, bonus evaluation/trigger/progress, rewards claim/issue, chat, payday settlement, debug data-gen) now lives in `frontend/src/lib/server/services/`, grouped **by app area** (not by role): `fam.ts`, `chores.ts`, `completions.ts`, `rewards.ts`, `bonuses.ts`, `chat.ts`, `settings.ts`, `crud.ts`, `debug.ts`, plus a generic per-resource `crud.ts`. `createServices(pb, user)` returns a per-feature binder; `servicesFor(event)` is the shorthand for loads/form actions. **No role guard** — PB collection rules on the acting user's token are the security boundary (the `admin`/`member` split no longer exists as separate files).
|
- **Decision**: deleted the `proxy/` Hono service entirely. All business logic (admin CRUD, member kanban, weekly summary/EOW, bonus evaluation/trigger/progress, rewards claim/issue, chat, payday settlement, debug data-gen) now lives in `frontend/src/lib/server/services/`, grouped **by app area** (not by role): `fam.ts`, `chores.ts`, `completions.ts`, `rewards.ts`, `bonuses.ts`, `chat.ts`, `settings.ts`, `crud.ts`, `debug.ts`, plus a generic per-resource `crud.ts`. `createServices(pb, user)` returns a per-feature binder; `servicesFor(event)` is the shorthand for loads/form actions. **No role guard** — PB collection rules on the acting user's token are the security boundary (the `admin`/`member` split no longer exists as separate files).
|
||||||
|
|||||||
+85
-1997
File diff suppressed because it is too large
Load Diff
+16
-4
@@ -1,9 +1,14 @@
|
|||||||
// Single source of truth for the PocketBase schema + field builders.
|
// Single source of truth for the PocketBase schema + field builders.
|
||||||
// Consumed by BOTH proxy/src/migrate.ts (idempotent bootstrap) and
|
// Consumed by frontend/src/lib/server/migrate.ts (idempotent bootstrap) so the
|
||||||
// proxy/scripts/seed.ts (fresh-store seed) so the schema isn't duplicated.
|
// schema isn't duplicated.
|
||||||
//
|
//
|
||||||
// Relations reference collections by name; the `ids` map maps collection
|
// Relations reference collections by name; the `ids` map maps collection
|
||||||
// name -> runtime id (filled as each collection is created).
|
// name -> runtime id (filled as each collection is created).
|
||||||
|
//
|
||||||
|
// NOTE: the native `users` auth collection and the superuser-only `otp`
|
||||||
|
// collection are NOT in SCHEMA_PLAN — they're applied separately in
|
||||||
|
// migrate.ts (users is PB's built-in auth model; `otp` needs null rules,
|
||||||
|
// which the `col()` builder can't express). Everything else lives here.
|
||||||
|
|
||||||
export interface FieldDef {
|
export interface FieldDef {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -128,7 +133,10 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
|||||||
uniqueText("slug"),
|
uniqueText("slug"),
|
||||||
text("stripeCustomerId"),
|
text("stripeCustomerId"),
|
||||||
jsonField("featureFlags"),
|
jsonField("featureFlags"),
|
||||||
jsonField("seasons"),
|
number("payday"),
|
||||||
|
text("lastIssued"),
|
||||||
|
text("paydayTime"),
|
||||||
|
text("timezone"),
|
||||||
],
|
],
|
||||||
{ listRule: RULE_OWN_FAM, viewRule: RULE_OWN_FAM, updateRule: RULE_OWN_FAM },
|
{ listRule: RULE_OWN_FAM, viewRule: RULE_OWN_FAM, updateRule: RULE_OWN_FAM },
|
||||||
)(ids),
|
)(ids),
|
||||||
@@ -156,7 +164,7 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
|||||||
{
|
{
|
||||||
name: "settings",
|
name: "settings",
|
||||||
build: (ids) =>
|
build: (ids) =>
|
||||||
col("settings", [rel("famId", ids.fams, true), text("webhookUrl")], {
|
col("settings", [rel("famId", ids.fams, true), text("webhookUrl"), bool("simulateEow")], {
|
||||||
createRule: RULE_PARENT_WRITE,
|
createRule: RULE_PARENT_WRITE,
|
||||||
updateRule: RULE_PARENT_SCOPED,
|
updateRule: RULE_PARENT_SCOPED,
|
||||||
deleteRule: RULE_PARENT_SCOPED,
|
deleteRule: RULE_PARENT_SCOPED,
|
||||||
@@ -246,6 +254,7 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
|||||||
// Explicit createdAt: PB 0.39 does NOT auto-add createdAt to
|
// Explicit createdAt: PB 0.39 does NOT auto-add createdAt to
|
||||||
// API-created collections (0.25 did). Chat filters/sorts on it.
|
// API-created collections (0.25 did). Chat filters/sorts on it.
|
||||||
date("createdAt"),
|
date("createdAt"),
|
||||||
|
text("clientId"),
|
||||||
], {
|
], {
|
||||||
createRule: RULE_FAM_WRITE,
|
createRule: RULE_FAM_WRITE,
|
||||||
updateRule: RULE_FAM_SCOPED,
|
updateRule: RULE_FAM_SCOPED,
|
||||||
@@ -302,6 +311,9 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
|||||||
number("value", true),
|
number("value", true),
|
||||||
text("customName"),
|
text("customName"),
|
||||||
jsonField("seasonIds"),
|
jsonField("seasonIds"),
|
||||||
|
bool("isTodo"),
|
||||||
|
text("startDate"),
|
||||||
|
text("completeBy"),
|
||||||
], {
|
], {
|
||||||
createRule: RULE_PARENT_WRITE,
|
createRule: RULE_PARENT_WRITE,
|
||||||
updateRule: RULE_PARENT_SCOPED,
|
updateRule: RULE_PARENT_SCOPED,
|
||||||
|
|||||||
Reference in New Issue
Block a user