Analysis · Pics API gap

Analysis: Pics API gap analysis

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.

Contract source

Canonical: portrait-pics/portrait-pics/docs/portal-integration.md. The current scaffold's lib/pics/ consumes a subset of it.

What Pics v1 exposes today

ResourceEndpointsNotes
Auth POST /api/portal/v1/auth/exchange
POST /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.

What each roadmap phase needs

Phase 1 — Subjects + Exports core

NeedPics today?Implication
Subject CRUD (create / list / update / delete) per eventNoEither Pics adds it, or portal owns a subjects table.
Subject custom-fields persistenceNoSchema design needed regardless of where it lives — extensible columns + a known core.
Subject portrait image storage + retrievalNo (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)NoLive in portal — it's a query, not a stored entity.
Subject directory PDF (group-by)NoLive in portal — render against subject + image data.
Standard SIS export formatsNoLive in portal — each format is a transformation over subjects + a packaging rule.
Async export job tracking + historyNoJob substrate must live in portal regardless.

Phase 2 — Print layouts (render-only)

NeedPics today?Implication
Layout templates (read-only library)NoPortal-side asset store with versioning. If layouts are shared across studios, they live globally; if per-studio, scoped.
PDF rendering with field/image bindingNoPure portal concern — render engine ADR pending.
High-res subject images (suitable for print)NoPics image story has to be solved — at print resolution.
Async render jobs with per-page progressNoSame job substrate as Phase 1 exports.

Phase 3 — Custom exports + layout authoring

NeedPics today?Implication
Custom export format CRUD (per-studio)NoPortal-side. Format definitions are structured data, not code.
Layout template CRUD with image slots + placeholdersNoPortal-side. Storage shape will follow whatever editor approach we pick (canvas JSON vs. DSL).
Asset uploads for layouts (backgrounds, logos)NoPortal-side, likely Supabase Storage or S3.

Phase 4 — Customer portal + RBAC + Files

NeedPics today?Implication
Non-admin user identityNo (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 scopeNoPortal-side regardless of identity store — Pics has no concept of customer roles.
File request workflowNoPortal-side (mirrors Geskus task pattern).
Customer-uploaded file storagePartial (we already stage CSVs in Supabase Storage)Generalize the existing uploads table into a broader file model.

Three architectural postures

The gap above can be closed three ways. The trade-offs feed the subject-store ADR.

A. Portal owns the new world

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.

B. Pics expands to host the new entities

Pics adds endpoints for subjects, images, exports, layouts, roles, file requests. Portal stays a thin client like today.

C. Hybrid — split by entity type

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.

What we need from Pics regardless of posture

Recommendation to bake into the Phase 1 PRD

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.