This commit is contained in:
JCEEE
2026-09-14 15:36:55 +01:00
37 changed files with 2396 additions and 464 deletions
+54
View File
@@ -262,6 +262,54 @@ async function ensureOtp(ids: Record<string, string>): Promise<void> {
});
}
// Child shared-device PINs. Superuser-only rules (like `otp`) — all access
// goes through server endpoints with session-role checks, so children can
// never read siblings' pins via PB rules.
async function ensurePins(ids: Record<string, string>): Promise<void> {
if (await getCollection('pins')) return;
const famsId = ids.fams || (await getCollection('fams'))?.id;
const usersId = ids.users || (await getCollection('users'))?.id;
if (!famsId || !usersId) throw new Error('fams/users collection not found');
await createCollection({
name: 'pins',
type: 'base',
listRule: null,
viewRule: null,
createRule: null,
updateRule: null,
deleteRule: null,
fields: [
{
name: 'famId',
type: 'relation',
required: true,
collectionId: famsId,
maxSelect: 1,
cascadeDelete: false
},
{
name: 'userId',
type: 'relation',
required: true,
collectionId: usersId,
maxSelect: 1,
cascadeDelete: false
},
{ name: 'pin', type: 'text', required: false }
]
});
}
// Idempotent field-add for the shared-device idle lock (0 = off, else mins).
async function ensureSettingsFields(): Promise<void> {
const settingsCol = await getCollection('settings');
if (!settingsCol) return;
const has = (n: string) => settingsCol.fields.some((f: any) => f.name === n);
if (has('lockMins')) return;
settingsCol.fields.push({ name: 'lockMins', type: 'number', required: false });
await updateCollection(settingsCol.id, { fields: settingsCol.fields });
}
// Platform access codes — the codes that enable access to the platform. They're
// global (not fam-scoped) and managed via the platform admin page (superuser
// only), so all rules are null like `otp`. A code grants a family a subscription
@@ -404,6 +452,7 @@ async function ensureSchema(): Promise<void> {
await ensureUsers(ids);
await ensureOtp(ids);
await ensurePins(ids);
console.log('[migrate] Schema bootstrapped.');
}
@@ -473,11 +522,16 @@ export async function migrate(): Promise<void> {
// return) so new platform collections/fields/seed land on existing installs.
await ensureUserFields();
await ensureFamFields();
await ensureSettingsFields();
await ensureBonusFields();
await ensureTemplateFields();
await ensureAssignedChoreFields();
await ensureAccessCodes();
await ensurePlatform();
// Superuser-only collections also land on EXISTING installs (ensureSchema's
// early return skips them). Like ensureOtp before it, ensurePins no-ops when
// the collection already exists.
await ensurePins({});
await ensureDefaultSeasons();
if (await isDemo()) {
await seedDemoFamily();