Audit date: 2026-07-22 | Status: Post-Supabase migration, deployed but not usable
The app has a working foundation (auth, DB, project CRUD, PRD generation) but the core conversation feature is broken (streaming mismatch), 5 UI features call non-existent endpoints, the settings page doesn't exist, and BYOK is advertised but not implemented. There's also significant dead code and tech debt from the Supabase migration.
- Problem: Client (
conversation.tsx:251-305) expects SSE (data: {"content":"..."}lines via ReadableStream), server (routes.ts:1153) returnsres.json(). AI responses never display. - Fix: Convert server endpoint to SSE streaming — set
Content-Type: text/event-stream, stream AI response chunks, senddata: {"content":"...","done":true}lines. Requires streaming support in Gemini/Anthropic adapters. - Impact: Core feature — the interview conversation is the whole point of the app.
- Problem: Webhook route (
routes.ts:1867) is registered afterapp.use('/api', requireAuth)(routes.ts:316) → Stripe gets 401. Also,vercel-entry.tsparses JSON body before webhook, sostripe.webhooks.constructEvent()can't verify the signature (needs raw body). - Fix: Move webhook registration before
requireAuth. Add raw body capture for/api/webhook/stripepath invercel-entry.ts(useexpress.rawfor that specific path). - Impact: Subscriptions can't be processed — Pro tier is non-functional on Vercel.
- Problem:
app-layout.tsx:65-70— Settings button has noonClick. No/app/settingsroute exists. No settings page component. - Fix: Create
client/src/pages/settings.tsxwith tabs: Profile (email, change password), API Keys (BYOK), Billing (Stripe portal link), Danger Zone (delete account). Add route inApp.tsx. Wire button to navigate. - Impact: Users can't manage their account or configure BYOK.
- Problem: 5 features in the UI call endpoints that don't exist:
conversation.tsx:97→/api/speech-to-text(voice input)conversation.tsx:137→/api/text-to-speech(TTS playback)prd-view.tsx:185→/api/projects/:id/generate-landing-pageprd-view.tsx:215→/api/projects/:id/find-communitiesprd-view.tsx:240→/api/projects/:id/reality-check
- Fix: Remove the voice/TTS buttons from conversation.tsx. Remove the three dead feature sections from prd-view.tsx. These were never implemented and add confusion.
- Impact: Clean UX — no more broken buttons.
- Add
user_api_keystable:id,userId,provider(gemini|anthropic|openai),encryptedKey,createdAt,lastUsedAt. - Encrypt keys at rest using AES-256-GCM with a server-side
ENCRYPTION_KEYenv var. - Add
drizzle-kit pushto create the table.
- New endpoints:
GET /api/user/keys(list, masked),POST /api/user/keys(save),DELETE /api/user/keys/:id. - Modify
AIServiceinterface: addsetApiKey(key: string)method or pass key per-call. - Modify route handlers: check for user's BYOK key first, fall back to server default key. Per-request AI service instantiation when BYOK key is present.
- Add
ENCRYPTION_KEYenv var to Vercel.
- API Keys tab in settings page: dropdown for provider (Gemini, Anthropic, OpenAI), input for API key, save/delete buttons.
- Show masked keys (e.g.,
sk-ant-...x7f2). - Link to provider docs for getting keys.
- Test connection button (makes a minimal API call to verify the key works).
client/src/pages/home.tsx(616 lines, not imported, superseded by new-idea.tsx)client/src/components/layout.tsx(not imported anywhere)
@supabase/supabase-js— no longer importedpassport— never usedpassport-local— never usedconnect-pg-simple— never usedexpress-session— never usedmemorystore— never usedopenai— imported in service.ts type but no adapter exists
- Rename
client/src/lib/supabase.ts→client/src/lib/auth.ts(update all imports) - Update
.env.example— remove Supabase vars, addJWT_SECRET,ENCRYPTION_KEY,STRIPE_SECRET_KEY,STRIPE_PRO_PRICE_ID - Fix
server/test/mcp.test.ts— mock../storagenot../storage-supabase - Fix
shared/schema.ts:13— update comment from "Legacy - unused with Supabase Auth" to "bcrypt hash" - Fix
package.jsonname fromrest-expresstoidea-foundry
server/app.ts(local) andserver/vercel-entry.ts(serverless) have inconsistent middleware (helmet, rate limiters, CORS, raw body). Extract shared middleware intoserver/middleware.tsand use in both.
- Landing page says $15/mo, upgrade page says $19/mo. Pick one and align both.
app-layout.tsx:72— Sign Out navigates to/but doesn't clear the JWT token. Should callsignOut()then navigate to/auth.
routes.ts:240—storage.getUser("health-check-nonexistent")throws when user doesn't exist, returning 500. Should catchundefinedand return 200.
gemini.ts:8— hardcodedgemini-1.5-flash(comment in routes.ts says "Gemini 3.0 Flash"). Update to current model.anthropic.ts:7— hardcodedclaude-3-5-sonnet-20241022. Update to current model.
auth.tsx:76— shows "not available yet". Either implement (needs email service) or remove the reset option entirely.
server/auth.ts:8— falls back to'dev-secret-change-in-production'ifJWT_SECRETis missing. Should throw in production instead.
routes.ts:567—PATCH /api/projects/:idpasses rawreq.bodytostorage.updateProject(). Add Zod validation.
server/vercel.tshas rate limiter paths that don't match actual routes (/api/projects/:id/prdshould be/generate-prd,/api/projects/:id/synergyshould be/synergies).
- Make AI model configurable via env var (
GEMINI_MODEL,ANTHROPIC_MODEL) with sensible defaults.
routes.ts,mcp/index.ts,mcp/auth.tsall duplicate theisDevMode ? mockStorage : dbStoragepattern. Extract to a sharedgetStorage()function.
- App uses both Radix toast (
useToast) and Sonner toast inconsistently across pages. Pick one (Sonner is newer) and migrate.
App.tsxmaintains both/app/*and legacy/*routes (dashboard, idea, conversation, prd). Once all internal links use/app/*, remove legacy routes.
| # | Item | Effort | Impact |
|---|---|---|---|
| 1 | Fix conversation streaming | M | Critical — core feature broken |
| 2 | Fix settings button + page | S | High — users can't manage account |
| 3 | Remove dead UI features | S | Medium — clean up broken buttons |
| 4 | Fix Stripe webhook | S | High — payments broken on Vercel |
| 5 | BYOK implementation | L | High — advertised, not delivered |
| 6 | Dead code cleanup | S | Medium — reduce confusion |
| 7 | Fix Sign Out | XS | Medium — security/UX bug |
| 8 | Fix pricing inconsistency | XS | Low — trust |
| 9 | Fix health check | XS | Low — monitoring |
| 10 | Security hardening | M | Medium — defense in depth |
S = small (1-2h), M = medium (half day), L = large (1-2 days)