# Metis — Systems Deep Dive

> The `apps/metis/` area: the TypeScript/Expo client-and-edge tier for
> **Metis**, the Oshun learning platform — a learner web PWA, an operator admin
> console, a mobile app, an HTTP API gateway, and a background-job worker, all
> sitting in front of a separate Python content backend.

## What this area is

Metis is Oshun's education product: a "core-six" learning platform centred on
philosophy, religion, psychology, neuroscience, anthropology, and astronomy,
with grounded (source-cited) tutoring, assessments, and course authoring. The
five Nx projects under `apps/metis/` are the **application tier** — the
user-facing surfaces and the edge services — written in TypeScript and Expo.
They are not where course content, retrieval, or the tutoring models live: those
sit in a **separate Python backend** that every one of these projects ultimately
talks to. The gateway's default upstream is `http://localhost:8000`
(`METIS_PYTHON_BACKEND_URL` in `apps/metis/api-gateway/src/config.ts`), and the
web/admin Next.js apps proxy through their own server routes to that same
backend.

The split is along surface and responsibility. `@metis/web` is the learner PWA
(Next.js, port 3020). `metis-admin` is the operator/moderation/observability
console (Next.js, port 3021). `@metis/mobile` is the Expo / React Native app.
`metis-api-gateway` is a dependency-free Node `http` reverse proxy that fronts
the Python backend with auth, rate-limiting, caching, transforms, a circuit
breaker, and a WebSocket relay. `metis-worker` is the background-job runtime
(export, notifications, analytics, cleanup, reports, content
transcode/thumbnail, search reindex) with its own queue, cron-style scheduler,
and health server.

These projects relate as a fan-in onto the Python backend rather than as a deep
internal dependency chain. The two Next.js apps each carry a thin server-side
proxy (`src/lib/server/metis-proxy.ts`, `admin-proxy.ts`) that forwards browser
requests to the backend; the standalone `metis-api-gateway` is the
infrastructure-grade equivalent for non-browser callers. The worker is an
independent process that the backend (or the gateway's job-queue view) feeds.
The web and mobile apps additionally compose sibling Oshun libraries —
`@aja/domain-motion-pipelines` (embodied/movement instruction hooks),
`@kalika/core` and `@kalika/sdk` (math exploration), and `@metis/models` /
`@metis/integrations` — so a Metis lesson can host a Kalika math explorer or an
Aja movement practice path.

## How it fits the wider system

The consumers are end users (learners on web and mobile, operators in admin) and
infrastructure (the gateway is consumed by clients/services that need a hardened
entry point to the Python backend). The hard boundary is the TypeScript-app-tier
vs. Python-backend line: none of these projects own the domain data model — they
validate, shape, cache, and present it. That boundary shows up concretely in the
data libraries, whose API response types are snake_case mirrors of the backend
(e.g. `MetisCourseLessonApiResponse` in `apps/metis/web/src/lib/course-data.ts`,
the `Api*` interfaces in `apps/metis/admin/src/lib/admin-client.ts`) that are
mapped into the apps' camelCase view models. Cross-domain integration is via the
proxy's forwarded control headers (`x-metis-isis-*`, `x-metis-lilith-*` in
`metis-proxy.ts`), which thread Isis course-generation control and Lilith
pedagogical-tone policy through to the backend. Walk the "used by" / "depends
on" edges on any node below to see the exact wiring.

## Entity reference

### metis-admin

The operator console (`apps/metis/admin`, Next.js App Router, port 3021). It is
a deep moderation / oversight / observability surface: routes for analytics,
audit trail, complaints, content moderation, courses, incidents, monitoring,
operations, oversight, review queues, source-rights, and user management
(`src/app/*/page.tsx`). All backend access flows through `AdminApiClient`
(`src/lib/admin-client.ts`, ~2,400 lines) which calls a `/api/admin` route that
server-side-proxies to the Python backend (`src/lib/server/admin-proxy.ts`), and
maps richly-typed snake_case API payloads (concept-graph validation, runtime
rollout decisions, retrieval inspections, cohort mastery heatmaps, source-rights
postures) into camelCase view models. This is a fully implemented app with a
large Playwright e2e suite (`e2e/` — moderation, incident command, audit trail,
WCAG AA signoff, keyboard-focus paths) and per-page vitest tests, not a
scaffold.

### metis-api-gateway

A dependency-free reverse proxy for the Python backend, built on Node's `http`
module (`apps/metis/api-gateway`, default port 3000). `MetisApiGateway` in
`src/app.ts` composes an onion-model middleware chain — logging, rate-limiting,
JWT auth-gating with per-method least-privilege permissions, response cache, and
camel/snake transform — then matches against domain route tables
(`DEFAULT_ROUTES` in `src/config.ts`: courses, assessments, tutoring, content,
users, analytics, admin, search, recommendations, notifications). It forwards
upstream through a `BackendProxy` with a real circuit breaker
(`src/proxy/backend-proxy.ts`, CLOSED/OPEN/HALF_OPEN states) and exposes
`/health`, `/ready`, and `/api/v1/gateway/status` plus a WebSocket relay
(`src/realtime/websocket-proxy.ts`). It handles CORS, graceful shutdown, and
body-size limits. Each middleware and route has a co-located `*.test.ts`. Fully
implemented edge service.

### @metis/mobile

The Expo / React Native learner app (`apps/metis/mobile`). `app/_layout.tsx` and
`app/index.tsx` are the Expo Router entry; `src/MetisMobileHome.tsx` renders the
learner home against a typed learning model in `src/learning-model.ts`. That
model defines 19 required mobile surfaces (browse, course detail/play, study,
tutor, assessment, authoring, saved, queue, resume, profile, goals, pace,
preferences, reminders, exports, downloads, sharing) and five run-states, with
resolver functions (`resolveMetisMobileResumeState`, `…SyncState`,
`buildMetisMobileSurfaceInventory`, coverage/gap finders) and tests. It composes
`@aja/domain-motion-pipelines` for embodied-instruction hooks. Honest scope
note: the screen is driven by a **hand-authored demo learner state**
(`metisMobileLearnerState`, learner "Maya") rather than live backend data — the
surface inventory, navigation actions, and offline/grounding semantics are real
and tested, but the data is a fixture, and there is a single home screen plus a
Maestro smoke flow (`e2e/flows/smoke.yaml`) rather than the full navigable app.

### @metis/web

The learner-facing PWA (`apps/metis/web`, Next.js App Router, port 3020). It has
the full learner journey as real routes — courses, course play, assessments,
tutoring, create/authoring, progress, study, saved, notifications, settings,
login (`src/app/*`) — backed by ~30 domain libraries under `src/lib`
(`course-data`, `assessment-data`, `profile-data`, `progress-data`,
`tutoring-data`, `grounded-sources`, plus genuine client logic like the
`kalika-exploration` math solver and `iris-study-continuity` resume planner),
each with co-located tests. Server routes (`src/app/api/metis/[...path]`,
`src/lib/server/metis-proxy.ts`) proxy to the Python backend and forward Isis
course-generation and Lilith pedagogical-tone control headers; the data libs
parse the backend's snake_case responses into client types. It is a real PWA
(`public/sw.js`, `manifest.json`, `PwaBootstrap`), has Lighthouse budgets and a
high-value-route performance test, an extensive Playwright suite, and composes
`@kalika/*`, `@aja/*`, `@metis/models`, and `@metis/integrations`. Fully
implemented.

### metis-worker

The background-job runtime (`apps/metis/worker`). `MetisWorkerService` in
`src/main.ts` orchestrates a priority `JobQueue` (`src/queues/job-queue.ts`), a
cron-style `JobScheduler` (`src/queues/scheduler.ts` with `DEFAULT_SCHEDULES`),
a processor registry, a concurrency-bounded polling loop, heartbeat and
memory-pressure monitoring, graceful shutdown, and an HTTP health server
(`/health`, `/ready`, `/stats`). It ships processors for course export, single
and batch notifications, analytics aggregate/snapshot, cleanup, reports, and
content transcode/thumbnail/search-reindex/assessment-generation (`src/jobs/*`).
A deliberate honesty seam runs through it: processors that need a real data
source **fail closed rather than fabricate** — e.g. `course-export.ts` refuses
to export without an injected `MetisCourseLoader` ("refusing to fabricate course
content"), and the analytics/notification processors report failure rather than
fake metrics or delivery until a real backend transport is wired (see the
comments in `registerDefaultProcessors`). The orchestration is fully implemented
and tested; the default-wired processors are intentionally inert until their
backing stores are injected.
