# PocketBase — PilotVault schema PilotVault adds an `organizations` collection and three fields to the `users` auth collection: - **`preferences`** (JSON) — each user's settings blob. Written with the user's own token, so PocketBase's default owner-only update rule (`@request.auth.id = id`) is all the authorization needed. - **`role`** (select: `superadmin` | `admin` | `user`) — the user-rights level. A **superadmin** spans every organization; an **admin** is scoped to their own organization (may manage its users *and* admins, but not superadmins); a **user** has no management rights. Missing/empty is treated as `user`. - **`organization`** (relation → `organizations`, maxSelect 1, optional) — which org the user belongs to. Nullable: a user may belong to **no** organization. The **`organizations`** collection is a plain base collection with a unique `name`. It is reached only through the API Server's superuser service account (its API rules stay locked to superusers), the same way user management works. ## User + org management requires a service account Listing/creating/deleting users and organizations is done by the API Server using a **superuser service account** (`POCKETBASE_ADMIN_EMAIL` / `POCKETBASE_ADMIN_PASSWORD`), but only *after* verifying the caller's own token resolves to a manager role (`admin` for user management, `superadmin` for org management). This is the single place the server uses elevated PocketBase credentials; without the env vars, the `/api/users` and `/api/orgs` endpoints return 503 and the rest is unaffected. Preferences never need the service account — they use the caller's own token. ## Add the schema Pick **one** of the following. ### Option A — migration (recommended) Copy the migration files into your PocketBase deployment's `pb_migrations/` directory and restart PocketBase (migrations run automatically on boot; they target the PocketBase v0.22+/v0.23 JS migration API). They are idempotent, so they are safe even if the schema was already provisioned live: - [`pb_migrations/1720300000_add_users_preferences.js`](pb_migrations/1720300000_add_users_preferences.js) - [`pb_migrations/1720300100_add_users_role.js`](pb_migrations/1720300100_add_users_role.js) - [`pb_migrations/1720300200_add_organizations.js`](pb_migrations/1720300200_add_organizations.js) - [`pb_migrations/1720300300_add_users_organization.js`](pb_migrations/1720300300_add_users_organization.js) - [`pb_migrations/1720300400_extend_users_role_superadmin.js`](pb_migrations/1720300400_extend_users_role_superadmin.js) - [`pb_migrations/1720300500_seed_orgs_and_users.js`](pb_migrations/1720300500_seed_orgs_and_users.js) — seeds the PilotVault org + baseline accounts ### Option B — Admin UI (any version) 1. Open the PocketBase Admin UI → **Collections → New collection** `organizations` (base); add a **text** field **`name`** (required) with a unique index. 2. **Collections → `users` → New field.** Add **JSON** field **`preferences`**, not required, max size ~5 MB. 3. Add **Select** field **`role`**, values `superadmin`, `admin`, `user`, max select 1. 4. Add **Relation** field **`organization`** → `organizations`, max select 1, not required, cascade delete off. 5. Save. ## Verify With a normal user token you should be able to round-trip the field: ```bash # 1) log in (PocketBase directly, or via the API Server /api/auth/login) TOKEN=... # the "token" from the auth response # 2) save curl -X PATCH "$PB_URL/api/collections/users/records/$USER_ID" \ -H "Authorization: $TOKEN" -H "Content-Type: application/json" \ -d '{"preferences":{"fontSize":"lg","themeMode":"dark"}}' # 3) read back curl "$PB_URL/api/collections/users/auth-refresh" -X POST -H "Authorization: $TOKEN" ``` In the app the round-trip is: browser → `GET/PUT /bff/preferences` → API Server `GET/PUT /api/preferences` → PocketBase user record.