Repository navigation
apps api
Active contributors: Rom Iluz
apps/api is the Hono HTTP server that fronts Memongo's memory engine. In a standard deployment it is the only process that opens a MongoDB connection: everything else (the web console, the MCP server, the client SDK, AI SDK tools) talks to MongoDB indirectly by calling this app over HTTP. See Architecture for how it fits into the four-layer system (surfaces -> facade -> engine -> MongoDB) and Memory bridge for the facade it calls into.
This page covers the app's internal shape: directory layout, the request pipeline, and where to make changes. For the wire contract (endpoints, request/response bodies) see API. For auth, CORS, and rate-limiting design rationale, see Security. For the scope/tenant model enforced by scoped API keys, see Multi-tenancy and scopes. For how the app is containerized and deployed, see Deployment.
Route registration, middleware detail, and the OpenAPI document assembly are covered in Routes and middleware.
apps/api/
src/
app.ts Hono app factory: auth, CORS, rate limit, body limit, health/ready, graceful shutdown
server.ts process entry point: boot validation, capability probe, serve(), signal handlers
scope-identity.ts shared scope/agentId/scopeRef resolution (auth and routes read identity identically)
version.ts MEMONGO_API_VERSION, must match root package.json
openapi-spec.ts assembles the OpenAPI document from the path fragments below
openapi-schemas.ts shared OpenAPI schema fragments (scope enum, idempotency, TTL wording)
openapi-paths-*.ts one file per route family's OpenAPI path definitions
routes/
v1.ts router entry point: body pre-parse middleware, registers each route family
v1-helpers.ts shared request-body readers, validation-error mapping, limits
v1-search-routes.ts search, search-kb, recall-conversation, import, search-detailed
v1-context-routes.ts hydrate-active-slate, discovery-projection, context-bundle, read-file
v1-write-routes.ts add, write-event(s), extract, write-structured, write-procedure
v1-lifecycle-routes.ts lifecycle get/update/delete/history, procedure outcome, memory feedback
v1-status-routes.ts profile, state, status, stats, sync, embedding/vector probes
v1-admin-routes.ts relevance explain/report, access trends/summaries, traces, jobs
v1-maintenance-routes.ts chain-trace, novelty-scan, consolidate, self-edit
lib/
boot-env.ts fail-fast check that a MongoDB URI resolves before the port binds
capabilities.ts derives/logs which search lanes (vector/keyword/hybrid/text) are available at boot
errors.ts canonical `{ error: { code, message } }` envelope, dependency-unavailable -> 503 mapping
readiness.ts GET /ready lane checks: mongo ping, vector probe, embedding probe
validation.ts Zod schemas for write-family bodies, KB filters, and free-form metadata
Dockerfile multi-stage production image (turbo prune + bun build + node runtime)
| Concern | File(s) |
|---|---|
| App factory, auth, CORS, rate limit, body limit | apps/api/src/app.ts |
| Process entry point, boot checks, graceful shutdown wiring | apps/api/src/server.ts |
| Shared scope/agentId/scopeRef resolution (auth <-> routes) | apps/api/src/scope-identity.ts |
| Route registration and body pre-parse | apps/api/src/routes/v1.ts |
| Route families (8 files) | apps/api/src/routes/v1-*-routes.ts |
| Shared route helpers (readers, limits, idempotency) | apps/api/src/routes/v1-helpers.ts |
| Boot-time MongoDB URI check | apps/api/src/lib/boot-env.ts |
| Search-lane capability detection and logging | apps/api/src/lib/capabilities.ts |
| Error envelope and 503 classification | apps/api/src/lib/errors.ts |
| Liveness/readiness checks | apps/api/src/lib/readiness.ts |
| Zod input validation | apps/api/src/lib/validation.ts |
| OpenAPI document assembly |
apps/api/src/openapi-spec.ts, apps/api/src/openapi-schemas.ts, apps/api/src/openapi-paths-*.ts
|
| Release version constant | apps/api/src/version.ts |
| Production container image | apps/api/Dockerfile |
Every /v1/* request passes through the same middleware chain before it reaches a route handler. Order matters: request-id assignment happens first so every later rejection can be correlated, rate limiting happens before body parsing so an attacker cannot spend CPU on JSON parsing before being throttled, and the body-size cap runs before any handler reads the body.
sequenceDiagram
participant Caller
participant App as apps/api/src/app.ts
participant V1 as routes/v1.ts
participant Route as route family handler
participant Bridge as memory-bridge
Caller->>App: HTTP request
App->>App: secureHeaders(), CORS check
App->>App: requestId() (on /v1/*)
App->>App: rate limiter (per credential or trusted-proxy IP)
App->>App: bodyLimit() (default 1 MB, before JSON parsing)
App->>App: bearer auth: MEMONGO_API_KEY or a scoped API key policy
App->>App: scoped-key checks: route policy, admin-only paths, agent-global paths
App-->>Caller: 401/403/429/413 (short-circuit on any failure)
App->>V1: next()
V1->>V1: parseJsonRequestBody() once, stash on context
V1->>Route: dispatch by path
Route->>Route: scope-identity.ts resolves agentId/scope/scopeRef; lib/validation.ts validates body
Route->>Bridge: memongoBridge*(params)
Bridge-->>Route: typed result or thrown error
Route-->>Caller: 200 {...} or a mapped error envelope
Two failure paths bypass this chain deliberately: a deliberate HTTPException thrown by Hono internals (e.g. the body-limit middleware) returns its own response via app.onError, and anything unexpected falls through to lib/errors.ts's internalError, which logs the raw error server-side under the request id and returns a generic INTERNAL 500 (or SERVICE_UNAVAILABLE 503 for a recognized MongoDB network failure) — raw driver messages, hostnames, and stack traces never reach the client.
GET /health (liveness) and GET /ready (deep readiness: mongo ping + vector probe + embedding probe, from apps/api/src/lib/readiness.ts) sit outside the /v1/* auth chain because container orchestrators probe them without an API key. GET /openapi.json serves the assembled OpenAPI document unauthenticated as well.
-
Calls into
packages/memory-bridge: every route handler's terminal action is amemongoBridge*function call (for examplememongoBridgeSearch,memongoBridgeAdd,memongoBridgeWriteConversationEvent). The app never importspackages/memory-enginedirectly. -
Calls into
packages/lib: the canonical scope enum (MEMORY_SCOPE_VALUES), theApiErrorenvelope schema, the bearer security scheme, and the route table used for OpenAPI/route conformance checking all come frompackages/lib/src/contract.tsand friends, re-exported throughapps/api/src/scope-identity.tsandapps/api/src/openapi-spec.ts. -
Consumed by:
packages/client'sMemongoClient(HTTP calls),apps/mcp(stdio MCP server that proxies tool calls to/v1/*), andapps/web(the console, viaMEMONGO_API_URL). None of these call MongoDB directly — see Architecture. -
Contract conformance:
apps/api/src/contract-conformance.test.tsfails CI if the hand-written OpenAPI paths and the live router disagree, keepingapps/api/src/openapi-spec.tshonest againstapps/api/src/routes/v1.ts.
-
Add a new
/v1endpoint: add the field/route definition topackages/lib/src/contract.tsfirst, then add the handler to the relevantapps/api/src/routes/v1-*-routes.tsfile (or create a new route family file and register it inapps/api/src/routes/v1.ts), then add its OpenAPI path fragment to the matchingapps/api/src/openapi-paths-*.tsfile. The conformance test enforces that all three agree. -
Change auth or rate-limit behavior:
apps/api/src/app.ts(scoped API key policy parsing,AGENT_GLOBAL_V1_PATHS,ADMIN_ONLY_V1_PATHS, rate limiter bucket logic). -
Change how identity is resolved from a request:
apps/api/src/scope-identity.ts— edit here, not in individual routes, so auth and execution cannot diverge (see the issue #57 comments in that file). -
Add input validation:
apps/api/src/lib/validation.ts(Zod schemas), consumed by the write and search route families. -
Change boot behavior:
apps/api/src/server.tsandapps/api/src/lib/boot-env.ts/apps/api/src/lib/capabilities.ts. -
Change the container image:
apps/api/Dockerfile.
| File | Role |
|---|---|
apps/api/src/app.ts |
Hono app factory, auth, CORS, rate limiting, body limit, health/ready, graceful shutdown |
apps/api/src/server.ts |
Process entry point: boot validation, capability probe, serve(), signal handlers |
apps/api/src/scope-identity.ts |
Shared scope/agentId/scopeRef resolution used by both auth and routes |
apps/api/src/routes/v1.ts |
Router entry point and body pre-parse middleware |
apps/api/src/lib/errors.ts |
Canonical error envelope and dependency-unavailable classification |
apps/api/src/lib/readiness.ts |
/ready lane checks (mongo, vector, embedding) |
apps/api/src/lib/validation.ts |
Zod schemas for write/search bodies and metadata |
apps/api/src/openapi-spec.ts |
Assembles the OpenAPI document and enforces contract conformance |
apps/api/src/version.ts |
MEMONGO_API_VERSION constant |
apps/api/Dockerfile |
Production multi-stage image |