Applications · entity catalog

metis app

Authored subsystem deep-dive for metis, layered on the code-linked entity catalog — what each system is, why it exists, and how it fits.

authored deep-dive
5entities2layers5deep-dives

On this page

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 catalog (5)#

The 5 tracked Nx projects in metis, each a code-linked entity node — package, type, source path, declared targets, and its internal dependency graph (depends-on / used-by, resolved from the package manifests, §6/§8), read from the project graph. Grouped by architectural layer; walk the dependency links to travel the system. 5 of these carry an authored deep-dive (what / why / how it fits); the rest are generated scaffolds awaiting one.

app (2)#

app

metis-api-gateway

@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.

buildtestlinttypecheckserve
layer: appscope: metisowner: @GreyChimp
app

metis-worker

@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.

buildtestlinttypecheckserve
layer: appscope: metisowner: @GreyChimp

unclassified (3)#

app

@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.

buildtestlinttypechecke2eprebuildprebuild:cleanstartstart:android
scope: metisowner: @GreyChimp
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.

buildtestlinttypechecke2edevlighthousestart
scope: metisowner: @GreyChimp
app

metis-admin

@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.

buildtestlinttypechecke2edevstart
scope: metisowner: @GreyChimp