Skip to content

API: split app.ts into route modules, one Gemini client, remove dead code - #22

Merged
Bogzx merged 4 commits into
mainfrom
improve/2026-10-01-api-structure
Oct 1, 2026
Merged

Bogzx merged 4 commits into
mainfrom
improve/2026-10-01-api-structure

Conversation

@Bogzx

@Bogzx Bogzx commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Why

  • apps/api/src/app.ts was a 2,277-line, 87 KB file holding every route, its helpers and all middleware. Every later change in the API (keyless demo mode, the demo-team switch, both coming in follow-up PRs) has to touch it.
  • The rich wiki bootstrap had its own Gemini client. wiki-bootstrap-job.ts built a separate GoogleGenAI, so the API's largest fan-out of LLM calls skipped gemini.ts's retry policy and never showed up in Langfuse traces.
  • Dead code with a false README claim. extractLearning, EXTRACT_MODEL (gemma-4-31b-it) and the extract-prompt module served the Stop hook removed in PR Removed hook #5; nothing has imported them since. The README still said Gemma handled "async learning extraction" and "diff narration, rich bootstrap"; both use gemini-3-flash-preview.
  • Housekeeping. next dev (Next 16.3) writes AGENTS.md/CLAUDE.md into apps/dashboard, and bin/cli.mjs was committed without the executable bit. Both left a dirty tree after a normal install or run.

What changed

  1. Split (63b18db). app.ts becomes the app shell (243 lines): CORS, body caps, tracing, auth and LLM rate-limit middleware, GET /, route mounting, error handler.
    • http.ts holds what the middleware and routes share.
    • routes/{score,coach,assist,wiki,prompts,metrics,teams,onboard}.ts are Hono sub-apps mounted after the middleware.
    • Code moved verbatim, apart from app.<verb> → <router>.<verb> and export on the shared helpers.
    • apps/api/README.md documents the layout.
  2. One client (f897485).
    • gemini.generateText() runs one call through tracedGenerate + withRetry, and the bootstrap's three passes use it. Behaviour change: 429/5xx are now retried with backoff (timeouts still never retried, 90 s per call as before), and the calls are traced. Long-form answers are not capped at the 4 000 chars meant for short structured answers.
    • The extract-prompt module, EXTRACT_MODEL and extractLearning are deleted, along with their 9 tests.
  3. Housekeeping (93e9281). agentRules: false in next.config.mjs; cli.mjs is now 100755.
  4. README (0918f3f). Model lines match models.mjs; the route table points at src/routes/.

Verification

All on this branch, Node 22.23.3:

Check Result
npm run typecheck exit 0
npm run lint exit 0
npm test all pass. API 72 (was 71: +1 generateText test); scoring 35 (was 44: −9 tests of the deleted extract module); other workspaces unchanged
TRAILHEAD_IT_DATABASE_URL=… npm --workspace=apps/api run test:integration (Postgres 16) 38/38 pass. The suite drives every route and fails if a route in GET / lacks coverage, so a route lost in the split would show here.
npm --workspace=apps/dashboard run build exit 0
Booted src/index.ts against a fresh schema GET / 200, GET /wiki/tree 200, POST /score 400 on a bad body (as before), SIGTERM drains
next dev with agentRules: false AGENTS.md/CLAUDE.md no longer generated

The new test asserts that generateText makes exactly one request through the shared client and returns a 12 000-char answer uncapped.

Notes

This is the base of a stack. #23 (keyless demo mode) and the PRs after it build on this branch, so please merge this one first.

Bogdan Truta and others added 4 commits October 1, 2026 12:26
app.ts held every route, its helpers and the middleware in one 87 KB file.
It is now the app shell (CORS, body caps, tracing, auth, LLM rate limits,
GET /, route mounting, error handler: 243 lines), with:

- http.ts: what the middleware and the routes share (env type, tenant
  policy, rate limiting, the prompt cap, skill-observation writes)
- routes/{score,coach,assist,wiki,prompts,metrics,teams,onboard}.ts: one
  Hono sub-app per area, mounted after the middleware so every route still
  gets auth, body caps, tracing and rate limits

Code moved verbatim (apart from `app.<verb>` → `<router>.<verb>` and
`export` on the shared helpers), so behaviour is unchanged: the 38
Postgres integration tests, which drive every route and cross-check the
GET / catalog, pass unchanged. apps/api/README.md documents the layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wiki-bootstrap-job.ts built its own GoogleGenAI client, so the rich
bootstrap (the biggest fan-out of LLM calls in the API) bypassed the retry
policy and never appeared in Langfuse traces. It now calls
gemini.generateText, which goes through the same tracedGenerate/withRetry
path as the request handlers: 429/5xx are retried with backoff, timeouts
are still never retried (90 s per call, as before). generateText does not
apply the 4 000-char cap meant for short structured answers, because folder
narratives are several thousand words; a new test pins both properties.

Removed as dead code: extractLearning (gemini.ts), EXTRACT_MODEL
(gemma-4-31b-it) and the extract-prompt module in packages/scoring with its
tests. They served the Stop hook that was removed in PR #5; nothing has
imported them since. The README's "Gemma for async learning extraction"
claim goes with them; every call uses gemini-3-flash-preview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ecutable

Next 16.3 generates AGENTS.md and CLAUDE.md in apps/dashboard on every
`next dev` unless `agentRules: false` is set; they showed up as untracked
files for anyone running the dashboard. apps/mcp-server/bin/cli.mjs has a
shebang and is the package's `bin`, but was committed as 100644 (npm fixed
the mode on install, leaving a dirty tree).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…utes/

The README said gemma-4-31b-it handled "async learning extraction" and
"diff narration, rich bootstrap". Learning extraction was never wired up
(removed in the previous commits) and /diff and the bootstrap use
gemini-3-flash-preview. Also points the route table at the new layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
learnloop Building Building Preview Oct 1, 2026 12:26pm UTC
polihackwinners-dashboard Ready Ready Preview Oct 1, 2026 12:26pm UTC

This branch was successfully deployed

2 active deployments
Preview – polihackwinners-dashboard — 0918f3f7 Deployed Oct 1, 2026 by vercel[bot]
Preview – learnloop — 0918f3f7 Deployed Oct 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant