conceptadev / conceptadev/rockets
Field report: rebuilding a production API on Rockets v8 — findings and parity backlog
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 2
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 23
Description
# Field report: rebuilding a production API on Rockets v8 — findings and parity backlog
Tracking issue. We rebuilt a real production API (real-estate analytics: MLS proxying, valuation math, AI report generation, chat with tool calls, video rendering) on Rockets v8 **twice**, to separate two questions:
- **A — frozen contract**: reproduce the existing HTTP contract byte-for-byte, front end untouched. 47 routes, 225 e2e, router diff against a frozen `contract.json` with an empty allowlist, and the front end's own Zod `.strict()` schemas validating the new responses (18/18).
- **B — contract free**: use the framework to its ceiling — generated CRUD, CQRS commands/events, zod everywhere, contract redesigned where the framework earns it. 52 routes, 249 e2e, front end adapted.
## Headline results
| Measure | Legacy | A · frozen | B · max |
|---|---:|---:|---:|
| Framework-generated routes | 0 | 5/47 (10.6%) | **19/52 (36.5%)** |
| Server source LOC | 29,497 | 28,710 | 31,177 |
| Handwritten code deleted | — | — | **1,400 LOC (7 files)** |
| e2e | — | 225 | 249 |
| Front-end change | — | none | 23 files, +735/−300 (≈1/6 of the API-side cost) |
Interpretation we would stand behind: **Rockets pays clearly where the surface is owned-entity CRUD, and does not compress analysis/proxy/streaming surfaces** — 2/3 of this product. Contract freedom tripled generated routes but did not change that shape; what limits it is the closed operation set, not the contract.
## Filed from this study
- **#43** — non-CRUD operations as first-class (the single highest-impact item; ~10 of our handwritten routes would convert). Commented with second-phase evidence.
- **#44** — `rockets-repository-firestore` parity plan to become a production store of record. This decided our architecture: we chose TypeORM *before writing a line*, purely because the zod entity compiler is TypeORM-only and the Firestore adapter has no cross-entity transactions — the four transactional behaviors this product needs (fail-closed rate limiting, idempotent job enqueue, chat turn lock, render lease) had produced 9 raw-SDK bypasses in an earlier POC.
- **#45** — `ctx` omission silently disables entity hooks and escapes the operation's transaction. Found via a real defect: an expired parent record still minted working public share links.
## Backlog — not yet filed, evidence and reference implementations available
Each item below cost us handwritten code in **both** builds, i.e. contract freedom did not remove it. We have working, e2e-pinned implementations of all of them and are happy to extract any as a starting point.
- [ ] **`input` / `output` on the zod path.** `ZodResourceDefinition extends Omit<…, 'entity' | 'dto' | 'operations'>`, so the class path gets per-operation input/output DTOs and the zod path does not. Today you choose between controlled projection and automatic OpenAPI. *(Small.)*
- [ ] **Pluggable error envelope.** `RocketsCoreExceptionsFilter` hardcodes `{statusCode, errorCode, message, timestamp}` in `catch()` and both unwrap helpers are `private`, so an app with its own envelope re-implements the whole filter to change three keys — while needing to preserve the `context.originalError` unwrap chain (miss it and every hook 409 becomes a 500). Proposal: a serializer strategy + `protected` unwrap helpers. *(Small.)*
- [ ] **Global rate limiting.** The framework ships only an auth-route throttler. Every serious app writes a policy→route limiter; ours is a fail-closed fixed-window store over `@InjectDynamicRepository` + `TransactionScope`. *(Medium.)*
- [ ] **Background job port.** No dispatch abstraction (named tasks, dedupe, lease/heartbeat, at-least-once). Ours is a `JOB_DISPATCHER` token with an in-process implementation for tests and Cloud Tasks in deploy. *(Medium.)*
- [ ] **Session-cookie auth + CSRF + ternary route policy**, for apps whose identity is external (Firebase/Auth0/Clerk). `rockets-adapter-firebase` exposes only `verifyIdToken` — no `verifySessionCookie`, no cookie minting; there is no CSRF anywhere; and route policy is binary (`@AuthPublic()` vs protected) where we needed `public | internal | session`. With external identity, ~100% of auth is app code. *(Medium; two ~100-LOC adapters is the whole recipe.)*
- [ ] **Transport primitives: SSE and Range.** Zero framework support; three domains (chat, video, PDF) stayed fully app-owned in both builds. Note SSE cannot be expressed in OpenAPI — the route and body DTO can, the framing cannot. *(Large.)*
- [ ] **Discoverability of the non-CRUD transaction seam.** `transactional: true` exists only on CRUD operations; custom guards/services must discover upstream `TransactionScope` + per-call `{ ctx }`. Cost us 45 min of source spelunking and is the root of #45. *(Docs.)*
- [ ] **Ecosystem pinning.** `@nest-mcp/server` supports ≤ Nest 11, so an MCP surface on Nest 12 alpha requires reimplementing the streamable-HTTP transport. *(Ecosystem.)*
## Notes on method
Friction, bypasses and gaps were logged **at the moment they happened**, not reconstructed: 40+ friction entries, 39 bypass rows (each with an "could Rockets absorb this?" verdict), 54 gaps. Both builds were audited by an adversarial reviewer that ran the gates itself and rejected reported results; both came back REVISE and both work orders were executed before these numbers were published.
Two findings we would highlight for the maintainers, because neither was visible in a green test suite:
1. the `ctx` chain in #45, and
2. a repository call inside a hook that appeared transactional (and was documented as such) while committing outside the operation.
Happy to open any backlog item as its own issue on request, or to hand over the reference implementations.
Contributor guide
Research direction
Treat this as a tracking report rather than a single implementation task. Read the evidence for #43, #44, and #45, then choose one named backlog entry such as the zod input/output path, RocketsCoreExceptionsFilter, TransactionScope, or the JOB_DISPATCHER token. Done should be defined by a separately scoped issue with tests and reference behavior identified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- firebase, typescript
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100