migrate from hono
This commit is contained in:
+83
-16
@@ -69,20 +69,43 @@ export function rel(name: string, collectionId: string, required = false): Field
|
||||
};
|
||||
}
|
||||
|
||||
// ── Per-user access rules ──
|
||||
// The app writes directly to PB as the authenticated user (their own token),
|
||||
// so PB enforces famId scoping instead of running everything as superuser.
|
||||
// Only genuinely privileged app-level actions (signup, OTP join, member
|
||||
// creation, superuser dashboard, CRON/webhook) use the superuser client.
|
||||
//
|
||||
// Admin-only collections require role='parent'; child-accessible collections
|
||||
// (completions toggle, reward claim, chat) are scoped by famId alone.
|
||||
export const RULE_PARENT_WRITE =
|
||||
"@request.body.famId = @request.auth.famId && @request.auth.role = 'parent'";
|
||||
export const RULE_PARENT_SCOPED =
|
||||
"famId = @request.auth.famId && @request.auth.role = 'parent'";
|
||||
export const RULE_FAM_WRITE = "@request.body.famId = @request.auth.famId";
|
||||
export const RULE_FAM_SCOPED = "famId = @request.auth.famId";
|
||||
// fams has no self-referencing famId field; its record id IS the famId.
|
||||
export const RULE_OWN_FAM = "id = @request.auth.famId";
|
||||
|
||||
// ── Collection builder ──
|
||||
export function col(
|
||||
name: string,
|
||||
fields: FieldDef[],
|
||||
rules: { listRule?: string | null; viewRule?: string | null } = {},
|
||||
rules: {
|
||||
listRule?: string | null;
|
||||
viewRule?: string | null;
|
||||
createRule?: string | null;
|
||||
updateRule?: string | null;
|
||||
deleteRule?: string | null;
|
||||
} = {},
|
||||
): (ids: Record<string, string>) => CollectionDef {
|
||||
return (ids) => ({
|
||||
name,
|
||||
type: "base",
|
||||
listRule: rules.listRule ?? "",
|
||||
viewRule: rules.viewRule ?? "",
|
||||
createRule: null,
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
createRule: rules.createRule ?? null,
|
||||
updateRule: rules.updateRule ?? null,
|
||||
deleteRule: rules.deleteRule ?? null,
|
||||
fields,
|
||||
});
|
||||
}
|
||||
@@ -107,7 +130,7 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
jsonField("featureFlags"),
|
||||
jsonField("seasons"),
|
||||
],
|
||||
{ listRule: null, viewRule: null },
|
||||
{ listRule: RULE_OWN_FAM, viewRule: RULE_OWN_FAM, updateRule: RULE_OWN_FAM },
|
||||
)(ids),
|
||||
},
|
||||
{
|
||||
@@ -124,12 +147,20 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
text("rewardValue", true),
|
||||
number("criteriaValue"),
|
||||
select("period", ["schedule", "daily", "weekly", "monthly"]),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "settings",
|
||||
build: (ids) =>
|
||||
col("settings", [rel("famId", ids.fams, true), text("webhookUrl")])(ids),
|
||||
col("settings", [rel("famId", ids.fams, true), text("webhookUrl")], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "chore_templates",
|
||||
@@ -141,7 +172,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
select("defaultFrequency", ["daily", "weekly"], true),
|
||||
select("defaultType", ["points", "money"], true),
|
||||
number("defaultValue", true),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "bonus_configs",
|
||||
@@ -159,7 +194,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
rel("memberId", ids.users),
|
||||
select("period", ["schedule", "daily", "weekly", "monthly"]),
|
||||
select("status", ["active", "completed"], true),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "weekly_history",
|
||||
@@ -172,7 +211,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
number("moneyEarned"),
|
||||
number("choresCompleted"),
|
||||
number("bonusEarned"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "seasons",
|
||||
@@ -184,7 +227,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
bool("active"),
|
||||
date("autoDisable"),
|
||||
date("autoStart"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "messages",
|
||||
@@ -199,7 +246,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
// Explicit createdAt: PB 0.39 does NOT auto-add createdAt to
|
||||
// API-created collections (0.25 did). Chat filters/sorts on it.
|
||||
date("createdAt"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_FAM_WRITE,
|
||||
updateRule: RULE_FAM_SCOPED,
|
||||
deleteRule: RULE_FAM_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "chat_typing",
|
||||
@@ -211,7 +262,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
text("authorName", true),
|
||||
text("authorColor"),
|
||||
bool("typing"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_FAM_WRITE,
|
||||
updateRule: RULE_FAM_SCOPED,
|
||||
deleteRule: RULE_FAM_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "rewards",
|
||||
@@ -229,7 +284,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
date("claimedAt"),
|
||||
date("requestedAt"),
|
||||
text("date"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_FAM_WRITE,
|
||||
updateRule: RULE_FAM_SCOPED,
|
||||
deleteRule: RULE_FAM_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "assigned_chores",
|
||||
@@ -243,7 +302,11 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
number("value", true),
|
||||
text("customName"),
|
||||
jsonField("seasonIds"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_PARENT_WRITE,
|
||||
updateRule: RULE_PARENT_SCOPED,
|
||||
deleteRule: RULE_PARENT_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
{
|
||||
name: "completions",
|
||||
@@ -254,6 +317,10 @@ export const SCHEMA_PLAN: CollectionPlanEntry[] = [
|
||||
rel("assignedChoreId", ids.assigned_chores, true),
|
||||
date("date"),
|
||||
date("completedAt"),
|
||||
])(ids),
|
||||
], {
|
||||
createRule: RULE_FAM_WRITE,
|
||||
updateRule: RULE_FAM_SCOPED,
|
||||
deleteRule: RULE_FAM_SCOPED,
|
||||
})(ids),
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user