Status legend: 🔴 critical · 🟠 high · 🟡 medium · 🟢 polish
Captured from architecture review on 2026-05-06. Functionality work takes priority; tackle this list afterwards or in parallel as time permits.
- File:
.env - Keys to rotate:
SUPABASE_SERVICE_ROLE_KEY,SUPABASE_ANON_KEY(optional),BAGS_API_KEY,ANTHROPIC_API_KEY,GEMINI_API_KEY,APIFY_TOKEN,TWITTERAPI_IO_KEY,TWITTERAPI_WEBHOOK_KEY. - Verify
.envwas never committed:git log --all --full-history -- .envandgit ls-files | findstr .env. If any history hit, force-rotate and consider history rewrite. - After rotation, restart
dev:serverand confirm/api/health/bagsreportsbagsKeyLoaded: trueandauthOk: true.
- File:
server/index.ts, mount before the/api/adminrate limiter. - Add env var
ADMIN_API_KEY(long random, not the same as anything else). - Reject any
/api/admin/*request withoutx-admin-keymatching, usingsafeEqual. - Update
.env.examplewithADMIN_API_KEY=.
- File:
server/index.ts:32-41. - If
process.env.NODE_ENV === "production"andCORS_ORIGINSis empty, throw on boot rather than allowing all origins.
ALTER TABLE narrative_tokens ADD COLUMN IF NOT EXISTS is_on_bags BOOLEAN DEFAULT false;
ALTER TABLE narrative_tokens DROP CONSTRAINT IF EXISTS narrative_tokens_tweet_ticker_unique;
CREATE INDEX IF NOT EXISTS idx_narrative_tokens_ticker ON narrative_tokens(tweet_ticker);
CREATE INDEX IF NOT EXISTS idx_narrative_tokens_tweet_id ON narrative_tokens(tweet_id);- File:
server/narrativePipeline.ts:560. ignoreDuplicates: truesilently drops updates tois_on_bags, score, and metadata. Switch to merge-on-conflict for the columns that should refresh; keep ignore only for immutable fields.
- File:
server/index.ts:1372-1393. - Cap parallel
runNarrativePipeline+fetchLinkPreviewcalls at 3-5 (small semaphore orp-limit). - Prevents 50-tweet webhook bursts from triggering Anthropic/Gemini/Bags 429s.
- File:
server/bagsClient.ts:223-236. - Verify Bags response shape; follow cursor/offset until exhausted. Otherwise the
is_on_bagsflag silently misclassifies tokens once the catalog grows past page 1.
- File:
server/index.ts:1010-1203. - Track
last_submitted_tx_signatureper launch. If the same signed tx body is replayed, return cached result instead of re-broadcasting.
- File:
server/index.ts(/api/launches). - Query RPC
getBalanceforwalletAddrbefore calling Bagscreate-token-info. Surface clear error early; current generic Bags 500 is hostile.
- Root
tsconfig.jsoncoveringserver/andsrc/. - Add npm script
"typecheck": "tsc --noEmit". - Wire into Railway / GitHub Actions pre-deploy.
- New file:
server/schemas.tsexporting per-route input schemas. - Refactor each handler to
Schema.parse(req.body)and return 400 onZodError. - Eliminates the manual
String(req.body?.x ?? "")pattern acrossserver/index.ts.
routes/auth.ts,routes/feed.ts,routes/launches.ts,routes/webhooks.ts,routes/admin.ts.jobs/metricsRefresh.ts,jobs/cleanup.ts,jobs/bagsRefresh.ts.services/launchService.tsfor the multi-step Bags flow.- Centralizes auth middleware (item 0.2) and shrinks merge-conflict surface.
- New file:
src/lib/useWallet.ts. - Move duplicated connect/disconnect/auth state from
FeedPage.tsx:106-159andTokenizePage.tsx:101-126.
{ error: { code, message, hint?, context? } }everywhere.- Update client
api.tsto parse the new shape uniformly.
- New folder:
server/__tests__/. - Cover: Bags-only result, Jupiter fallback fill, dedupe by mint, ticker collision, cache miss, AI weight thresholds.
- File:
server/narrativePipeline.ts:139-164. - Add stopword list (gm/am/the/etc.) OR require AI weight ≥ 70 before falling back to Jupiter-only matches.
- Prevents the feed filling with random tokens named after common verbs.
- File:
server/narrativePipeline.ts:63-92. - Build
Map<symbolLower, Token>andMap<nameWordLower, Token[]>at refresh time. Lookup is O(1) per term instead of O(N).
- File:
src/app/pages/FeedPage.tsx:55-63. - Subscribe to
tweetsandnarrative_tokenschannels; debounce re-render.
- Files:
src/app/routes.tsx:18,src/app/pages/TokenDetailPage.tsx. - Drop
mockTokenDatalookup or move it behind a dev flag.
- Either commit to Phantom-only and remove the fallback in
src/lib/phantom.ts:30, or adopt@solana/wallet-adapter-reactproperly.
- File:
src/app/components/TweetCard.tsx. - ~700 KB library; either
import()it on demand or replace with regex if usage is narrow.
npx supabase gen types typescript --project-id <id> > server/db.types.ts.- Replace
anycasts inserver/index.ts:535,541,635,1774,1810.
- File:
server/index.ts:1719-1756. - Pick the SDK-documented field names; treat the heuristic fallbacks as last-resort logged warnings.
- Single timer driving
metricsRefresh,bagsRefresh,cleanup,feedCacheRefreshwith offsets to prevent collisions.
- File:
server/loadEnv.ts:55-60. - Diagnose root cause of dotenv load order; remove disk re-read from hot paths.
- File:
server/index.ts:797-826. The branch is unreachable in a healthy schema and corrupts records on transient errors.
- Add to
.gitignore:Untitled,scratch/,dist/, any local-only docs.
When starting an item, create a branch fix/<phase>.<item>-<slug> (e.g. fix/0.2-admin-auth). Tick the item here in the same PR.