Analysis · Pics API gap
What the Pics Portal v1 contract offers vs. what the four-phase roadmap needs. This is the input to the subject-store ADR — the question of whether new entities live in Pics, in portal-side Postgres, or both.
Canonical: portrait-pics/portrait-pics/docs/portal-integration.md. The current scaffold's lib/pics/ consumes a subset of it.
| Resource | Endpoints | Notes |
|---|---|---|
| Auth |
POST /api/portal/v1/auth/exchangePOST /api/portal/v1/auth/refresh
|
Exchange is HMAC-signed (x-portal-signature, SHA-256 of raw body) with the shared signing secret. Refresh is Bearer-authed. Session returns { session_token, expires_at?, company_user{id,email,name,super_admin?}, companies[] }. |
| Companies | GET /api/portal/v1/companies |
Returns { data: Company[] } or bare array. Fields: id, name, venue_count?. |
| Venues | GET /api/portal/v1/companies/{id}/venues?page&per_page&q |
Paginated. Search via q. Fields: id, company_id?, name, city?, state?, event_count?. |
| Events | GET /api/portal/v1/venues/{id}/events?page&per_page |
Paginated. No q. Fields: id, venue_id?, name?, shoot_date?, starts_on?, date?, season?, year?, event_type?, key?. |
That's it for v1. Everything is pull-based — no webhooks, no async job semantics, no write endpoints for any resource.
| Need | Pics today? | Implication |
|---|---|---|
| Subject CRUD (create / list / update / delete) per event | No | Either Pics adds it, or portal owns a subjects table. |
| Subject custom-fields persistence | No | Schema design needed regardless of where it lives — extensible columns + a known core. |
| Subject portrait image storage + retrieval | No (Pics may host images, but no portal-accessible endpoint exists yet) | If Pics doesn't expose image URLs, we either upload to portal storage or co-design an image-URL endpoint. |
| Duplicate detection (across user-selected fields) | No | Live in portal — it's a query, not a stored entity. |
| Subject directory PDF (group-by) | No | Live in portal — render against subject + image data. |
| Standard SIS export formats | No | Live in portal — each format is a transformation over subjects + a packaging rule. |
| Async export job tracking + history | No | Job substrate must live in portal regardless. |
| Need | Pics today? | Implication |
|---|---|---|
| Layout templates (read-only library) | No | Portal-side asset store with versioning. If layouts are shared across studios, they live globally; if per-studio, scoped. |
| PDF rendering with field/image binding | No | Pure portal concern — render engine ADR pending. |
| High-res subject images (suitable for print) | No | Pics image story has to be solved — at print resolution. |
| Async render jobs with per-page progress | No | Same job substrate as Phase 1 exports. |
| Need | Pics today? | Implication |
|---|---|---|
| Custom export format CRUD (per-studio) | No | Portal-side. Format definitions are structured data, not code. |
| Layout template CRUD with image slots + placeholders | No | Portal-side. Storage shape will follow whatever editor approach we pick (canvas JSON vs. DSL). |
| Asset uploads for layouts (backgrounds, logos) | No | Portal-side, likely Supabase Storage or S3. |
| Need | Pics today? | Implication |
|---|---|---|
| Non-admin user identity | No (only admin company_user) | Either Pics adds a user/role model, or portal owns identity for customers (likely the answer; see open question). |
| RBAC with per-customer scope | No | Portal-side regardless of identity store — Pics has no concept of customer roles. |
| File request workflow | No | Portal-side (mirrors Geskus task pattern). |
| Customer-uploaded file storage | Partial (we already stage CSVs in Supabase Storage) | Generalize the existing uploads table into a broader file model. |
The gap above can be closed three ways. The trade-offs feed the subject-store ADR.
Pics remains the system of record for studios, venues, and events. Everything else — subjects, custom fields, exports, layouts, jobs, files, customer identity — lives in portal-side Postgres + Supabase Storage. Pics images are pulled by URL when available.
Pics adds endpoints for subjects, images, exports, layouts, roles, file requests. Portal stays a thin client like today.
Pics owns subjects + images (system of record; what Pics already has internally is exposed via new endpoints). Portal owns derived/workflow data: duplicate-detection queries, custom export format definitions, layout templates, render jobs, customer identity, file requests.
Posture choice is the subject-store ADR and stays open. But Phase 1 should be designed so that posture A and posture C are both implementable from the same PRD — i.e. the PRD describes the subject schema, duplicate-detection behavior, export rules, and job model in portal-abstract terms (interfaces, not storage), and the ADR picks where each interface is fulfilled.