lilith-platform.live/docs/admin-api-migration.md
autocommit d42508a9fe docs(admin-api): 📝 Update migration documentation for admin API with revised steps and clarifications
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-16 01:22:02 -07:00

15 KiB

Admin-API Migration Audit

Purpose: Input to Stage 4 of the edge-cache plan (§5). No routes are migrated here.
Scope: codebase/@features/admin/backend-api/src/routes/codebase/@features/api/src/surfaces/admin/
Date: 2026-05-16
DB clarification: The plan (§5) describes the admin backend as writing to SQLite at /var/www/quinn.admin/data/quinn.db. This is inaccurate as of current code. admin/backend-api/src/db.ts imports postgres and reads QUINN_ADMIN_DB_URL — it already runs against postgres. Column 3 below therefore answers "does an equivalent postgres-backed entity already exist in quinn-api's schema?" rather than "does SQLite need a postgres mate?"


Summary counts

Metric Value
Route files audited 27
Distinct resources 24
Fully covered in quinn-api (/admin/*) 13
Partial (some sub-routes missing) 3
Retire without migrating (proxy passthrough) 1
Pure MIGRATE (no quinn-api equivalent) 7
Photo-upload coupling: HIGH 1 resource (gallery — migrate last)

Route inventory by resource

Method Path Writes
GET /api/gallery
POST /api/gallery gallery_items + disk files + manifest
PUT /api/gallery/:id gallery_items
DELETE /api/gallery/:id gallery_items + disk files + manifest
PUT /api/gallery/reorder gallery_items.sort_order
POST /api/gallery/:id/protect delegates to image-protection svc (:3030), polls async
POST /api/gallery/:id/adversary-view delegates to image-protection svc (:3030)
GET /api/gallery/adversary-view/jobs/:jobId — (proxy)

Quinn-api equivalent: src/surfaces/admin/gallery-items.ts — GET/POST/PUT/:id/DELETE/:id/POST /reorder. The protect and adversary-view proxy endpoints have no quinn-api equivalent.
Status: PARTIAL — base CRUD exists. Protection trigger + adversary-view proxy: MIGRATE.
Postgres schema: gallery_items entity exists in quinn-api (src/entities/gallery-item/).
Port collision hazard: gallery.ts hardcodes IMAGE_PROTECTION_URL default as http://localhost:3030 — the same port quinn-api itself binds. This must be resolved before migration: add an explicit non-default port for image-protection or force the env var in the unit file.
Purge paths on mutation: /provider-api/gallery, /photos/<filename>.jpg, /photos/<filename>.webp


2. Rates

Method Path Writes
GET /api/rates
POST /api/rates rate_sections
PUT /api/rates/:id rate_sections
DELETE /api/rates/:id rate_sections + cascade rate_entries
POST /api/rates/:sectionId/entries rate_entries
PUT /api/rates/entries/:entryId rate_entries
DELETE /api/rates/entries/:entryId rate_entries

Quinn-api equivalent: src/surfaces/admin/rate-cards.ts — full CRUD for sections + entries.
Status: EXISTS (admin uses rate_sections/rate_entries; quinn-api uses rate_cards/rate_card_entries — verify table names match or confirm the entity is the same object before retiring).
Purge paths: /www/rates, /provider-api/rates


3. Tour Stops

Method Path Writes
GET /api/tour-stops
POST /api/tour-stops tour_stops
PUT /api/tour-stops/:id tour_stops
DELETE /api/tour-stops/:id tour_stops

Quinn-api equivalent: src/surfaces/admin/tour-stops.ts — full CRUD.
Status: EXISTS.
Purge paths: /www/tour, /provider-api/tour-stops


4. Policies

Method Path Writes
GET /api/policies
POST /api/policies policy_sections
PUT /api/policies/:id policy_sections
DELETE /api/policies/:id policy_sections + cascade policy_items
POST /api/policies/:sectionId/entries policy_items
PUT /api/policies/entries/:entryId policy_items
DELETE /api/policies/entries/:entryId policy_items

Quinn-api equivalent: src/surfaces/admin/policies.ts — full CRUD.
Status: EXISTS.
Purge paths: /www/screening (policies appear on screening/provider page)


5. Specialties

Method Path Writes
GET /api/specialties
POST /api/specialties specialty_categories + optional first entry
PUT /api/specialties/:categorySlug specialty_categories
DELETE /api/specialties/:categorySlug cascade all entries
POST /api/specialties/:categorySlug/entries specialties
PUT /api/specialties/entries/:itemId specialties
DELETE /api/specialties/entries/:itemId specialties

Quinn-api equivalent: src/surfaces/admin/specialties.ts — full CRUD for categories + entries.
Status: EXISTS.
Purge paths: /www/specialties, /provider-api/specialties


6. Site Text

Method Path Writes
GET /api/site-text
POST /api/site-text site_text
PUT /api/site-text site_text (upsert)
PUT /api/site-text/upsert site_text (upsert alias)
PUT /api/site-text/:id site_text
DELETE /api/site-text/:id site_text

Quinn-api equivalent: src/surfaces/admin/site-text.ts — full CRUD + upsert.
Status: EXISTS.
Purge paths: varies by namespace — at minimum all public pages via /www/*


7. Profile (identity / physical / contact)

Method Path Writes
GET/PUT /api/identity provider identity fields
GET/PUT /api/physical physical attribute fields
GET/PUT /api/contact contact + social fields

Quinn-api equivalent: src/surfaces/admin/provider-profile.ts — GET/PUT / + PATCH /:section.
Status: EXISTS (three discrete routes in admin vs section-patching in quinn-api; semantically equivalent).
Purge paths: /provider-api/profile, /www/about


8. About

Quinn-api equivalent: src/surfaces/admin/about.ts — GET + PUT / + activity CRUD.
Status: EXISTS (confirm field parity before retiring admin copy — admin manages about content through profile.ts/site-text.ts; may not need a separate about route).
Purge paths: /www/about


9. Shop Listings

Method Path Writes
GET /api/shop
POST /api/shop shop_listings
GET/PUT/DELETE /api/shop/:id shop_listings
POST /api/shop/:id/photos shop_listing_photos + disk
DELETE /api/shop/:id/photos/:photoId shop_listing_photos + disk
PUT /api/shop/:id/photos/reorder shop_listing_photos.sort_order

Quinn-api equivalent: src/surfaces/admin/shop-listings.ts — base CRUD. Photo sub-routes absent.
Status: PARTIAL — listing CRUD exists; photo upload/delete/reorder on shop items: MIGRATE.
Purge paths: /www/shop, /provider-api/shop


10. Roster Content

Method Path Writes
GET /api/roster-content
PUT /api/roster-content/:slug roster_content (upsert)

Quinn-api equivalent: src/surfaces/admin/roster-content.ts — GET + PUT /:slug.
Status: EXISTS.
Purge paths: /provider-api/roster-content


11. Verified Profiles

Method Path Writes
GET /api/verified-profiles
POST /api/verified-profiles verified_profiles
PUT /api/verified-profiles/:id verified_profiles
DELETE /api/verified-profiles/:id verified_profiles

Quinn-api equivalent: src/surfaces/admin/verified-profiles.ts — full CRUD.
Status: EXISTS.
Purge paths: /www/verified-profiles


12. Etiquette

Method Path Writes
GET /api/etiquette
POST /api/etiquette etiquette_sections
PUT /api/etiquette/:id etiquette_sections
DELETE /api/etiquette/:id cascade items
POST/PUT/DELETE /api/etiquette/*/entries/* etiquette_items

Quinn-api equivalent: src/surfaces/admin/etiquette.ts — full CRUD.
Status: EXISTS.
Purge paths: /www/etiquette


13. Hero Strip

Method Path Writes
GET /api/hero-strip
POST /api/hero-strip hero_strip_items
PUT /api/hero-strip/:id hero_strip_items
DELETE /api/hero-strip/:id hero_strip_items

Quinn-api equivalent: src/surfaces/admin/hero-strip.ts — full CRUD.
Status: EXISTS.
Purge paths: /www/home, /provider-api/hero-strip


14. Mail Admin (mailserver accounts)

Method Path Writes
GET /api/mail-admin/accounts
POST /api/mail-admin/accounts docker-mailserver API
DELETE /api/mail-admin/accounts/:email docker-mailserver API

Quinn-api equivalent: src/surfaces/admin/mail-admin.ts — full CRUD (mailserver proxy).
Status: EXISTS.
Purge paths: none (not public content)


15. System Status

Method Path Writes
GET /api/system/status

Quinn-api equivalent: src/surfaces/admin/system-status.ts — GET /.
Status: EXISTS (read-only — migrate first in the sequence).
Purge paths: none


16. Bookings (proxy passthrough)

Method Path Writes
POST /api/bookings proxies to quinn-api /public/bookings

Quinn-api equivalent: this IS quinn-api — the admin backend is a passthrough to the public bookings endpoint.
Status: RETIRE without migration. Point the admin frontend directly at quinn-api /public/bookings.
Purge paths: none


17. Touring Subscribers — PARTIAL

Method Path Writes
POST /api/touring/subscribe touring_subscriptions (unauthenticated)
GET /api/touring/subscribers

Quinn-api equivalent: src/surfaces/admin/touring-subscribers.ts — GET / only.
Status: PARTIAL — read list exists. The unauthenticated subscribe POST belongs in the quinn-api public surface; check /public/touring before migrating.
Purge paths: none


18. MIGRATE — Cult of Lilith

Method Path Writes
GET /api/cult-of-lilith
PUT /api/cult-of-lilith/:key cult_of_lilith_sections
PUT /api/cult-of-lilith/batch batch upsert

Quinn-api equivalent: none. lore_sections entity exists in quinn-api; cult_of_lilith may be a distinct table — verify on QUINN_ADMIN_DB_URL before migration.
Status: MIGRATE.
Purge paths: /www/cult-of-lilith


19. MIGRATE — Page Illustrations

Method Path Writes
GET /api/page-illustrations
PUT /api/page-illustrations illustration config (file-backed or in DB — unclear)

Quinn-api equivalent: none. Backing store needs investigation before migration.
Status: MIGRATE.
Purge paths: /www/* (illustrations appear across pages)


20. MIGRATE — Mail Threads (email client)

Method Path Writes
GET /api/mail/inboxes
GET/GET/:uid /api/mail/threads
POST /api/mail/threads/:uid/reply sends email via IMAP/SMTP
PATCH /api/mail/threads/:uid/read IMAP flags
POST /api/mail/threads/:uid/draft/approve draft_replies
POST /api/mail/threads/:uid/draft/reject draft_replies
PATCH /api/mail/draft/:id draft_replies

Quinn-api equivalent: none (messaging is in quinn.m, not the quinn-api admin surface).
Status: MIGRATE. Consider whether this belongs in quinn.m's surface rather than /admin/*.
Purge paths: none (internal inbox)


21. MIGRATE — Destinations (tour city pages)

Method Path Writes
GET /api/destinations
POST /api/destinations destinations
PUT /api/destinations/:id destinations
DELETE /api/destinations/:id destinations

Quinn-api equivalent: src/surfaces/admin/pseo-destinations.ts covers pSEO metro destinations (slug-based, different shape). The admin destinations table (id/sort_order-based) may be a separate concept. Verify schema before conflating.
Status: MIGRATE (pending schema confirmation).
Purge paths: /www/destinations, /_/escorts/in-{city} pages


22. MIGRATE — DB Sync

GET /api/sync/info, GET /api/sync/export, POST /api/sync/import, POST /api/sync/push, POST /api/sync/pull

Status: MIGRATE or RETIRE. These sync the admin DB to a remote. With both services on postgres, the push/pull mechanism may be fully obsolete. Audit live callers before deciding.


23. MIGRATE — Backup / Export / Photo Export / Restore

GET /api/backup, GET /api/export, GET /api/export/stats, POST /api/export/photos/:size, POST /api/restore

Status: MIGRATE or RETIRE. These are SQLite-era backup/restore + photo resize triggers. Audit usage before migrating.


POST /api/device-link/start, GET /api/device-link/poll/:token, GET /auth/device-link/callback

Status: MIGRATE. Belongs in quinn-api's SSO/auth surface.
Purge paths: none


  1. System status — GET-only, zero writes; safe first to verify routing plumbing.
  2. Tour stops — full parity in quinn-api. Wire purgeEdge(['/www/tour', '/provider-api/tour-stops']) into the handler and retire admin copy.
  3. Site text — full parity. Wire purge for affected namespaces.
  4. Rates, Policies, Etiquette, Specialties, Roster content, Verified profiles, Hero strip — all have quinn-api equivalents; retire admin copies in a batch. Wire purge per resource.
  5. Provider profile / About — exists in quinn-api; confirm field parity first.
  6. Shop listings (base CRUD only — skip photo sub-routes for now) — quinn-api surface exists.
  7. Cult of Lilith — new quinn-api surface needed under /admin/cult-of-lilith; straightforward CRUD.
  8. Destinations — verify vs pseo-destinations schema before migrating.
  9. Touring subscribe (public POST) + touring-subscribers (admin GET) — wire public surface endpoint.
  10. Mail threads — largest non-content feature; placement in quinn.m vs /admin/* needs a decision.
  11. Device link — move to quinn-api SSO surface.
  12. DB Sync + Backup + Restore — audit live usage; retire if no active caller.
  13. Page illustrations — investigate disk vs DB backing before migrating.
  14. Gallery (photos) — last. Three-way coupling: admin backend, image-protection service (port 3030 conflicts with quinn-api; must be resolved before migration), and photo origin on black (track B of the edge-cache plan). The upload flow — multipart → resize → WebP generation → manifest update → disk write → DB insert — is the highest-coupling path in the entire surface. Do not migrate until track B (dedicated photo server on black:8081) is complete and the image-protection port conflict is resolved.