Comprender MVP — Effort E1 (foundation + identity)
:::note Contenido en inglés Esta página del wiki se sincroniza desde la base de conocimiento en inglés y todavía no está traducida. :::
canonical· pm · updated 2026-09-05 · source
What the product side of TED OS IS today, after effort E1 shipped (deployed). This is the
client-facing System of Record (tenant data) — separate from the dev-workflow Plan Engine
graph. It describes the running system, not the build process; for "what happened" see
decisions/log.md.
Note (ADR-017, 2026-08-31): the two-level
apps/adminshell this doc describes is now FROZEN —apps/portalis the primary tenant surface, and Comprender itself is retiring/ migrating into portal. The System of Record + contract described below (@tedos/domain,@tedos/shared) remain canonical; the admin-shell delivery detail is historical.
Comprender = tenant #1. The first paying client (an education provider) is the first project on the platform. E1 is "MVP slice 1": identity-first — a single, unified person deduped across Comprender's channels, with fiscal data, on real infra with server-side tenancy + roles.
What E1 delivered
- A product System of Record for tenant/client data — package
@tedos/domain(Drizzle/Postgres), in a dedicatedproductPostgres schema. - A frozen shared contract in
@tedos/shared(/domain+/apientry points): zod-as-source- inferred TypeScript types for
project/person/person_identity, plus the 8 endpoint request/response shapes. Both the API and the admin import it — consistency by construction.
- inferred TypeScript types for
- Auth + tenancy in
apps/api(Clerk): arequireProjectguard maps a Clerk org →projectId- role; superadmin is the operator (
OPERATOR_USER_IDS). Every/p/:id/*route is authorized server-side.
- role; superadmin is the operator (
- Projects + Person API in
apps/api(Fastify) — see the surface below. - A two-level admin shell in
apps/admin: Level 1 (platform) + Level 2 (project context). - Match-key dedupe (email / phone / RFC): the same person arriving from two channels unifies into one record, with an append-only merge audit.
- Deployed to real infra (Fly + Vercel) — see deploy topology.
The product SoR is isolated from the dev-workflow graph (hard rule)
Per ADR-006, tenant/client data must never enter the dev-workflow graph. The product SoR uses
its own Drizzle journal/config in a dedicated product Postgres schema. The dev-workflow Plan
Engine graph (@tedos/db, effort #560, live) uses a dedicated plan schema. The two never
share tables. As built, both schemas currently live on the same Fly MPG (managed Postgres)
cluster — a documented compromise (no real tenant data exists yet) with a tracked upgrade path:
move the plan graph to a dedicated cluster before real tenant-PII volume or any external
training-data export. See plan-engine.md §7 for the full decision + upgrade
path. This boundary is the product/workflow split applied at the data layer.
Data model (@tedos/domain, Drizzle — product schema)
| Table | Purpose | Key fields |
|---|---|---|
project | The tenant (= a Clerk org = a client) | id · clerk_org_id · name · status · domain · created_at |
person | A unified person inside a project | id · project_id · full_name · email · phone · rfc (fiscal, PII-masked) · created_at · updated_at |
person_identity | One source/channel record for a person | id · person_id · channel (live | recorded | posgrado) · external_ref · raw (jsonb) |
person_merge | Append-only merge audit log | merge source/target + reason |
Match keys — unique-ish on (project_id, email), (project_id, phone), (project_id, rfc);
the merge/dedupe service links/dedupes on these. Tenant scoping (project_id) is mandatory on
every product row.
API surface (apps/api, Fastify v5)
All routes behind the auth/tenancy guard (Clerk org + role; superadmin = any project). Tenant scoping is server-side, never trusted from the client.
| Method | Route | What |
|---|---|---|
GET / POST | /projects | List / create the operator's projects |
GET | /projects/:id | One project |
GET | /p/:id/students | List + search the project's people |
GET | /p/:id/students/:sid | One person (single-view) |
POST / PATCH | /p/:id/students | Create / update a person |
POST | /p/:id/students/merge | Merge two people (dedupe) |
GET | /p/:id/summary | Project summary (basic) |
The admin reaches these through a proxy at /api/e1/* (env ENGINE_API_URL), so Clerk session +
tenant context inject server-side.
Two-level admin shell (apps/admin)
The same chrome wraps both levels; the level swaps only the sidebar + topbar slots (composition, not a boolean variant).
- Level 1 — platform:
/projectsswitcher (pick / create a project). Root route group. - Level 2 — project context:
/p/[projectId]/…swaps in the project sidebar, sets org context (ProjectProvider), and renders role-scoped nav (Owner / Sales / Finanzas / Soporte / Alumno). Screens: Alumnos list, person single-view (channels, fiscal, enrollments placeholder), Resumen (basic).
Each screen ships the 4 mandatory states and follows the admin conventions (semantic tokens,
HugeIcons, Grid v2, components/ui/ reuse, one Cian accent per screen). Paper design was
deferred for E1 — the screens use the existing design system and are flagged for later Designer
review (see below).
Roles
Clerk org membership maps to a ProjectRole: Owner · Sales · Finanzas · Soporte · Alumno. The
operator is superadmin (OPERATOR_USER_IDS) — any project. The role gates Level-2 nav (admin)
and authorization on every /p/:id/* route (API).
Deploy topology
- API — Fly app
tedos-api(regiongru) as two process groups:web(Fastify) +worker(pg-boss). Backed by Fly Managed Postgres (Basic,gru). Live athttps://tedos-api.fly.dev(custom domainapi.tuempresa.digitalpending DNS). - Admin — Vercel (
tedos-admin). - The product SoR (
productschema) and the dev-workflow Plan Engine graph (planschema) currently share this Fly MPG cluster, isolated by Postgres schema — a documented compromise with a tracked upgrade path to a dedicated cluster (see the hard rule above andplan-engine.md§7).
Screens flagged for Designer review (Paper deferred)
E1 shipped these on the existing design system without a Paper spec; each needs a later
Designer pass (per design-routing.md):
/projects— Level-1 platform project switcher/p/[projectId]— Level-2 project shell + role-scoped nav- Alumnos — people list
- Person single-view — channels, fiscal, enrollments placeholder
- Resumen — basic project summary
Related docs
orientation.md— how to read the project + system status.decisions/adrs/ADR-006-effort-workflow-trace.md— effort model + the tenant-data/dev-graph separation rule.decisions/adrs/ADR-001-backend-stack.md— Fastify + Drizzle + Postgres.admin-design-system.md— admin tokens the E1 screens consume.
The Comprender hand-authored theme (
.tenant-comprendernavy+gold scope, custom fonts, section bands — effort #1376) was removed by effort #1461: the tenant portal renders only on the neutral design system + runtimebrandingTokens; the single-rail chrome stays as the generictenant-chrome. The old spec (comprender-tenant-design.md) is deleted — git is the archive.