Skip to content

Latest commit

 

History

History
217 lines (175 loc) · 13 KB

File metadata and controls

217 lines (175 loc) · 13 KB

Glimpse — Developer Handoff

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.


1. What's been built

Mobile (Expo / React Native — artifacts/glimpse)

  • 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 the DropPanel component, 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

API (artifacts/api-server)

  • 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/*.ts file; @workspace/api-zod (generated from OpenAPI) is currently consumed only by routes/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 (isInappropriate on detail)
  • Place autocomplete proxied through /places/autocomplete and /places/details/*placeId (server holds the Google key)

Shared libraries

  • @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 push entry
  • @workspace/location-validation — single source of truth for presence-gate constants and pre-flight helpers (consumed by both client and server)

2. What still needs human review

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.tomldrizzle-kit push could be interactive on destructive diffs
Production CORS & Clerk origin list artifacts/api-server/src/app.tsALLOWED_ORIGINS / REPLIT_DOMAINS resolution
18+ gate placement app/profile-setup.tsx:107-115 — gate at profile-setup, not signup (acceptable, see replit.md)

3. Critical user flows to re-test

Numbered in the order they happen in real use.

  1. First-launch onboarding — sign up, location permission, profile setup, 18+ gate, mandatory photo, redirect into tabs
  2. Drop a Glimpse — pick a place, descriptor layers, presence pre-flight (try a place you have NOT been near), submit
  3. Discovery — log a presence at a known bucket, then verify a Glimpse posted there appears after the visibility delay
  4. Respond + confirm — respond to someone else's Glimpse, switch accounts, confirm as the author, verify chat unlocks
  5. Block & report — block another user, verify their content disappears from Discover/Responses; report a user, verify it persists
  6. Photo CRUD — upload via signed URL, reorder, set main, delete, hit the 6-photo cap
  7. Account deletion — delete from Settings, verify Clerk user is gone, verify all rows cascade-delete
  8. Sign out / sign back in — session restores, no stale cache leakage between accounts
  9. Legal links — tap Terms and Privacy on the welcome screen and in Settings → About

4. Known limitations & deliberate scope cuts

  • Web build is not a shipping target. react-native-web is wired in for the Expo dev server only. Do not audit the web bundle as a product surface.
  • mockup-sandbox is a dev-only canvas tool. Not deployed, not user-reachable.
  • Schema sync uses drizzle-kit push, not versioned migrations. This is intentional, parity with scripts/post-merge.sh. Migration in this codebase = "edit lib/db/src/schema/index.ts then push." See RUNBOOK.md for 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 /events endpoint persists user actions to Postgres for in-house analysis only. No Segment, Mixpanel, Amplitude, etc.
  • No Stripe / RevenueCat / IAP. The subscriptionStatusEnum exists in the schema but no purchase flow ships in 1.0.
  • EXPO_PUBLIC_GOOGLE_MAPS_API_KEY is 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.

5. Services & accounts the developer needs

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.


6. Where to find important code

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

7. How to run things

Backend, locally

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"}

Mobile, locally

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 device

In Replit, both run automatically via the configured workflows.

Regenerate API client + Zod schemas

After editing lib/api-spec/openapi.yaml:

pnpm --filter @workspace/api-spec run codegen
pnpm run typecheck

Apply schema changes

After 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.

End-to-end test

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.


8. Pre-TestFlight blockers (status)

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):

  1. Set EXPO_PUBLIC_DOMAIN in EAS production profile
  2. Provision Clerk production instance, set pk_live_… (EAS) and sk_live_… (Replit deploy secrets)
  3. Set EXPO_PUBLIC_TERMS_URL / EXPO_PUBLIC_PRIVACY_URL to publicly-reachable URLs
  4. Provision a separate production Postgres
  5. Apple Developer enrollment + App Store Connect app record + bundle id
  6. App Store privacy questionnaire (declare email, name, age, photos, precise location, UGC text)
  7. Demo reviewer account in Clerk prod, run through onboarding once, paste credentials in App Review notes
  8. EAS init (eas init), eas.json (not yet checked in), set ios.bundleIdentifier in app.json