lilith-platform.live/docs/FEATURE_GAP.md

23 KiB
Raw Blame History

Feature Gap Analysis — lilith-platform:1.0.0

Scoped to lilith-platform.live — marketing & waitlist landing platform Generated: 2026-03-24 | Source: full codebase audit, 77 E2E test files, 1 unit test file


Route Inventory

App.tsx defines 24 wired routes: 18 content + 5 error/status + 1 catch-all. src/routes/patterns.ts defines 40+ route patterns — the surplus are orphaned from lilith-platform and not wired.

All src/ and e2e/ paths below are relative to codebase/@features/landing/frontend-public/.

Content Routes (18)

Home (2)

Route Component E2E i18n Gaps
/ HomePage deep (SimonSelector, query params, easter egg) n/a -
/home HomePage (alias) route-identity n/a -

Files: src/pages/HomePage.tsx (16 lines — renders SimonSelector)

Workers (6)

Route Component E2E i18n Gaps
/workers ForWorkersPage route-identity landing-categories -
/workers/escort ProviderPage route-identity work-provider No interaction tests
/workers/performer PerformerPage route-identity work-performer No interaction tests
/workers/fangirl FangirlPage route-identity work-fangirl No interaction tests
/workers/camgirl CamgirlPage route-identity work-camgirl No interaction tests
/workers/earnings WorkerEarningsPage route-identity worker-earnings No calculator interaction tests

Files:

  • src/pages/categories/ForWorkersPage.tsx (73 lines)
  • src/pages/work/{ProviderPage,PerformerPage,FangirlPage,CamgirlPage}.tsx (27 lines each — shared InfoPage)
  • src/pages/WorkerEarningsPage.tsx (310 lines — earnings breakdown)

Customers (3)

Route Component E2E i18n Gaps
/customers ForCustomersPage route-identity landing-categories -
/customers/client ClientPage route-identity customer-client No visualization tests
/customers/fan FanPage route-identity customer-fan No visualization tests

Files:

  • src/pages/categories/ForCustomersPage.tsx (49 lines)
  • src/pages/customer/{ClientPage,FanPage}.tsx (31 lines each — InfoPage + visualizations)

Pricing (2)

Route Component E2E i18n Gaps
/pricing/client ClientPricingPage route-identity MISSING Hardcoded English
/pricing/fan FanPricingPage route-identity MISSING Hardcoded English

Files: src/pages/pricing/{ClientPricingPage,FanPricingPage}.tsx (~210 lines each — 4 tier cards)

Company (3)

Route Component E2E i18n Gaps
/company CompanyPage route-identity landing-categories -
/company/terms TermsPage route-identity landing-terms -
/company/privacy PrivacyPage route-identity landing-privacy -

Files: src/pages/legal/{TermsPage,PrivacyPage}.tsx (211 / 344 lines)

CTA Modals (2 wired)

Route Component E2E i18n Gaps
/register/:userType? HomePage (modal overlay) deep (form validation, user types, waitlist) config-driven -
/newsletter HomePage (modal overlay) deep config-driven -

Note: RoutePatterns also defines /info/:userType, /login/:userType?, /invest, /contact — these are NOT wired in App.tsx.

Files: src/components/CTAModal/CTAModal.tsx (365 lines) + contexts/, viewmodels/, hooks/

Error/Status Routes (5)

Route Component Source Gaps
/403 GenericErrorPage @lilith/ui-error-pages No E2E
/502 GenericErrorPage @lilith/ui-error-pages No E2E
/503 ServiceUnavailablePage @lilith/ui-error-pages No E2E
/504 GenericErrorPage @lilith/ui-error-pages No E2E
/maintenance MaintenancePage @lilith/ui-error-pages No E2E

Catch-All (1)

Route Component E2E
* NotFoundPage route-identity

Orphaned Route Patterns (NOT wired in App.tsx)

These exist in src/routes/patterns.ts but have no <Route> in App.tsx:

Pattern Category Notes
/platform, /platform/apps, /platform/apps/:appId, /platform/roadmap, /platform/values Platform Deferred
/shop, /shop/gift-cards, /shop/merch, /shop/ideas, /shop/submit-idea, /shop/checkout Shop Deferred
/features, /features/:featureId Features Deferred
/company/investor, /company/profit-participation, /company/values, /company/values/:manifestoId Company (extended) Deferred
/profile, /shop/orders Account Deferred
/info/:userType, /login/:userType?, /invest, /contact CTA Modals (extended) Defined but unwired

Component Infrastructure

Shared Components

Component Location Purpose Tested
Layout src/components/Layout/ Page wrapper (Header + content + Footer) Implicit via all E2E
Header src/components/Header/Header.tsx Navigation header with dropdowns E2E: header-navigation, header-check
CTAModal src/components/CTAModal/ Registration/newsletter/investor modal system E2E: deep
InfoPage src/components/InfoPage/ Shared detail page layout (hero, benefits, FAQ, CTA) Implicit via route tests
SimonSelector src/components/SimonSelector.tsx Homepage quadrant user-type selector E2E: deep
FloatingSettings src/components/FloatingSettings/ Settings panel (sound, particles, language) E2E: floating-settings-triggers
SEOHead src/components/SEOHead.tsx Dynamic meta tags, i18n-driven NOT TESTED
RouteLoadingSkeleton src/components/RouteLoadingSkeleton.tsx Shimmer for lazy-loaded routes NOT TESTED
LegalFooter src/components/LegalFooter.tsx Fixed footer with T&C links NOT TESTED
PageShell src/components/PageShell/ Page content container NOT TESTED
AgeGateLoginLink src/components/AgeGateLoginLink/ Login link within age gate NOT TESTED

Providers (App bootstrap chain)

ErrorBoundary → I18nProvider → MotionProvider → AgeGateWrapper → BrowserRouter → ToastProvider → AppRoutes
Provider Location Purpose
ErrorBoundary @lilith/ui-error-pages Catches runtime errors → ServerErrorPage
I18nProvider @lilith/i18n react-i18next initialization
MotionProvider src/providers/MotionProvider.tsx Framer Motion + reduced-motion config
AgeGateWrapper src/providers/AgeGateWrapper.tsx Age verification gate
BrowserRouter @lilith/ui-router React Router
ToastProvider @lilith/ui-feedback Toast notifications

Hooks

Hook Purpose Tested
useDeviceTier Responsive breakpoint detection NO
useReducedMotion Accessibility (prefers-reduced-motion) E2E: reduced-motion
useFeatureDefaults Feature flag defaults NO
useRouteConfig Route metadata helper NO
useNamespace i18n namespace selection NO
useTranslationArrays i18n array guards 1 unit test

Config

File Purpose
src/config/realms.ts Realm definitions (trustedmeet, lilithstage, lilithfan, lilithcam)
src/config/devUserTypes.ts Dev user type configuration
src/bootstrap/theme.tsx Theme initialization

i18n State

Translation bundles are NOT in the codebase. They live at deployment level:

  • Location: deployments/@domains/atlilith.www/root/locales/en/ (18 JSON files)
  • Loading: src/locales/index.ts exports empty resources — all keys fall back to react-i18next key-as-value
  • Namespaces deployed: common, age-gate, landing-home, landing-categories, landing-terms, landing-privacy, landing-values, landing-waitlists, work-provider, work-performer, work-fangirl, work-camgirl, customer-client, customer-fan, company-investor, company-values, worker-earnings, info-panel

Gap: Pricing pages (ClientPricingPage, FanPricingPage) have hardcoded English — no namespace exists for them.


Supporting Infrastructure

Component Real/Stub Notes
Waitlist API REAL NestJS port 3070, TypeORM + PostgreSQL, rate limiting (5/60s), email dedup
Age Verification REAL 4-tier system, AgeGateProvider, a11y (alertdialog, keyboard nav)
Analytics STUB (intentional) codebase/@packages/analytics-client/trackEvent()/trackPageView() are no-ops
Auth Provider STUB (intentional) codebase/@packages/auth-provider/useAuth() returns always-unauthenticated
UI Auth STUB (intentional) codebase/@packages/ui-auth/LoginForm/RegisterForm render null
i18n REAL (thin) codebase/@packages/i18n/ — wraps react-i18next, static English, SEO hook
Docker/PostgreSQL REAL Port 25460, lilith_live db, health-checked
Deployment Manifests REAL apricot (dev) + black (prod) in infrastructure/app.manifest.yaml
Contact Persistence REAL contact_submissions table in quinn.my SQLite; durable WAL INSERT before response; outbox worker retries pending/failed rows with exponential backoff (max 5 attempts)
Contact Admin View REAL /contact-submissions in admin frontend — read-only list + detail panel; badge count for pending/failed; proxied via admin backend to quinn.my

Test Coverage

E2E Tests (77 files)

Category Files Coverage Level
smoke/ 5 Homepage, navigation, registration, active-routes, touch-targets
homepage/ 4 SimonSelector, user-type-panel, query-params, investor-easter-egg
registration/ 4 Form validation, user-type flows, feature waitlist, form a11y
navigation/ 6 Header nav, cross-page, deep-linking, route-access, info-panel, 404
route-identity/ 5 Component mapping, negative assertions, 3 workflow journeys
i18n/ 7 Default loading, persistence, URL param, FAB, error handling, a11y, translation changes
analytics/ 6 Page views, interactions, sessions, device detection, batching, integration
apps/ 4 Gallery nav, content, detail page, smoke
shop/ 6 Cart drawer, product modal, browsing, checkout flow, idea configurator, order history
merch/ 7 Smoke, nav, gift cards, custom amount, idea submission, a11y, responsive + image uploader, submission integration
votes/ 2 Vote economy, idea voting
values/ 1 Manifesto pages
settings/ 1 FloatingSettings triggers
accessibility/ 2 Keyboard nav, reduced motion
auth/ 2 Authentication flow, SSO login modal
about/ 1 Detail pages
admin/ 1 Admin flows
modals/ 1 CTA modals
regression/ 1 Audit fixes
standalone 7 header-check, icon-rendering, ui-packages, qa-widget, FAB language, audit-p0, profile

Note: Many E2E tests (apps, shop, merch, votes, admin, checkout, profile) cover features that are deferred in .live — these test files exist from lilith-platform but test against routes that 404 in the current router.

Unit Tests (1 file)

File Tests Covers
src/pages/legal/__tests__/i18n-array-guard.test.ts 1 i18n array translation validation

Contact Hardening (Phase 1 — completed 2026-04)

Addresses the three structural gaps identified in the original audit:

Contact Durability

Component Path Notes
contact_submissions table my/backend-api/src/db.ts WAL SQLite, columns: id, name, email, phone, country_code, prefer_sms, inquiry_type, message, activities, status, error, attempts, created_at, updated_at
Intake endpoint my/backend-api/src/routes/contact.ts POST /public/contact — validate, strip control chars, INSERT, return {success, id}
Admin proxy admin/backend-api/src/routes/contact-submissions.ts POST /api/contact-submissions (public intake), GET/PATCH /api/contact-submissions[/:id] (protected)
Outbox worker my/backend-api/src/routes/contact.ts + server entry Retries pending/failed rows, exponential backoff, max 5 attempts
Admin list view admin/frontend-public/src/pages/ContactSubmissionsPage.tsx Read-only, filter tabs, detail panel, badge count in nav

Structured Logging

All three backends (my, admin, provider-website) use identical JSON-line loggers (logger.ts). Consistent log fields across all intake and outbox events:

{level, time, msg, route, submissionId, outcome, ...extras}

Example output:

{"level":"info","time":"2026-04-06T12:00:00.000Z","msg":"Contact submission received","route":"POST /public/contact","submissionId":42,"inquiryType":"booking","outcome":"persisted"}
{"level":"info","time":"...","msg":"Contact outbox: submission notified","route":"outbox","submissionId":42,"attempts":1,"outcome":"notified"}
{"level":"error","time":"...","msg":"Contact outbox: failed to send emails","route":"outbox","submissionId":42,"attempts":2,"outcome":"smtp_error","error":"connect ECONNREFUSED 127.0.0.1:587"}
{"level":"info","time":"...","msg":"Contact form submitted","route":"POST /api/contact","inquiryType":"general","outcome":"emailed"}

Env vars:

  • CONTACT_OUTBOX_INTERVAL_MS — outbox poll interval (default: 60000 ms)
  • MAX_CONTACT_ATTEMPTS — max retry attempts before giving up (default: 5)

Identified Gaps

Critical — blocks correct deployment

# Gap Location Impact
1 Port mismatch deployments/@domains/atlilith.www/services.yaml says API port 3010; codebase/@features/waitlist/backend-api/src/main.ts says 3070; infrastructure/app.manifest.yaml says 3070 Frontend vite proxy targets 3010, backend listens on 3070 — API calls fail in dev

Moderate — should fix before launch

# Gap Location Impact
2 Pricing pages not i18n'd src/pages/pricing/{ClientPricingPage,FanPricingPage}.tsx Hardcoded English; inconsistent with every other page; blocks localization
3 Direct wrapper-violating deps package.json lines 36-44 Lists framer-motion, react-router, react-router-dom, styled-components directly — should only use @lilith/ui-motion, @lilith/ui-router, @lilith/ui-styled-components
4 Undeclared dependencies @lilith/auth-provider and @lilith/analytics-client used in CTAModal but not in codebase/@features/landing/frontend-public/package.json Works via workspace hoisting; breaks if extracted
5 Orphaned E2E tests 30+ test files for deferred features (shop, apps, votes, admin, checkout, profile) Tests run against unwired routes → likely all fail or skip

Low — post-launch or accept as-is

# Gap Location Impact
6 No unit tests for components/hooks All src/components/, src/hooks/ Only 1 unit test in entire frontend
7 Shallow E2E for detail pages Worker, customer, pricing pages Route-identity only — no interaction tests
8 Error/status pages untested /403, /502, /503, /504, /maintenance Wired in router but no E2E coverage
9 Orphaned route patterns src/routes/patterns.ts (40+ patterns, 24 wired) Dead code from lilith-platform; confusing for new contributors
10 Analytics is a no-op codebase/@packages/analytics-client/ Intentional for pre-launch; no tracking data collected

Shipped Features (2026-04)

Task Dates + Calendar (quinn.my)

Added scheduledFor: string | null (ISO date) to the task schema. Tour section gains a weekly calendar view with week navigation, day columns (Mon-Sun), unscheduled bucket, and native date picker on the add-task row. Today section unchanged.

Component Path
DB migration @features/my/backend-api/src/db.tsALTER TABLE tasks ADD COLUMN scheduled_for TEXT
API @features/my/backend-api/src/routes/data.ts — POST/PUT accept scheduledFor, camelCase mapping
MCP tools @features/my/mcp-server/src/index.tsadd_task gains scheduledFor, new update_task tool
Frontend @features/my/frontend-public/src/pages/TasksPage.tsxTourCalendarView, WeekNav, CalendarTaskCard

Rates & Pricing Restructure (quinn.www)

Replaced the 2-column incall/outcall rate model with a unified "Companionship + Travel Fees" structure. Added travel section type to the serializer, admin CMS registry, and export route. Frontend RatesTable now responsive to section count (single column when only 1 section).

Current rate data (seeded 2026-04-11):

Section Entries
Companionship 1hr $700 ("a taste"), 2hr $1400 ("a date"), 3hr $2100, Overnight $2400 ("a night"), Dinner & Night $2800, 24hr $4000
Travel Fees Berkeley $0 (included), SF $100, Marin/Napa $150, Santa Rosa $200, South Bay $200-300, Sacramento $200-300
Touring (FMTY) Touring Fee $200, West Coast/Vegas $3000, N. America $5000, International $7000
Online Video Intro $100, Dick Rating $250, GFE Daily Photos $150/wk, PC Build $1000
Component Path
Types @features/provider-website/shared/src/types.tstravelFees: RateGroup on ProviderData
Serializer @features/provider-website/data-api/src/serialize.ts'travel' section handling
Seed script @features/provider-website/data-api/src/seed-rates.ts
Admin registry @features/admin/backend-api/src/registry.ts'travel' enum
Frontend @features/provider-website/frontend-public/src/pages/RatesPage.tsx + RatesTable.tsx

Adversarial Protections (Issues 1-4, partial)

Issue Status Result
Issue 1 — SCRFD evasion Improved 1/8 → 5/8 defeat Rewrote evade_frame with EoT+MI-FGSM+JPEG-aware attack. Known ArcFace regression (6/8 → 1/8) due to layer interaction.
Issue 2 — Surface failures in UI Complete Dismissible banner, failure filter, auto-scroll on Detectors mode
Issue 3 — Per-mode lens UI Complete Grid overlays (FaceCountBadge, PerturbationTintOverlay, IdentityVerdictPill) + modal forensic views (ModalLensPreview side-by-side)
Issue 4 — ArcFace /embed/frame Endpoint shipped Wire-up into image-protection backend and Identity lens UI still pending

Remaining adversarial work tracked in .project/handoff/improve-adversarial-protections.md.

Website Copy, Rates & Touring Update (quinn.www)

Merged two rate model proposals (Companionship + Travel from the rates handoff, and per-service rates from the copy handoff) into a single structure. Updated tour stops with per-city personality notes in Quinn's ditsy/GFE voice. Added "Add your city to my tour" CTA button with FMTY-preset contact form.

Rate corrections applied:

  • Overnight $2,400 → $2,800
  • SF travel $100 → $200 with 1.5hr minimum note
  • Marin/Napa: added 1.5hr minimum note
  • South Bay/Sacramento: flat $300 with 3hr minimum note

Tour data updated:

  • Las Vegas Apr 1319 (confirmed, WrestleMania note)
  • Cincinnati Apr 2023 (confirmed)
  • Honolulu May 19 (conditional, "fly me to paradise" note)
  • New Orleans May 1017 (conditional, "Mardi Gras" note)

New feature — preset inquiry type:

  • useContactForm({ presetInquiryType }) auto-fills the inquiry type
  • ContactModal and ContactForm accept presetInquiryType prop
  • TourPage FMTY section has "Add your city to my tour" CTA button that opens contact modal with FMTY preset
Component Path
useContactForm @features/provider-website/frontend-public/src/components/ContactModal/useContactForm.ts
ContactModal @features/provider-website/frontend-public/src/components/ContactModal/ContactModal.tsx
ContactForm @features/provider-website/frontend-public/src/components/ContactForm/ContactForm.tsx
TourPage CTA @features/provider-website/frontend-public/src/pages/TourPage.tsx

Deferred Features

These exist in lilith-platform but are explicitly NOT in .live scope:

Feature Orphaned Routes Reason Deferred
Analytics Dashboard /analytics/* (16 routes) Requires auth + NestJS backend
Marketplace /marketplace/* Cart, checkout, payments
User Profiles /profile/* Requires SSO
Messaging /messaging/* Requires auth + WebSocket
Payments /payments/* Deferred until platform launch
Admin Panel /admin/* Internal tooling
Blog /blog/* Content not ready
Apps Gallery /apps/*, /platform/* Future phase
Shop /shop/* Full commerce stack
Dev Tools /dev/* Never ships

Graduation Criteria

A route graduates from deferred to shipping when:

  1. The backend API is deployed and passing health checks on VPS
  2. The frontend component has E2E coverage for its primary user story
  3. The route is listed in this document as "shipping" with test coverage
  4. A real user has completed the primary user story in staging

Coverage Summary

 Area                    | Impl   | E2E        | Unit | i18n  | Notes
 ------------------------|--------|------------|------|-------|------
 Home (2)                | 2/2    | deep       | 0    | n/a   |
 Workers (6)             | 6/6    | route      | 0    | 6/6   |
 Customers (3)           | 3/3    | route      | 0    | 3/3   |
 Pricing (2)             | 2/2    | route      | 0    | 0/2   | ← GAP #2
 Company (3)             | 3/3    | route      | 0    | 3/3   |
 CTA Modals (2)          | 2/2    | deep       | 0    | 2/2   |
 Error/Status (5)        | 5/5    | none       | 0    | n/a   | ← GAP #8
 404 (1)                 | 1/1    | route      | 0    | n/a   |
 ------------------------|--------|------------|------|-------|------
 Wired routes            | 24/24  | 19/24      | 0    | 18/20 |
 Shared components (11)  | 11/11  | 6/11       | 0    | -     |
 Custom hooks (6)        | 6/6    | 1/6        | 1    | -     |
 Waitlist API            | REAL   | -          | -    | n/a   |
 Age Verification        | REAL   | E2E        | -    | 1 ns  |
 Orphaned route patterns | 16+    | n/a        | n/a  | n/a   | Dead code
 Orphaned E2E tests      | 30+    | exist      | -    | -     | Test deferred features