Content Admin
/admin is the CMS for everything the public site serves — docs, firmware source, and CAD files — editable without a redeploy. Restricted to team members with a Supabase login.
Sign In
/admin/login — email + password, checked against Supabase Auth (signInWithPassword). On success the server sets an eb-admin cookie (httpOnly, secure, sameSite=lax, 24h expiry) containing the Supabase access token; every admin API route checks for that cookie and returns 401 without it. Log out (top-right of /admin) clears the cookie via DELETE /api/admin/auth.
There's no self-service signup — accounts are created directly in the Supabase project's Auth panel by whoever administers the project.
Docs Tab
Edit any of the doc pages the sidebar lists (this site) as raw markdown:
- Pick a page from the slug list.
- Edit the textarea.
- Save →
PUT /api/admin/docs→ upserts a row indocs_pages, keyed by slug.
Once a slug has a
docs_pagesrow, it permanently overrides the hardcoded fallback inlib/docs-content.ts— a future code-level edit to that page silently does nothing until the DB row is removed or re-saved. See the precedence note in Platform Overview.
Code Tab
Manages the Code Browser's file list.
- Upload: pick a
.cpp/.h/.ino/.cfile → uploads to R2 (POST /api/admin/upload) → creates acode_filesrow (POST /api/admin/code). - Delete: removes both the R2 object and the DB row.
- Bulk reseed:
POST /api/admin/seed-codere-uploads every firmware file embedded bysync-code.mjsin one shot — the normal way to push a firmware update, rather than uploading files one at a time. See Platform Overview for the full pipeline.
Design Tab
Same upload/delete pattern as Code, for the CAD Viewer: accepts .glb .gltf .step .stp .stl .sldasm .sldprt, writes to design_files.
Runs Tab
Removed. Run data is never stored server-side — it goes robot → downloaded results.json → dropped into the Visualiser in the browser. There is nothing to administer.
API Reference
All routes below require the eb-admin cookie (401 without it).
| Method | Endpoint | Purpose |
|---|---|---|
GET / PUT |
/api/admin/docs |
Fetch / upsert a doc page ({slug, title?, content}) |
GET / POST / DELETE |
/api/admin/code |
List / create / delete a code_files row |
GET / POST / DELETE |
/api/admin/design |
List / create / delete a design_files row |
POST |
/api/admin/upload?key=&type= |
Raw-byte upload to R2 at key |
POST |
/api/admin/seed-code |
Bulk-reseed all firmware files from the embedded sync-code.mjs output |
POST / DELETE |
/api/admin/auth |
Sign in / sign out |
Every create/delete flow that touches R2 does the storage operation first, then the DB write — a failed DB write after a successful upload leaves an orphaned R2 object (harmless, just unreferenced) rather than a DB row pointing at nothing.
Security Notes
SUPABASE_SERVICE_ROLE_KEY(used by every admin route to bypass RLS) is a server-only secret — never sent to the browser, never logged.- The
eb-admincookie is the only gate on admin routes — there's no per-route role check, so any authenticated account has full access to every tab. - The firmware carries no private credentials to leak: WiFi is AP-only, and the
RobotAPSSID/password are printed on the robot for judges anyway.sync-code.mjstherefore publishes firmware verbatim.