mega-plant/scripts/setup-auth.mjs
Dave 2594dead84 feat: add user access and improve plant dashboard
Add PocketBase login, first-sign-in password changes, account settings,
and user activation, reactivation and deletion with self-removal guards.
Protect application pages and APIs and keep private pages out of PWA
caches.

Resolve plant locations from site assignments and improve map controls,
profit chart views, navigation and mobile table layouts.

Validation: production build and TypeScript passed; 28 unit tests passed.
Backend access integration tests and mobile verification are documented.
2026-10-06 04:02:08 +02:00

36 lines
2.1 KiB
JavaScript

// Private first-login and access state. Existing collection rules are unchanged.
import PocketBase from "pocketbase";
const { NEXT_PUBLIC_PB_URL, PB_ADMIN, PB_PASS } = process.env;
if (!NEXT_PUBLIC_PB_URL || !PB_ADMIN || !PB_PASS) throw new Error("Configure NEXT_PUBLIC_PB_URL, PB_ADMIN and PB_PASS first.");
const pb = new PocketBase(NEXT_PUBLIC_PB_URL);
pb.autoCancellation(false);
await pb.collection("_superusers").authWithPassword(PB_ADMIN, PB_PASS);
const existing = (await pb.collections.getFullList()).find((c) => c.name === "user_onboarding");
if (existing) {
const fields = existing.fields;
if (existing.type !== "base" || !fields.some((f) => f.name === "user" && f.type === "relation") ||
!fields.some((f) => f.name === "password_changed" && f.type === "bool") ||
[existing.listRule, existing.viewRule, existing.createRule, existing.updateRule, existing.deleteRule].some((rule) => rule !== null)) {
throw new Error("Existing user_onboarding collection does not match the required private schema.");
}
const disabled = fields.find((field) => field.name === "disabled");
if (disabled && disabled.type !== "bool") throw new Error("user_onboarding.disabled must be a boolean.");
if (!disabled) {
await pb.collections.update(existing.id, { fields: [...fields, { name: "disabled", type: "bool" }] });
console.log("Added private access status. Existing users remain active.");
} else console.log("Private user_onboarding collection already configured. No changes made.");
} else {
const users = await pb.collections.getOne("users");
await pb.collections.create({
name: "user_onboarding", type: "base",
listRule: null, viewRule: null, createRule: null, updateRule: null, deleteRule: null,
fields: [
{ name: "user", type: "relation", collectionId: users.id, required: true, maxSelect: 1, cascadeDelete: true },
{ name: "password_changed", type: "bool" },
{ name: "disabled", type: "bool" },
],
indexes: ["CREATE UNIQUE INDEX idx_user_onboarding_user ON user_onboarding (user)"],
});
console.log("Created private user_onboarding collection. Existing users and collection rules are unchanged.");
}