Analysis · Geskus reference
Two public Geskus repos solve a related but smaller problem space. Neither implements subjects, duplicates, exports, or layouts — so we're learning shapes (RBAC, file trees, task-driven uploads), not borrowing features.
Both repos lack a LICENSE file. Treat as proprietary / all-rights-reserved. We can read for inspiration and reimplement patterns idiomatically in our stack, but no copy-paste of source.
@sveltejs/adapter-node for Cloud Run.@auth/sveltekit + Auth0. Backend validates JWTs against Auth0 JWKS; supports an API-key + impersonate-user fallback for automation.RECEIVE_NOTIFICATIONS permission opt-in.Our stack (Next.js + Supabase + Pics) doesn't align directly, but the conceptual model translates cleanly.
STUDIO_ID at the Firestore root.parent_client_id for hierarchy.geskus-client-portal stored in Firestore; in pics-client-portal fetched from the external Pics API.id, name, parent_id, bucket_path, created_at) with binary in GCS. Folders are rows with bucket_path === null. Tree reconstructed at read time.text_response or a list of file_response entries. Tasks emit email notifications.Roles live in a Firestore sub-collection: studios/{STUDIO_ID}/users/{user_id}/roles. Each role doc carries a name (one of the predefined role types) and the materialized permission list derived from PREDEFINED_ROLES. Roles can be globally scoped (client_id == null, studio-level) or per-client.
| Role | Posture |
|---|---|
STUDIO_ADMIN | Implicit superuser — special-cased in code. |
STUDIO_USER | Broad CRUD across events, files, tasks; can invite + modify roles. |
CLIENT_ADMIN | Manages a single client, can invite users and modify client-scoped roles. |
CLIENT_USER | View access + upload data via tasks. The "everyday school user". |
DATA_ACCESS | Narrow grant: upload data files, view files and tasks. No event management. |
EVENT_ACCESS | View events only. |
RECEIVE_NOTIFICATIONS | Opt-in for emails; not a privilege grant. |
Permission checks iterate the user's roles, match the requested client_id scope, and look for the named permission. Granular permissions exist for VIEW / CREATE / UPDATE / DELETE of events, files, tasks, plus INVITE_USERS and MODIFY_ROLES.
parent_id; tree rebuilt with build_branches() at read time. Avoids deep Firestore nesting.studios/{STUDIO_ID}/clients/{client_id}/files/{season}/.<input type=file>) or a structured task-bound upload that mutates the task's file_response.Worth highlighting because it's the cleanest piece of these repos for our Phase 4 (customer portal + files):
input_type='file', allowed types (csv/xlsx/xls/txt/zip), assignee, and due date.VIEW_TASKS + RECEIVE_NOTIFICATIONS.client_id scope. Our Phase 4 ADR should adopt this taxonomy.querySelector to drive file input clicks the way FileViewCard does. Fragile under multiple instances; we'll prefer refs and React-shaped patterns.Geskus gives us a validated RBAC vocabulary and a clean task-and-file-request pattern. Everything that makes this product different from Geskus — subjects, dedupe, exports with format authoring, print layouts with template authoring, render pipeline — has to come from us.