1. What it is
Four things in this repository are load-bearing but do not run in the oper
Kubernetes namespace, so Argo CD never sees them and kubectl cannot tell you
whether they are healthy: two GPU endpoints on Modal, one Cloudflare edge worker, and the public
documentation site. Three of the four are genuinely live; the fourth is deployed but currently
documents nothing.
| Who uses them | micro-learning's TTS worker (Modal Chatterbox) · RagFlow, driven by rag-context-worker (Modal MinerU) · anyone clicking an OTP or invitation link in an email (Cloudflare) · engineers and integrators (docs portal) |
| Runtime | Modal serverless GPU containers · Cloudflare Workers edge runtime · one in-cluster Docusaurus static pod (docs-portal, the only one with a Deployment) |
| Database | None. The Modal apps keep model weights in Modal Volumes (chatterbox-weights, mineru-model-cache); the edge worker is stateless. |
| Redis | None. |
| NATS streams | None. Every satellite is reached over HTTPS. |
| External APIs | They are the external APIs — Modal and Cloudflare are third-party platforms holding Oper data in transit. |
| Entry points | 1 Modal HTTPS endpoint (TTS) · 1 Modal HTTPS endpoint (PDF parse) · 3 edge paths · 1 static site |
| How they are deployed | By hand. There is no GitHub workflow for any of them except docs-portal (.github/workflows/docs-portal-ci.yaml): the Modal apps ship with modal deploy and the edge worker with wrangler deploy. Nothing reconciles them against this repository. |
Why this page exists
Everything here can break without a single Kubernetes signal firing. A Modal deploy that never happened, a Cloudflare route that 404s, a spec refresh that never ran — none of it shows up in Argo, in a pod restart count, or in a readiness probe. These are the blind spots, so each entry below states who calls it, how it gets deployed, and what proves it is live.
2. Feature map
flowchart LR ML["micro-learning TTS worker"] --> CB["chatterbox-modal (Modal A10G)"] CB --> WAV["narration audio → asset-manager"] RC["rag-context-worker"] --> RF["RagFlow (ragflow ns)"] RC -->|"warm-up ping"| MU["miner-u on Modal (L4)"] RF -->|"MINERU_APISERVER"| MU OTP["otp-worker email"] --> CF["link-otp-worker (links.useoper.com)"] CF --> APP["mobile app deep link"] DEV["Engineers"] --> DP["docs-portal (docs.useoper.com)"]
3. The satellites
Internal (other services)
chatterbox-modal — the voice behind every narrated lesson live
When a lesson screen needs spoken narration, the TTS worker sends the text and a reference voice clip here and gets back a WAV. It runs Chatterbox Multilingual on a Modal GPU that only exists while a sentence is being synthesised, which is why audio costs fractions of a cent per screen instead of the per-request minimums the previous provider charged. One multilingual model covers both English and Spanish.
- What calls it
- micro-learning-service-v2's TTS worker, at the URL in
TTS_ENDPOINT; a per-voiceendpointentry in the voice map can override it for A/B testing a second engine. - Contract
POST <endpoint>with{text, audio_url, language, temperature, exaggeration, cfg, seed}→ rawaudio/wav. 422 on missing text or reference clip (permanent failure for the worker); 5xx and timeouts are retried inside the worker's delivery budget.- Deployment
modal deploy app.py, by hand. Modal appchatterbox-tts, GPUA10G, 120 s scale-down window, weights in thechatterbox-weightsVolume. Auth is Modal proxy auth:MODAL_KEY/MODAL_SECRETfromtts-worker-v2-secrets.- Evidence of life
-
Endpoint pinned in cluster config:
micro-learning-service-v2/k8s/tts-worker-v2-configmap.yaml:11→https://fiott248--chatterbox-tts-multilingual-tts.modal.run; consumed atmicro-learning-service-v2/app/tts_worker/pipeline.py:793(raisestts_endpoint_missingif unset, so the audio pipeline cannot run without it). Credentials wired atmicro-learning-service-v2/k8s/tts-worker-v2-deployment.yaml:96andk8s/es-tts-worker-v2.yaml:29-31. Listed as live external egress inARCHITECTURE.md§3.6 and as "load-bearing for tts-worker-v2" in §2. Source:chatterbox-modal/app.py:29(app name),:43(GPU),:135(the proxy-auth POST endpoint).
miner-u on Modal — the PDF parser behind document ingest live
When an author uploads a manual or a policy PDF, RagFlow has to turn it into clean text and tables before anything can be generated from it. MinerU does that parsing on a GPU that scales to zero between documents — a 79-page manual takes one to two minutes instead of four, and idle time costs nothing. rag-context-worker pings it awake before queueing a parse so the author does not pay for the cold start.
- What calls it
- RagFlow (in the
ragflownamespace, whose manifests live outside this repo) viaMINERU_APISERVER. rag-context-worker selects the backend and sends the warm-up ping, but never parses directly. - Contract
- MinerU's own
/file_parseHTTP API. Because RagFlow's client cannot send custom headers, auth is a secret path prefix baked into the URL; the bare root returns only an anonymous{"status":"ok"}. - Deployment
modal deploy miner-u/modal/modal_app.py, by hand. Modal appmineru-parser, GPUL4by default, 20-minute warm window,min_containers=0, weights in themineru-model-cacheVolume.- Evidence of life
-
The backend is selected in cluster config —
rag-context-worker/k8s/configmap.yaml:19RAGFLOW_LAYOUT_RECOGNIZER: "mineru", read byrag-context-worker/app/ragflow/datasets.py:70-73— and the deployed Modal URL is pinned for warm-up atrag-context-worker/k8s/configmap.yaml:25(https://fiott248--mineru.modal.run/<prefix>/openapi.json), used atrag-context-worker/app/consumers/indexing_consumer.py:405. Source:miner-u/modal/modal_app.py:21-33. - Caveats worth knowing
-
Tenant PDFs leave the cluster to Modal's US infrastructure — a deliberate compliance call is
required before routing regulated content (
miner-u/modal/README.md:54-59). And the secret path prefix that serves as the endpoint's only authentication is committed in a plaintext ConfigMap (rag-context-worker/k8s/configmap.yaml:25); rotating it means redeploying the Modal app and updating both that URL andMINERU_APISERVERon the RagFlow pods.
Employee (mobile)
link-otp-worker — where an emailed sign-in link lands live
An employee gets a sign-in email, taps the link, and should end up signed in inside the Oper app. This Cloudflare worker is what that link points at. It serves the two association files iOS and Android require before they will let a website open an app, and it answers the link itself with a small page that hands the code to the app — never a redirect and never an empty response, both of which break Universal Links and silently strand the user in a browser.
- What calls it
-
Employee OTP emails sent by the otp-worker, which build
https://links.useoper.com/sign-in?code=…. Admin OTP emails deliberately point atapp.useoper.cominstead, so they never reach this worker. - Paths
/.well-known/apple-app-site-association·/.well-known/assetlinks.json·/sign-in?code=(mobile bridge page or desktop fallback page; an error page when the code is missing). Everything else returns 404.- Deployment
wrangler deploy, by hand — there is no workflow for it in.github/workflows/. Bound tolinks.useoper.comas a Cloudflare custom domain, so TLS is Cloudflare-managed.- Evidence of life
-
Producer:
users-auth-service/app/otp_worker/processor.py:195-199selectslinks.useoper.comfor employee OTP emails; the template rendershttps://{domain}/sign-in?code={code}(users-auth-service/app/otp_worker/templates/otp_email.html:91). Handler:cloudflare-workers/link-otp-worker/src/index.js:53. Domain binding:wrangler.jsonc:19-21. Also evidenced independently by the compliance audit, which treats the live OTP-in-URL flow as a real data-transfer path (compliance/shared/vendor-list.md:33).
Admin
docs-portal — the public API documentation site suspect
A Docusaurus site at docs.useoper.com intended to publish the OpenAPI reference
for every backend service, so an integrator or a new engineer can see the platform's HTTP
surface without reading the code. The site is deployed and serving. It currently documents no
endpoints at all.
- What calls it
- Humans, over the public internet. Nothing in the platform depends on it at runtime.
- Deployment
- The one satellite with real CI:
.github/workflows/docs-portal-ci.yamlbuilds the image, and it runs as an ordinary in-cluster Deployment (docs-portal/k8s/deployment.yaml:4,replicas: 1) behind an ingress fordocs.useoper.com(docs-portal/k8s/ingress.yaml:16). It is on this page because it is the documentation surface for everything else here, and because its content pipeline — not its pod — is the part that is broken. - The verifiable problem
-
All eight specs under
docs-portal/specs/are placeholders. Every one parses to"paths": {}with"version": "0.0.0-placeholder"and a description that says it "will be replaced by the docs-portal-refresh-specs workflow once it runs against the cluster" (e.g.docs-portal/specs/feed-service.json:5-7). The portal therefore renders a service list and zero endpoints. - Evidence
-
Parsed all of
docs-portal/specs/*.json: asset-manager, assignment, authoring-image-worker, feed, micro-learning-v2, rag-context-worker, suggest-pipeline-worker, users-auth —len(paths) == 0for all eight. The refresh workflow (.github/workflows/docs-portal-refresh-specs.yaml) isworkflow_dispatchplus a 06:00 UTC cron on ak8s-runner; it port-forwards eight services and opens a PR with the diff, and no such PR has landed. Its service list at:57-65no longer contains the deadauthoring-servicethatARCHITECTURE.md§4.2 recorded as making it hang — that half is fixed; the empty specs are not.
Background
None. Both Modal apps are request-driven and scale to zero; the edge worker runs per request; the docs pod serves static files. No satellite runs a scheduled job of its own — the only schedule involved is the spec-refresh cron, which runs in GitHub Actions, not here.
4. API reference
No Kubernetes Service and no in-cluster route: these are external endpoints and edge paths. "Callers" is the in-repo code or configuration that points at them.
| Method | Path | Auth | Feature | Callers | Verdict |
|---|---|---|---|---|---|
| POST | https://fiott248--chatterbox-tts-multilingual-tts.modal.run | Modal proxy auth (Modal-Key / Modal-Secret) | Narration synthesis | micro-learning-service-v2/app/tts_worker/pipeline.py:793 via TTS_ENDPOINT | live |
| POST | https://fiott248--mineru.modal.run/<secret-prefix>/file_parse | Secret path prefix | PDF parsing for RagFlow | RagFlow pods via MINERU_APISERVER (manifests outside this repo); warmed by rag-context-worker/app/consumers/indexing_consumer.py:405 | live |
| GET | https://links.useoper.com/sign-in?code= | none — the code in the URL is the credential | OTP deep link | users-auth-service/app/otp_worker/templates/otp_email.html:91 | live |
| GET | https://links.useoper.com/.well-known/apple-app-site-association | none (public by design) | iOS app-link association | iOS, before it will open the app for a link | live |
| GET | https://links.useoper.com/.well-known/assetlinks.json | none (public by design) | Android app-link association | Android, same | live |
| GET | https://links.useoper.com/i/<tenant-slug> | n/a | Invitation landing | users-auth-service/app/otp_worker/processor.py:378 — the worker has no handler for it | dead |
| GET | https://docs.useoper.com/ | none | API documentation | humans | suspect |
5. Async contracts
Consumes
| Subject | Stream | Durable | Published by | Feature | Verdict |
|---|---|---|---|---|---|
| None. No satellite has a NATS client; every one of them is reached over HTTPS. | |||||
Publishes
| Subject | Consumed by | Feature | Verdict |
|---|---|---|---|
| None. | |||
Background jobs
| Job | Schedule | What it does | Verdict |
|---|---|---|---|
docs-portal-refresh-specs.github/workflows/docs-portal-refresh-specs.yaml | Daily 06:00 UTC + manual | Port-forwards eight services, pulls their openapi.json, opens a PR with the diff | suspect — the specs it should be replacing are still placeholders, so either it is not completing or its PRs are not being merged |
6. Data it owns
No database and no tables anywhere in this page's scope. What each satellite holds:
| Store | What it holds | Written by |
|---|---|---|
Modal Volume chatterbox-weights | Chatterbox Multilingual model weights, downloaded once on first run so later cold starts only pay model load. | chatterbox-modal on first execution chatterbox-modal/app.py:33 |
Modal Volume mineru-model-cache | MinerU model weights, same pattern. | miner-u on first parse miner-u/modal/modal_app.py:35 |
Cloudflare Worker vars | The Apple and Android app-association documents. Public by design — they are served verbatim to anyone; no secret belongs here. | Set at deploy time from wrangler.jsonc |
| docs-portal image | Static HTML plus the eight (currently empty) OpenAPI specs, baked in at build time. | CI docs-portal/Dockerfile, .github/workflows/docs-portal-ci.yaml |
Nothing here writes an Oper database. The data that matters is data in transit: narration text
and reference clips to Modal, tenant PDFs to Modal, and an OTP code through Cloudflare's edge —
all three recorded as cross-border transfers in compliance/shared/vendor-list.md.
7. Dependencies
flowchart LR MLW["micro-learning TTS worker"] --> CB["chatterbox-modal"] RCW["rag-context-worker"] --> MU["miner-u on Modal"] RFLOW["RagFlow (ragflow ns)"] --> MU OTPW["otp-worker (users-auth image)"] --> MAIL["Mailgun"] MAIL --> USER["Employee inbox"] USER --> CFW["link-otp-worker"] CFW --> MAPP["Oper mobile app"] CI["GitHub Actions"] --> DP["docs-portal pod"] CB --> AM["asset-manager (via the TTS worker)"]
Note the asymmetry: rag-context-worker only selects and warms MinerU; the actual parse call is made by RagFlow, whose configuration lives outside this repository. That is the one edge on this page that cannot be fully verified from here.
8. Dead-code verdicts
Every satellite entry point that is not plainly live. Deleting is a separate decision — see the hub roll-up.
| Entry point | Kind | Verdict | Evidence |
|---|---|---|---|
https://links.useoper.com/i/{tenant_slug} — invitation links |
Edge route | dead |
The link is really sent:
users-auth-service/app/otp_worker/processor.py:375-379 builds
https://{invite_link_domain}/i/{tenant_slug} (or bare /i with no
slug), with invite_link_domain defaulting to links.useoper.com
(app/otp_worker/config.py:55-57); it is rendered into the invitation email at
app/otp_worker/processor.py:419 /
templates/invitation_email.html.And the worker cannot answer it: cloudflare-workers/link-otp-worker/src/index.js matches exactly three paths —
/.well-known/apple-app-site-association (:27),
/.well-known/assetlinks.json (:36) and /sign-in
(:44) — and every other request hits
return new Response("Not Found", { status: 404 }) at :81. There is
no route, no redirect and no catch-all. An invited employee lands on a 404. Confirms
ARCHITECTURE.md §4.1(8).
|
cloudflare-workers/link-otp-worker/wrangler.toml |
Config duplicate | dead |
Duplicate: the worker ships both wrangler.jsonc and
wrangler.toml for the same worker name and entry point.And divergent, in a way that would break production: the TOML carries a placeholder Apple team id ( ABCDE12345.com.useoper.training) where the JSONC has
the real one (U4KQGWA75N.com.useoper.training), and it omits the
custom_domains: ["links.useoper.com"] binding entirely. A deploy that picked up
the TOML would publish an association file that iOS rejects — silently breaking every
Universal Link — and would not bind the domain. Since there is no CI for this worker, which
file a given wrangler deploy reads is decided by whoever runs it. Confirms
ARCHITECTURE.md §4.1(8).
|
cloudflare-workers/link-otp-worker/test/index.spec.js |
Test | dead | Untouched create-cloudflare scaffolding: it fetches http://example.com and asserts the response body is "Hello World!" (:5-19), which this worker has never returned — that path hits the 404 branch. It asserts nothing about the three real routes and would fail if run. |
miner-u/k8s/ — the in-cluster CPU fallback |
Manifest | dead |
Referenced in three places: miner-u/README.md:20
(kubectl apply -f miner-u/k8s/deployment.yaml),
miner-u/modal/README.md:3 ("the in-cluster CPU pod (miner-u/k8s/)"),
and rag-context-worker/k8s/configmap.yaml:17 ("needs the GPU mineru-api workload
… k8s/mineru-api.yaml").And it does not exist: git ls-files miner-u returns exactly
four files — Dockerfile, README.md, modal/README.md,
modal/modal_app.py — and a repo-wide search for *mineru* filenames
finds no manifest anywhere. This also corrects ARCHITECTURE.md §2, which
describes the fallback as "a fallback with a placeholder image": there is no manifest and no
placeholder image left. The documented rollback path from Modal back to
http://mineru-api.ragflow.svc.cluster.local:8000
(miner-u/modal/README.md:38-40) therefore has nothing to roll back to — the CPU
Dockerfile survives, but the deployment that used it must be re-authored.
|
docs-portal/specs/*.json (all eight) |
Content | dead |
Nothing to serve: every file parses to "paths": {} — verified
by loading all eight with a JSON parser — and each declares itself a placeholder in
info.version (0.0.0-placeholder) and info.description.And the generator has not delivered: the only thing that can replace them is .github/workflows/docs-portal-refresh-specs.yaml, whose whole job is to
port-forward the services, fetch their live openapi.json and open a PR; no such
PR has landed, because the committed specs are still the originals. The pod at
docs.useoper.com is up and serving — it is the content that is empty.
|
docs.useoper.com (the site itself) |
Deployment | suspect | Deployed and reachable (docs-portal/k8s/deployment.yaml, ingress.yaml:16) with working CI, but no in-repo consumer and, given the empty specs, no demonstrated reader value today. Whether anyone actually visits it is not answerable from this repository — ingress access logs would resolve it. |
9. Sources
chatterbox-modal/README.mdandapp.py— endpoint contract, GPU choice, cost measurements, worker wiring.miner-u/README.md(CPU variant) andminer-u/modal/README.md+modal_app.py— the Modal deployment, the secret-prefix auth model and the data-residency caveats.cloudflare-workers/link-otp-worker/src/index.js,wrangler.jsonc,wrangler.toml,test/index.spec.js.docs-portal/—specs/*.json,scripts/services.config.mjs,k8s/, and.github/workflows/docs-portal-ci.yaml+docs-portal-refresh-specs.yaml.ARCHITECTURE.md§2 (the "Not in k8s" paragraph this page verifies and partly corrects), §3.6 (external egress), §4.1(8) (the Cloudflare worker defects), §4.2 (broken CI), §5 (both Modal directories marked KEEP).- Caller and configuration verification:
micro-learning-service-v2/k8s/tts-worker-v2-configmap.yamlandapp/tts_worker/pipeline.py;rag-context-worker/k8s/configmap.yaml,app/ragflow/datasets.py,app/consumers/indexing_consumer.py;users-auth-service/app/otp_worker/processor.py,config.pyandtemplates/. compliance/shared/vendor-list.mdandcompliance/_subagent-findings/cloudflare-edge-and-network.md— independent confirmation that the Cloudflare OTP path carries live traffic.