Audience: a senior engineer joining post-NDA to do a launch-readiness review and TestFlight prep. This document tells you what exists, what's intentionally open, and where to look first.
- Auth: Clerk-backed sign up / sign in / forgot password
- Onboarding: location-permissions screen, mandatory profile setup with 18+ gate
- Tabs: Glimpses (
index), Discover, Responses, Chats, Profile. The "Drop a Glimpse" UI lives inside the Glimpses tab as theDropPanelcomponent, not as its own tab. - Drop flow: 3-layer descriptor system (required → optional → context-aware refinements), place picker (Google Places via server), presence pre-flight gate
- Discovery: matches authored Glimpses against viewer's recent presence buckets
- Responses & connections: incoming/outgoing review, mutual-confirm to unlock chat
- Chat: 1:1 only after mutual confirmation
- Profile: editable bio + demographic fields, up to 6 photos with reorder/main-photo
- Settings: subscription stub, blocked users, privacy info, Terms + Privacy links, sign out, delete account
- Moderation: block, report (server-validated), client-side hides on block
- Account deletion: client calls
DELETE /api/me→ cascading delete + Clerk user delete → sign out
- Express 5, Pino logging, structured 500 handler
- Clerk session middleware on all
/me*,/glimpses*,/responses*,/connections*,/chat*,/places*,/presence,/reports,/events, and signed-upload routes - Zod validation on every input. Most route validators are handwritten Zod schemas inside each
routes/*.tsfile;@workspace/api-zod(generated from OpenAPI) is currently consumed only byroutes/health.ts. Bringing the rest of the routes onto the generated schemas is a worthwhile P1 cleanup. - Rate limiters on: signed-URL issuance, profile patch, photo POST/PUT, block POST/DELETE
- Object storage: signed-URL upload flow +
/storage/objects/*and/storage/public-objects/*serving - Server-side moderation gate on
POST /reports(isInappropriateondetail) - Place autocomplete proxied through
/places/autocompleteand/places/details/*placeId(server holds the Google key)
@workspace/api-spec— OpenAPI 3.1 source of truth + Orval codegen@workspace/api-client-react— generated React Query hooks@workspace/api-zod— generated Zod request/response schemas@workspace/db— Drizzle schema +drizzle-kit pushentry@workspace/location-validation— single source of truth for presence-gate constants and pre-flight helpers (consumed by both client and server)
These are flagged not as bugs but as places where a fresh set of eyes is most valuable.
| Area | What to verify |
|---|---|
| Cross-user data exposure | DTO helpers in routes — nothing returns precise coords or precise timestamps to other users |
| Object storage authorization | routes/storage.ts + routes/photos.ts — uploaders can only attach objects they actually own |
| Discovery & matching | routes/glimpses.ts discover handler — block filtering, presence-bucket join, status filters |
| Response/confirm authorization | routes/responses.ts — only Glimpse author can confirm/decline a response |
| Chat unlock | routes/chat.ts — both directions of a connection must be confirmed |
| Report path | routes/reports.ts — validation, persistence, and abuse limits |
| Account deletion idempotency | routes/me.ts DELETE /me — Clerk 404 treated as success, DB failure returns 500 to retry |
| Schema-on-deploy build step | artifacts/api-server/.replit-artifact/artifact.toml — drizzle-kit push could be interactive on destructive diffs |
| Production CORS & Clerk origin list | artifacts/api-server/src/app.ts — ALLOWED_ORIGINS / REPLIT_DOMAINS resolution |
| 18+ gate placement | app/profile-setup.tsx:107-115 — gate at profile-setup, not signup (acceptable, see replit.md) |
Numbered in the order they happen in real use.
- First-launch onboarding — sign up, location permission, profile setup, 18+ gate, mandatory photo, redirect into tabs
- Drop a Glimpse — pick a place, descriptor layers, presence pre-flight (try a place you have NOT been near), submit
- Discovery — log a presence at a known bucket, then verify a Glimpse posted there appears after the visibility delay
- Respond + confirm — respond to someone else's Glimpse, switch accounts, confirm as the author, verify chat unlocks
- Block & report — block another user, verify their content disappears from Discover/Responses; report a user, verify it persists
- Photo CRUD — upload via signed URL, reorder, set main, delete, hit the 6-photo cap
- Account deletion — delete from Settings, verify Clerk user is gone, verify all rows cascade-delete
- Sign out / sign back in — session restores, no stale cache leakage between accounts
- Legal links — tap Terms and Privacy on the welcome screen and in Settings → About
- Web build is not a shipping target.
react-native-webis wired in for the Expodevserver only. Do not audit the web bundle as a product surface. mockup-sandboxis a dev-only canvas tool. Not deployed, not user-reachable.- Schema sync uses
drizzle-kit push, not versioned migrations. This is intentional, parity withscripts/post-merge.sh. Migration in this codebase = "editlib/db/src/schema/index.tsthen push." SeeRUNBOOK.mdfor the path to switch to versioned migrations later. - No test runner. No vitest, jest, or detox is configured. QA today is typecheck + manual device testing.
- No analytics provider. A
POST /eventsendpoint persists user actions to Postgres for in-house analysis only. No Segment, Mixpanel, Amplitude, etc. - No Stripe / RevenueCat / IAP. The
subscriptionStatusEnumexists in the schema but no purchase flow ships in 1.0. EXPO_PUBLIC_GOOGLE_MAPS_API_KEYis not consumed by the current build. There is no in-app native MapView.- 18+ gate at profile-setup, not signup — see
replit.md§ Design decisions for rationale.
Provide credentials privately, after NDA, for:
| Service | What they need |
|---|---|
| Replit | Workspace invite (Editor role) — gives access to code, dev DB, dev secrets store |
| Clerk (dev instance) | Dashboard invite — to inspect users, sessions, JWT templates |
| Google Cloud (Places) | Read access to the project that owns GOOGLE_PLACES_API_KEY |
| Replit deployment | Optional: Viewer role on the deployment for production logs and deploy history |
| Expo / EAS | Optional: invite to the Expo organization once one is created |
| App Store Connect | Required for TestFlight upload — App Manager role on the Glimpse app record (once created) |
Do not paste any of these credentials into chat or commit. The developer should request them through the same private channel used to share the NDA.
artifacts/api-server/src/
app.ts Express app construction, CORS, Clerk middleware, mounted router
index.ts Server bootstrap (reads PORT, calls app.listen)
middlewares/
requireAuth.ts Clerk session guard used by all protected routes
clerkProxyMiddleware.ts Production Clerk Frontend API proxy
routes/
index.ts Composes all per-feature routers under /api
health.ts GET /api/healthz (public)
me.ts GET / PATCH / DELETE /me (account deletion lives here)
photos.ts Profile photo CRUD + 6-photo cap
storage.ts Signed-URL issuance + object serving
presence.ts POST /presence (writes to presence_buckets)
glimpses.ts Glimpse CRUD, /discover, /recent-areas, /me
responses.ts Respond + confirm/decline; produces connections
connections.ts GET /connections (mutual list)
chat.ts GET / POST chat messages (mutual gate)
blocks.ts Block list + add/remove
reports.ts POST /reports (server moderation gate)
places.ts Server proxy for Google Places autocomplete + details
events.ts In-house analytics ingestion
artifacts/glimpse/
app/ Expo Router routes (file = screen)
auth.tsx Welcome / sign-in / sign-up; legal links here
location-onboarding.tsx
profile-setup.tsx 18+ gate at lines ~107-115
settings.tsx Account deletion, blocked users, legal links
(tabs)/... index (Glimpses + DropPanel), discover, responses, chats, profile
glimpse-detail.tsx
chat.tsx
components/ Shared UI primitives
DropPanel.tsx Drop flow with presence pre-flight (mounted in tabs/index)
PlacePicker.tsx Server-proxied Places autocomplete
GlimpseLogo.tsx SVG logo
lib/
legalLinks.ts Terms / Privacy URL constants + opener helper
descriptorConfig.ts 3-layer descriptor schema
moderation.ts Client-side advisory filters (server enforces)
context/ Auth + Glimpse + Toast React contexts (singular "context")
lib/
db/src/schema/index.ts All Drizzle tables, enums, indexes
api-spec/openapi.yaml OpenAPI 3.1 contract (source of truth)
location-validation/src/ Presence-gate constants & pre-flight helpers
cp artifacts/api-server/.env.example artifacts/api-server/.env
# fill in PORT, DATABASE_URL, CLERK_SECRET_KEY, ALLOWED_ORIGINS, GOOGLE_PLACES_API_KEY, etc.
pnpm install
pnpm --filter @workspace/db run push # one-time schema sync
PORT=8080 pnpm --filter @workspace/api-server run dev # serves on $PORT
curl http://localhost:8080/api/healthz # → 200 {"status":"ok"}cp artifacts/glimpse/.env.example artifacts/glimpse/.env
# fill in EXPO_PUBLIC_DOMAIN, EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY
pnpm --filter @workspace/glimpse run dev
# scan the QR with Expo Go on a real deviceIn Replit, both run automatically via the configured workflows.
After editing lib/api-spec/openapi.yaml:
pnpm --filter @workspace/api-spec run codegen
pnpm run typecheckAfter editing lib/db/src/schema/index.ts:
pnpm --filter @workspace/db run push
# Confirm prompts manually if drizzle detects a destructive change.
# In CI/deploy this would fail — see RUNBOOK.md § Schema changes.There is no automated suite. Walk through the 9 critical flows in §3 above, on a real device, against a live API. A demo Clerk account appreview@… is documented in replit.md § TestFlight Readiness for App Review use; it should also be the dev's first test account.
Resolved in code:
- iOS / Android permission strings —
app.json - Privacy + Terms in-app links —
lib/legalLinks.ts, surfaced on welcome + settings - Schema-sync on production build —
artifacts/api-server/.replit-artifact/artifact.toml
Outstanding (require human action — see replit.md § TestFlight Readiness):
- Set
EXPO_PUBLIC_DOMAINin EAS production profile - Provision Clerk production instance, set
pk_live_…(EAS) andsk_live_…(Replit deploy secrets) - Set
EXPO_PUBLIC_TERMS_URL/EXPO_PUBLIC_PRIVACY_URLto publicly-reachable URLs - Provision a separate production Postgres
- Apple Developer enrollment + App Store Connect app record + bundle id
- App Store privacy questionnaire (declare email, name, age, photos, precise location, UGC text)
- Demo reviewer account in Clerk prod, run through onboarding once, paste credentials in App Review notes
- EAS init (
eas init),eas.json(not yet checked in), setios.bundleIdentifierinapp.json