From f8d46e05cfd0da6bb65bfde2bed07736aaca0795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ramiro=20Entrerrios=20Garc=C3=ADa?= <100527906+Sebas1705@users.noreply.github.com> Date: Thu, 12 Nov 2026 17:52:25 +0100 Subject: [PATCH] docs(architecture): align flows, topology and contract claims with code on main - rewrite key sequence flows from the real gateway, BFF and service routes - mark target vs current in the platform architecture and add quizz/word-pass -> gateway -> ai-engine - state that shared-sdk-client is an internal TypeScript library - mark event schemas, Outbox and contract-driven SDK regeneration as not implemented - note that true-false exists only in ai-engine --- architecture/c4-views.md | 11 +- .../0003-contracts-as-source-of-truth.md | 2 + architecture/domain-model.md | 12 +- architecture/glossary.md | 4 +- architecture/key-sequence-flows.md | 213 +++++++++++------- architecture/master-alignment.md | 10 +- architecture/quality-attributes.md | 14 +- architecture/target-architecture.md | 35 ++- architecture/use-cases.md | 2 +- .../capabilities/ai/ai-content-generation.md | 2 +- .../platform/contract-governance.md | 6 +- guides/communication/service-communication.md | 2 +- guides/foundations/tfm-practice-matrix.md | 2 +- 13 files changed, 193 insertions(+), 122 deletions(-) diff --git a/architecture/c4-views.md b/architecture/c4-views.md index 12e2885..e730177 100644 --- a/architecture/c4-views.md +++ b/architecture/c4-views.md @@ -67,8 +67,8 @@ System_Boundary(ai, "AI") { System_Boundary(platform, "Platform / Governance") { Container(platformInfra, "platform-infra", "kustomize + GH workflows", "Build, push, deploy") - Container(contracts, "contracts-and-schemas", "OpenAPI + JSON Schema", "Source of truth") - Container(sdk, "shared-sdk-client", "TS/Python/Kotlin", "Generated clients") + Container(contracts, "contracts-and-schemas", "OpenAPI + JSON Schema", "Hand-written docs validated by CI; no code generation") + Container(sdk, "shared-sdk-client", "TypeScript", "Internal TypeScript library (shared schemas, HTTP proxy, game runtime)") Container(secretsRepo, "secrets", "GitOps repo", "Sealed material") Container(obs, "observability-platform", "Prometheus/Grafana stack", "Telemetry + alerts") } @@ -87,8 +87,8 @@ Rel(bffBack, quiz, "HTTP") Rel(bffBack, wp, "HTTP") Rel(bffBack, aiStats, "HTTP") Rel(bffBack, gateway, "HTTP (control plane mutations)") -Rel(quiz, aiApi, "HTTP (generation)") -Rel(wp, aiApi, "HTTP (generation)") +Rel(quiz, gateway, "HTTP (generation, /internal/ai-engine)") +Rel(wp, gateway, "HTTP (generation, /internal/ai-engine)") Rel(aiApi, llama, "HTTP") Rel(aiApi, redis, "TCP") Rel(aiStats, redis, "TCP") @@ -96,8 +96,7 @@ Rel(users, usersDb, "TCP") Rel(quiz, quizDb, "TCP") Rel(wp, wpDb, "TCP") Rel(platformInfra, gateway, "deploys") -Rel(contracts, sdk, "feeds") -Rel(sdk, gateway, "imports") +Rel(sdk, gateway, "imports (also both BFFs, users, quizz, wordpass)") Rel(sdk, bffMobile, "imports") Rel(sdk, bffBack, "imports") ``` diff --git a/architecture/decision-records/0003-contracts-as-source-of-truth.md b/architecture/decision-records/0003-contracts-as-source-of-truth.md index 69a9d10..5b8057a 100644 --- a/architecture/decision-records/0003-contracts-as-source-of-truth.md +++ b/architecture/decision-records/0003-contracts-as-source-of-truth.md @@ -13,6 +13,8 @@ Multiple services and channels exchange request/response payloads. Without a sin CI enforces the chain: contracts validated -> SDK regenerated -> consumers compiled against new SDK. +> **Status note (2026-11-12): partially implemented.** Contracts are validated in CI, but nothing regenerates the SDK: `shared-sdk-client` is a hand-written internal TypeScript library and there are no Python or Kotlin clients. The OpenAPI files cover the internal services only (not the gateway or the BFFs), and the event schemas have no producer or consumer. Treat the chain above as the intended direction, not as the current behaviour. + ## Alternatives considered 1. Per-service schemas duplicated locally: rejected; produced silent drift historically. diff --git a/architecture/domain-model.md b/architecture/domain-model.md index 6150d3f..3b48ead 100644 --- a/architecture/domain-model.md +++ b/architecture/domain-model.md @@ -122,12 +122,14 @@ classDiagram ## Cross-context contracts -| Contract | Producer | Consumer | Source | +> Updated 2026-11-12: the Zod schemas below are defined in `shared-sdk-client/typescript/src/game-schemas.ts` and imported by the services. The JSON Schema and OpenAPI copies in `contracts-and-schemas` are hand-written documentation; nothing is generated from them. + +| Contract | Defined in (code) | Consumer | Documented in | |---|---|---|---| -| `RandomGameQuerySchema` | `contracts-and-schemas` | `api-gateway`, `bff-mobile`, `microservice-{quizz,wordpass}` | shared SDK | -| `LeaderboardQuerySchema` | `contracts-and-schemas` | `api-gateway`, `bff-mobile`, `microservice-users` | shared SDK | -| `GameCategoriesSchema` | `contracts-and-schemas` (json) | `shared-sdk-client/typescript`, gameplay services | generated at SDK build | -| AI generation request | `contracts-and-schemas/openapi/ai-engine` | quiz/wordpass, bff-backoffice | generated client | +| `RandomGameQuerySchema` | `shared-sdk-client` (`game-schemas.ts`) | `api-gateway`, `bff-mobile`, `microservice-{quizz,wordpass}` | `contracts-and-schemas/schemas/json/random-game.query.v1.json` | +| `LeaderboardQuerySchema` | `shared-sdk-client` (`game-schemas.ts`) | `api-gateway`, `bff-mobile`, `microservice-users` | `contracts-and-schemas/schemas/json/leaderboard.query.v1.json` | +| `GameCategoriesSchema` | `shared-sdk-client` (`game-schemas.ts`) | gameplay services | `contracts-and-schemas/schemas/json/game-categories.v1.json` | +| AI generation request | `ai-engine` (FastAPI app) and `shared-sdk-client` `ai-engine-client.ts` | quiz/wordpass (through the gateway) | `contracts-and-schemas/schemas/openapi/internal-ai-engine.v1.yaml` (partial) | ## Anti-patterns explicitly rejected diff --git a/architecture/glossary.md b/architecture/glossary.md index 0dd0076..96379a9 100644 --- a/architecture/glossary.md +++ b/architecture/glossary.md @@ -25,8 +25,8 @@ Common terms used across AxiomNode documentation. | Sealed-secret | Encrypted secret object committed to git and decrypted in-cluster. | | Validation chain | Per-repo CI gates (lint, test, audit, contract validation) that must pass before dispatch. | | Dispatch | Cross-repo `repository_dispatch` from a service to `platform-infra` to trigger build/push. | -| SDK | Generated client library distributed via `shared-sdk-client` (TS / Python / Kotlin). | -| Contract | OpenAPI/JSON Schema/event schema in `contracts-and-schemas`. | +| SDK | `shared-sdk-client`: an internal TypeScript library (shared Zod schemas, HTTP proxy helpers, game-service runtime). Not generated from contracts. | +| Contract | OpenAPI/JSON Schema/event schema in `contracts-and-schemas`. Hand-written and validated by CI; the event schemas are not implemented. | | Bounded context | DDD term; one microservice = one context. | | Aggregate | DDD term; consistency boundary inside a bounded context. | | ADR | Architecture Decision Record (see `decision-records/`). | diff --git a/architecture/key-sequence-flows.md b/architecture/key-sequence-flows.md index 2643470..d61653c 100644 --- a/architecture/key-sequence-flows.md +++ b/architecture/key-sequence-flows.md @@ -1,11 +1,15 @@ # Key Sequence Flows -Last updated: 2026-04-22. +Last updated: 2026-11-12. Sequence diagrams of the most important runtime flows. Each flow lists the use case it satisfies and the failure points to consider. +> **Verification (2026-11-12):** SF-01, SF-02, SF-04, SF-05, SF-06 and SF-07 were rewritten from the route registrations and handlers on `origin/main` of `api-gateway` (`23e067b`), `bff-mobile` (`a3a3fc5`), `bff-backoffice` (`eb4a4a7`), `microservice-quizz`, `microservice-word-pass`, `microservice-users`, `ai-engine` and `shared-sdk-client` (`typescript/src/game-routes.ts`). The earlier version (2026-04-22) described routes that do not exist (`/v1/games/quiz/random`, `/admin/routing/ai-engine`, `/rounds/:id/result`, ...). SF-03 was not re-verified here. Wherever a claim could not be confirmed in code, the flow says so. + ## SF-01 Mobile player starts a quiz round (UC-01) +`GET /v1/mobile/games/quiz/random` only reads rows that are already stored. It never calls `ai-engine`: content is produced beforehand by the generation endpoints and the batch worker (SF-07). The word-pass flow is identical with `/v1/mobile/games/wordpass/random` and `microservice-wordpass`. + ```mermaid sequenceDiagram autonumber @@ -13,35 +17,31 @@ sequenceDiagram participant GW as api-gateway participant BFF as bff-mobile participant Q as microservice-quizz - participant AI as ai-engine-api - participant L as llama runtime + participant DB as quizz DB - App->>GW: GET /v1/games/quiz/random?... - GW->>GW: Validate RandomGameQuerySchema - GW->>BFF: forwardHttp(/quiz/random) - BFF->>Q: GET /random?categoryId=... - Q->>Q: select cached GameGeneration by difficulty (Prisma) - alt cache hit - Q-->>BFF: 200 generation payload - else cache miss - Q->>AI: POST /generate {category, difficulty} - AI->>AI: optimizer + RAG retrieve + cacheKey - AI->>L: POST /completion - L-->>AI: model output - AI-->>Q: 200 generation - Q->>Q: persist GameGeneration (difficultyPercentage materialized) - Q-->>BFF: 200 generation - end - BFF-->>GW: 200 normalized payload + App->>GW: GET /v1/mobile/games/quiz/random?categoryId=...&count=...&language=... + GW->>GW: validate query (MobileRandomQuerySchema), drop language + GW->>BFF: GET /v1/mobile/games/quiz/random (mobile circuit breaker) + BFF->>Q: GET /games/models/random?categoryId=... + Q->>DB: find stored GameGeneration rows (gameType quiz, status != pending_review) + DB-->>Q: candidate rows + Q->>Q: pick random models + Q-->>BFF: 200 {gameType, requested, returned, items} + BFF->>BFF: apply requested count to items + BFF-->>GW: 200 GW-->>App: 200 ``` Failure points: -- Invalid query → 400 from gateway, never reaches BFF. -- AI cache miss + llama unreachable → 503 surfaced with correlation id. -- DB unreachable → 5xx, no partial writes. +- Invalid query: 400 from the gateway, never reaches the BFF. +- Nothing stored for the category: the service answers 200 with `returned: 0`; no AI call is made as a fallback. +- Upstream failure or open circuit breaker at the gateway: 503 `Service temporarily unavailable`. + +Related: `POST /v1/mobile/games/quiz/generate` (and `/wordpass/generate`) is also served from the inventory. `bff-mobile` calls the same `GET /games/models/random` on the service, returns the first item as `generated`, and answers 502 `No game models available to build a playable game` when there is none. It does not trigger AI generation. + +## SF-02 Backoffice operator changes the runtime AI target (UC-09) -## SF-02 Backoffice operator changes runtime AI target (UC-09) +There are two independent targets. This flow covers the llama target that `ai-engine-api` uses for generation. The gateway keeps its own ai-engine API/stats target, changed with `PUT /internal/admin/ai-engine/target` (guarded by `API_GATEWAY_ADMIN_TOKEN` when set); it is not changed by this flow. ```mermaid sequenceDiagram @@ -50,28 +50,30 @@ sequenceDiagram participant GW as api-gateway participant BFF as bff-backoffice participant AI as ai-engine-api - participant PV as mounted PV - - SPA->>GW: PATCH /admin/routing/ai-engine - GW->>BFF: forward - BFF->>BFF: authorize operator role - BFF->>GW: PATCH /admin/runtime-target {url} - GW->>PV: persist RoutingTarget(scope=gateway-ai) - GW-->>BFF: 200 - opt also update llama - BFF->>AI: PATCH /runtime/llama-target - AI->>PV: persist RoutingTarget(scope=ai-llama) - AI-->>BFF: 200 - end - BFF-->>SPA: 200 effective target snapshot + participant Store as llama target store + + SPA->>GW: PUT /v1/backoffice/ai-engine/target {target} + GW->>GW: check edge token (EDGE_API_TOKEN, when configured) + GW->>BFF: PUT /v1/backoffice/ai-engine/target + BFF->>BFF: validate AiEngineTargetSchema + BFF->>AI: PUT /internal/admin/llama-target (x-api-key when configured) + AI->>Store: save override and apply it to the running generator + AI-->>BFF: 200 target payload + BFF->>BFF: clear upstream cache and breakers + BFF-->>GW: 200 effective target snapshot + GW-->>SPA: 200 ``` +`DELETE /v1/backoffice/ai-engine/target` follows the same path and resets the override to the environment value. + Failure points: -- PV write failure → revert in-memory state, return 5xx. -- Drift vs manifests is expected; runbook documents reconciliation. +- Invalid payload or a failed sync with `ai-engine-api`: the BFF answers 400 with the error message. +- Whether the override survives a pod restart depends on where `llama_target_store` writes in the deployment; this was not verified in this review. ## SF-03 CI/CD build and staging deploy (UC-12, UC-13) +> Status: thesis-era flow. On `origin/main` of `platform-infra`, `deploy.yaml` is manual-only (`workflow_dispatch`) because the k3s staging host no longer exists; only the build and push step still runs. The `workflow_run` trigger shown below is currently disabled. The rest of this flow was not re-verified. + ```mermaid sequenceDiagram autonumber @@ -97,7 +99,7 @@ Failure points: - Image digest mismatch → deploy aborts. - Smoke check fail → rollout marked unhealthy; manual intervention. -## SF-04 Operator inspects AI history with difficulty filter (UC-06) +## SF-04 Operator inspects stored quiz history with a difficulty filter (UC-06) ```mermaid sequenceDiagram @@ -108,49 +110,56 @@ sequenceDiagram participant Q as microservice-quizz participant DB as quizz DB - SPA->>GW: GET /admin/quiz/history?difficulty=hard&limit=... - GW->>BFF: forward - BFF->>BFF: cache lookup (TTL key normalized w/o querystring) - alt cache hit - BFF-->>SPA: 200 from cache - else cache miss - BFF->>Q: GET /historyPage?difficulty=... - Q->>DB: SELECT ... WHERE difficultyPercentage BETWEEN ... + SPA->>GW: GET /v1/backoffice/services/microservice-quiz/data?dataset=history&difficultyPercentage=...&page=... + GW->>GW: check edge token (EDGE_API_TOKEN, when configured) + GW->>BFF: GET /v1/backoffice/services/microservice-quiz/data + BFF->>BFF: validate DataQuerySchema + BFF->>BFF: upstream cache lookup (TTL depends on the upstream path) + alt cache miss + BFF->>Q: GET /games/history?limit=...&page=...&pageSize=...&difficultyPercentage=... + Q->>DB: query stored generations DB-->>Q: rows - Q-->>BFF: 200 - BFF->>BFF: store in metrics cache - BFF-->>SPA: 200 + Q-->>BFF: 200 page of history end + BFF->>BFF: apply filter/sort, compute history insights + BFF-->>GW: 200 {service, dataset, total, page, pageSize, rows, insights} + GW-->>SPA: 200 ``` Failure points: -- DB slow query → BFF returns 504 after upstream timeout. -- Cache stampede → mitigated by short TTL + per-path key normalization. +- Invalid query: 400 from the BFF with the flattened validation errors. +- Slow or unreachable service: the BFF applies its upstream timeout and circuit breaker; the exact status mapping was not verified here. +- The service key for the quiz service is `microservice-quiz` (not `microservice-quizz`) in the BFF routes. ## SF-05 AI ingest / corpus refresh (UC-11) +There is no BFF route for ingestion. The entry point is the game service, which forwards to `ai-engine` through the gateway (see SF-07 for the same hop used by generation). + ```mermaid sequenceDiagram autonumber - participant Op as Operator/Cron + participant Op as Internal caller + participant Q as microservice-quizz + participant GW as api-gateway participant AI as ai-engine-api - participant Vec as vector store - participant Cache as Redis - - Op->>AI: POST /ingest {corpus_id} - AI->>AI: load curated corpus - AI->>AI: compute embeddings (MiniLM-L12) - AI->>Vec: upsert vectors - AI->>AI: compute new corpusSignature - AI->>Cache: invalidate by signature prefix (logical) - AI-->>Op: 202 ingestion accepted + + Op->>Q: POST /games/ingest {documents[], source?, categoryId?, difficultyPercentage?} + Q->>GW: POST /internal/ai-engine/ingest/quiz + GW->>AI: POST /ingest/quiz + AI->>AI: normalize metadata, pipeline.ingest(docs), refresh optimizer + AI-->>GW: 200 {ingested} + GW-->>Q: 200 + Q-->>Op: 202 {gameType, ingested} ``` Failure points: -- Embedding model load failure → ingestion aborts, previous signature retained. -- Vector store partial write → ingestion marked failed; retry idempotent. +- Invalid payload: 400 from the service. +- `ai-engine` unavailable or RAG pipeline not initialised (503 from `ai-engine`): the service answers 502 `Failed to ingest documents into ai-engine RAG`. +- `ai-engine` also exposes the generic `POST /ingest` and `POST /ingest/word-pass`; `POST /ingest/true-false` exists but nothing calls it (see the true-false note below). + +## SF-06 Player submits gameplay results (UC-03) -## SF-06 Player submits gameplay result (UC-03) +State on `origin/main`: results stay inside `bff-mobile`. `microservice-quizz` has no result endpoint and `microservice-users` is only used by the BFF to identify the player. ```mermaid sequenceDiagram @@ -158,23 +167,66 @@ sequenceDiagram participant App as Mobile App participant GW as api-gateway participant BFF as bff-mobile - participant Q as microservice-quizz participant U as microservice-users + participant PS as PlayerStore (BFF local DB) + + App->>GW: POST /v1/mobile/games/events {events[]} + GW->>BFF: POST /v1/mobile/games/events + BFF->>U: GET /users/me/profile (resolve player identity from the token) + U-->>BFF: 200 profile + BFF->>BFF: validate GameEventsSyncSchema + BFF->>PS: saveGameEvents(playerId, events) + PS-->>BFF: synced count and stats + BFF-->>GW: 200 {synced, message, stats} + GW-->>App: 200 +``` + +Failure points: +- No token or an invalid token: 401 from the BFF. +- `microservice-users` unreachable while resolving the identity: 502 `Failed to resolve player identity`. +- Consequence: mobile results are not written to `microservice-users`, so they do not reach its leaderboard. `microservice-users` has `POST /users/me/games/events` (and the open, unmerged PR AxiomNode/microservice-users#5 proposes `POST /users/me/games/events/batch`), but `bff-mobile` on main does not call either. + +## SF-07 Content generation: batch worker and generation processes + +Generation is separate from serving. The services call `ai-engine` through the gateway (`AI_ENGINE_BASE_URL=http://api-gateway:7005/internal/ai-engine` in `platform-infra/kubernetes/base/microservice-quizz/api-deployment.yaml`). + +```mermaid +sequenceDiagram + autonumber + participant SPA as backoffice + participant GW as api-gateway + participant BFF as bff-backoffice + participant Q as microservice-quizz + participant AIGW as api-gateway /internal/ai-engine + participant AI as ai-engine-api + participant L as llama runtime + participant DB as quizz DB - App->>GW: POST /v1/games/quiz/result + SPA->>GW: POST /v1/backoffice/services/microservice-quiz/generation/worker/start {countPerIteration, categoryIds?, difficultyLevels?} GW->>BFF: forward - BFF->>Q: POST /rounds/:id/result - Q->>Q: persist score - Q-->>BFF: 200 - BFF->>U: POST /players/:id/events {gameResult} - U->>U: update PlayerStats projection - U-->>BFF: 202 - BFF-->>App: 200 + BFF->>Q: POST /games/generate/worker/start + Q-->>BFF: 200 {gameType, worker} + loop worker iterations (interval timer inside the service) + Q->>Q: runGenerationProcessBlocking for the selected categories and difficulty levels + Q->>AIGW: POST /internal/ai-engine/generate/quiz + AIGW->>AI: POST /generate/quiz + AI->>L: completion request (RAG context) + L-->>AI: model output + AI-->>AIGW: 200 generation + AIGW-->>Q: 200 generation + Q->>DB: persist GameGeneration + end ``` -Failure points: -- Q write fails → no analytics call; gateway returns 5xx. -- U analytics call fails → considered eventually consistent; logged for replay. +Other entry points on the same service: `POST /games/generate` (one item, synchronous), `POST /games/generate/process` (asynchronous, returns a `taskId`; poll `GET /games/generate/process/:taskId`) and `POST /games/generate/process/wait` (blocking). The Backoffice exposes them as `/v1/backoffice/services/:service/generation/process`, `/wait`, `/processes`, `/process/:taskId`. + +Notes: +- The k8s base manifest sets `BATCH_GENERATION_ENABLED=false` for `microservice-quizz`; the runtime worker above is controlled through the `/games/generate/worker*` routes. +- The worker is in-process state of each service. There is no queue or message broker. + +## True-false is not a game of the platform + +`ai-engine` has `POST /generate/true-false` and `POST /ingest/true-false`, but no microservice, BFF route or the mobile app uses them (the mobile `GameType` is QUIZ or WORDPASS only, per the F7 review notes; app code not re-checked here). The gateway does not proxy them either (it only proxies `generate/quiz`, `generate/word-pass`, `ingest/quiz`, `ingest/word-pass`, `catalogs`, `health` and `stats` under `/internal/ai-engine`). ## Related documents @@ -182,3 +234,4 @@ Failure points: - [Domain model](./domain-model.md) - [Target architecture](./target-architecture.md) - [Runtime routing](../operations/runtime-routing-and-service-targeting.md) +- Route inventory of the gateway and both BFFs (generated from code): `contracts-and-schemas/schemas/route-inventory/edge-routes.md` diff --git a/architecture/master-alignment.md b/architecture/master-alignment.md index 7ad1f6c..5629d85 100644 --- a/architecture/master-alignment.md +++ b/architecture/master-alignment.md @@ -1,6 +1,8 @@ # Alineación con el Máster en Desarrollo con IA -Last updated: 2026-04-23. +Last updated: 2026-11-12. + +> **Correction (2026-11-12):** earlier versions of this document claimed a partial event-driven architecture. On `origin/main` there is no message broker, no domain events and no Outbox in any service. The event schemas in `contracts-and-schemas/schemas/events/` have no producer and no consumer and are marked not implemented. The only asynchronous telemetry is the HTTP `POST /events` ingestion of the `ai-engine` stats app. References to events or Outbox below are *future work*. Este documento mapea los pilares del *Máster en Desarrollo con IA* (resumido en `.tmp/MásterDesarrolloIA/summary/`) con el estado actual de la plataforma AxiomNode. Para cada pilar se describe qué se cumple hoy, qué brechas existen y qué acciones concretas se proponen, enlazando a los artefactos donde se materializan. @@ -11,7 +13,7 @@ El objetivo es doble: (1) usar el máster como vara de medir externa para detect | Pilar del máster | Estado AxiomNode | Brecha principal | Acción propuesta | |---|---|---|---| | 2. Ingeniería de software | Cubierto: ciclo de vida, requisitos como casos de uso, principios de diseño aplicados por repo | No hay un mapa de historias de usuario formal por canal | Añadir story map por canal en `docs/architecture/use-cases.md` | -| 3. Arquitectura de software | Cubierto: C4 L1-L3, dominio, ADRs 0001-0007, monolito modular + microservicios + event-driven parcial | Falta formalizar Outbox y la matriz síncrono/asíncrono entre servicios | Documentar Outbox y comunicación inter-servicios; ADR si hay decisión nueva | +| 3. Arquitectura de software | Cubierto: C4 L1-L3, dominio, ADRs 0001-0007, monolito modular + microservicios con comunicación REST síncrona (event-driven: no implementado, trabajo futuro) | No hay broker ni eventos; Outbox y la matriz síncrono/asíncrono quedan como trabajo futuro | Documentar Outbox y comunicación inter-servicios; ADR si hay decisión nueva | | 4. Fundamentos de IA | Cubierto: split AI runtime (ADR 0004), generación + stats + cache + llama, eval harness baseline + prompts versionados | Faltan métricas de calidad sobre LLM real y documento de IA responsable | Promover eval a real-LLM gate; redactar `responsible-ai.md` | | 6. Flujo de desarrollo con IA | Parcial: Copilot en uso, prompts ad-hoc | No hay base de conocimiento ni reglas de prompting versionadas | Añadir `docs/guides/governance/ai-prompting-rules.md` | | 7. Calidad | Cubierto: vitest 90%, pytest 90%, Codecov en 8 repos, observabilidad mínima | Falta E2E de extremo a extremo y métricas DORA | Añadir Playwright E2E al menos para backoffice; medir DORA | @@ -62,12 +64,12 @@ El objetivo es doble: (1) usar el máster como vara de medir externa para detect - C4 L1, L2, L3 documentados en [c4-views.md](./c4-views.md). - Dominio modelado en [domain-model.md](./domain-model.md) con bounded contexts. - 7 ADRs cubren edge único, BFF por canal, contratos como SoT, split AI, runtime control plane, infra centralizada, tags inmutables. -- Comunicación principalmente síncrona REST. Hay eventos puntuales en `ai-engine` y `microservice-quizz`, no formalizados. +- Comunicación síncrona REST. No hay broker ni eventos de dominio (verificado en `origin/main` el 2026-11-12). El trabajo asíncrono es en proceso: tareas de generación y worker dentro de quizz/word-pass. Los esquemas `game-generation-completed/failed.v1.json` no están implementados. **Brechas:** - No hay un documento de comunicación inter-servicios que enumere qué llamadas son síncronas vs asíncronas. -- No se aplica patrón Outbox de forma sistemática para garantizar consistencia eventual. +- No se aplica patrón Outbox: no existe (no hay broker al que publicar). Trabajo futuro, solo si se introduce un broker. **Acción propuesta:** diff --git a/architecture/quality-attributes.md b/architecture/quality-attributes.md index d09eb24..1f3ffee 100644 --- a/architecture/quality-attributes.md +++ b/architecture/quality-attributes.md @@ -9,11 +9,11 @@ Each scenario uses the SEI template (Source, Stimulus, Environment, Artifact, Re ### QA-P1 Quiz round latency under nominal load - Source: Mobile player. -- Stimulus: `GET /v1/games/quiz/random` with cached generation available. +- Stimulus: `GET /v1/mobile/games/quiz/random` with stored quiz models available (the route only reads stored rows; it never calls `ai-engine`). - Environment: staging or production, normal load (<= 50 RPS per service). - Artifact: `api-gateway` -> `bff-mobile` -> `microservice-quizz`. -- Response: returns 200 with cached `GameGeneration`. -- Measure: p95 < 400 ms end-to-end; cache hit ratio > 70 % observed via stats. +- Response: returns 200 with stored `GameGeneration` models. +- Measure: p95 < 400 ms end-to-end (target; no automated measurement was found in this review). ### QA-P2 AI cold generation latency @@ -80,9 +80,9 @@ Each scenario uses the SEI template (Source, Stimulus, Environment, Artifact, Re - Source: Contracts maintainer. - Stimulus: breaking change merged to `contracts-and-schemas`. - Environment: CI of consumers. -- Artifact: SDK regeneration step. -- Response: dependent service builds fail until contracts are honored. -- Measure: 100 % of consumer pipelines re-run on SDK update. +- Artifact: SDK regeneration step. *Not implemented:* the SDK is not generated from contracts; CI only validates the contract files and builds the TypeScript library. +- Response: dependent service builds fail until contracts are honored (target; today a contract change does not affect any service build). +- Measure: 100 % of consumer pipelines re-run on SDK update (target). ### QA-M2 Service repo can be regenerated to a known good baseline @@ -120,7 +120,7 @@ Each scenario uses the SEI template (Source, Stimulus, Environment, Artifact, Re - Source: Engineering team. - Stimulus: introduce a new game type. - Environment: workspace. -- Artifact: new microservice repo + contracts entry + SDK regen. +- Artifact: new microservice repo + hand-written contracts entry + SDK update (there is no SDK regeneration). - Response: new BFF route + gateway forward; no schema changes to other services. - Measure: 0 modifications required to existing microservice DBs. diff --git a/architecture/target-architecture.md b/architecture/target-architecture.md index 797aa62..4ef5da5 100644 --- a/architecture/target-architecture.md +++ b/architecture/target-architecture.md @@ -1,6 +1,15 @@ # Current Platform Architecture -Last updated: 2026-05-03. +Last updated: 2026-11-12. + +> **Current vs target (reviewed 2026-11-12 against `origin/main`).** The diagram and the layers below describe the *current* code unless an item is explicitly marked *target* or *not implemented*. Corrections made in this review: +> +> - Quizz and word-pass call `ai-engine` **through the gateway**, not directly: `AI_ENGINE_BASE_URL=http://api-gateway:7005/internal/ai-engine` (`platform-infra/kubernetes/base/microservice-quizz/api-deployment.yaml`). The gateway forwards `/internal/ai-engine/{generate,ingest}/{quiz,word-pass}`, `catalogs`, `health` and `stats` to `ai-engine`. +> - `contracts-and-schemas` is not a build or runtime input of any service: its OpenAPI files are hand-written documentation validated by CI, and there are none for the gateway or the BFFs. +> - `shared-sdk-client` is an internal TypeScript library imported by the gateway, both BFFs and the users, quizz and word-pass services. It does not generate clients. +> - There is no message broker, event bus or Outbox. Asynchronous work is in-process (generation tasks and the runtime worker inside each game service). The event schemas in `contracts-and-schemas/schemas/events/` are *target / not implemented*. +> - `true-false` generation exists only in `ai-engine`; no service, BFF or app uses it. +> - The k3s staging host no longer exists and `platform-infra` `deploy.yaml` is manual-only; the deployment topology below describes the manifests, not a live environment. ## Scope @@ -46,18 +55,22 @@ flowchart TB BffBackoffice --> Wordpass BffBackoffice --> AISTATS Gateway --> AIAPI + Gateway --> AISTATS + Quiz -->|AI generation via /internal/ai-engine| Gateway + Wordpass -->|AI generation via /internal/ai-engine| Gateway Platform -. deploys .-> Gateway Platform -. deploys .-> BffMobile Platform -. deploys .-> BffBackoffice Platform -. deploys .-> Quiz Platform -. deploys .-> Wordpass Platform -. deploys .-> Users - Contracts -. shared contracts .-> Gateway - Contracts -. shared contracts .-> BffMobile - Contracts -. shared contracts .-> BffBackoffice - SDK -. shared client libs .-> Gateway - SDK -. shared client libs .-> BffMobile - SDK -. shared client libs .-> BffBackoffice + Contracts -. hand-written docs, CI validation only .-> SDK + SDK -. internal TypeScript library .-> Gateway + SDK -. internal TypeScript library .-> BffMobile + SDK -. internal TypeScript library .-> BffBackoffice + SDK -. internal TypeScript library .-> Users + SDK -. internal TypeScript library .-> Quiz + SDK -. internal TypeScript library .-> Wordpass Secrets -. runtime config .-> Platform Obs -. telemetry .-> Gateway Obs -. telemetry .-> BffMobile @@ -69,7 +82,7 @@ flowchart TB 1. Edge layer: `api-gateway` is the single public ingress and policy boundary. 2. Experience layer: `bff-mobile` and `bff-backoffice` expose channel-shaped contracts. 3. Domain services: `microservice-users`, `microservice-quizz`, `microservice-wordpass`, and optional `ai-engine` endpoints. -4. Data and async layer: service-owned data stores and deferred generation flows. +4. Data and async layer: service-owned data stores and deferred generation flows. Deferred generation means in-process generation tasks and a runtime worker inside the quizz and word-pass services; there is no broker, queue or event bus (event-driven integration is *target / not implemented*). 5. Platform layer: `platform-infra`, `observability-platform`, `contracts-and-schemas`, `shared-sdk-client`, and `secrets`. ## Context and boundaries @@ -92,8 +105,8 @@ flowchart TB #### Platform ownership -- `contracts-and-schemas` is the contract source of truth. -- `shared-sdk-client` is the shared client and validation distribution point. +- `contracts-and-schemas` holds the hand-written OpenAPI and JSON Schema documents for the internal services and a generated route inventory for the gateway and BFFs. It is validated in CI but nothing generates code from it, so the code remains the effective source of truth (*target*: contract-first). +- `shared-sdk-client` is an internal TypeScript library (Zod schemas, HTTP proxy helpers, game-service runtime) imported by six services. - `platform-infra` owns packaging and deployment policy. - `secrets` owns real runtime secret material and sync rules. - `observability-platform` owns shared telemetry assets and alerts. @@ -116,7 +129,7 @@ The deployable core for staging and production-oriented flows is: #### Optional AI topology -`ai-engine` is architecturally part of the platform, but it is no longer assumed to be always in-cluster for staging. +`ai-engine` is architecturally part of the platform, but it is no longer assumed to be always in-cluster for staging. Its `true-false` routes are not used by any service, BFF or app; the platform only plays quiz and word-pass. The current architecture supports two valid runtime modes: diff --git a/architecture/use-cases.md b/architecture/use-cases.md index d4ea1aa..6d64147 100644 --- a/architecture/use-cases.md +++ b/architecture/use-cases.md @@ -102,7 +102,7 @@ This document enumerates the primary use cases supported by the AxiomNode platfo - Trigger: PR to `contracts-and-schemas` or `shared-sdk-client`. - Path: `validate-contracts` / `typescript-sdk-ci` workflows. -- Post-conditions: Failing contract changes block downstream services from compiling against drift. +- Post-conditions: Failing contract changes block downstream services from compiling against drift. *Target:* today `validate-contracts` only checks that the contract files are valid, and `typescript-sdk-ci` builds the TypeScript library; neither compiles services against the contracts. ### UC-15 Recover AI services (Platform Engineer) diff --git a/guides/capabilities/ai/ai-content-generation.md b/guides/capabilities/ai/ai-content-generation.md index aa6c516..8915fc1 100644 --- a/guides/capabilities/ai/ai-content-generation.md +++ b/guides/capabilities/ai/ai-content-generation.md @@ -167,7 +167,7 @@ This capability turns internal generation requests into validated game payloads, ## Open questions - the quiz tests still assert effective language as English on model-specific generation paths even when the route defaults use `X-Game-Language=es`; that contract should be clarified explicitly at the platform level -- true-false generation and ingest routes exist in ai-engine, but the current capability inventory and main consumers focus on quiz and word-pass only +- true-false generation and ingest routes exist in ai-engine, but no microservice, BFF route or mobile game uses them (checked on `origin/main`, 2026-11-12) and the gateway does not proxy them; the platform only plays quiz and word-pass - the operational boundary between ai-engine local llama-target state and gateway/BFF ai-engine target overrides is functional but still easy to misread during incident response ## References diff --git a/guides/capabilities/platform/contract-governance.md b/guides/capabilities/platform/contract-governance.md index 037dd47..3e4fe38 100644 --- a/guides/capabilities/platform/contract-governance.md +++ b/guides/capabilities/platform/contract-governance.md @@ -32,9 +32,9 @@ This capability keeps request, response, and event semantics aligned across repo | Type | Location | Notes | |---|---|---| -| Source artifact | versioned OpenAPI specs under `contracts-and-schemas/schemas/openapi/` | HTTP contract source of truth | +| Source artifact | versioned OpenAPI specs under `contracts-and-schemas/schemas/openapi/` | hand-written HTTP documentation for the internal services (not the gateway or BFFs); checked against code on 2026-11-12, nothing generates code from it | | Source artifact | JSON Schemas under `contracts-and-schemas/schemas/json/` | payload and query semantics | -| Generated artifact | shared SDK modules under `shared-sdk-client/typescript/src/` | consumer integration surface | +| Hand-written library | shared SDK modules under `shared-sdk-client/typescript/src/` | internal TypeScript consumer integration surface (not generated from the contracts) | ### Inputs @@ -45,7 +45,7 @@ This capability keeps request, response, and event semantics aligned across repo ### Outputs - canonical specs and schemas -- generated SDK exports such as `AiEngineClient`, `createGameRoutes()`, and reusable validators +- SDK exports such as `AiEngineClient`, `createGameRoutes()`, and reusable validators (hand-written, not generated) - CI and compile feedback from consumers ### Contract sources diff --git a/guides/communication/service-communication.md b/guides/communication/service-communication.md index db27cc6..696795e 100644 --- a/guides/communication/service-communication.md +++ b/guides/communication/service-communication.md @@ -68,7 +68,7 @@ Last updated: 2026-04-05. - Batch generation endpoints return `taskId` values. - Clients poll process-status endpoints for progress/completion. -- Event contracts are versioned in `contracts-and-schemas/schemas/events/`. +- Event contracts are proposed in `contracts-and-schemas/schemas/events/` but are **not implemented** (no broker, no producer, no consumer on `origin/main`, 2026-11-12). Asynchronous behaviour today is the in-process generation tasks above. ## Effective AI request path diff --git a/guides/foundations/tfm-practice-matrix.md b/guides/foundations/tfm-practice-matrix.md index 0964fce..7ff1bd0 100644 --- a/guides/foundations/tfm-practice-matrix.md +++ b/guides/foundations/tfm-practice-matrix.md @@ -66,7 +66,7 @@ In practice: | Master block | Current evidence | Main gap | Practice exercise | Repositories | Validation evidence | TFM value | |---|---|---|---|---|---|---| | 2. Software engineering | Use cases, domain model, repository boundaries, issue/PR templates | User stories and acceptance criteria are not grouped by channel | Add a channel story map for mobile and backoffice, linked to existing use cases and critical workflows | `docs` | Updated use-case/story-map document; trace to smoke matrix rows | Shows requirements analysis, decomposition, and verification discipline. | -| 3. Software architecture | C4, ADRs, BFF-per-channel, single edge, runtime control plane | Event consistency is documented but not formalized as a design exercise | Model one async flow with idempotency and possible Outbox adoption, preferably gameplay event sync or batch generation | `docs`, `microservice-users`, `microservice-quizz`, `microservice-wordpass`, `contracts-and-schemas` | ADR or architecture note; event schema check; one executable smoke or integration test | Demonstrates distributed architecture trade-offs instead of only synchronous REST. | +| 3. Software architecture | C4, ADRs, BFF-per-channel, single edge, runtime control plane | There is no event or broker infrastructure today (the event schemas are not implemented), so async consistency is a design exercise rather than a documented implementation | Model one async flow with idempotency and possible Outbox adoption, preferably gameplay event sync or batch generation | `docs`, `microservice-users`, `microservice-quizz`, `microservice-wordpass`, `contracts-and-schemas` | ADR or architecture note; event schema check; one executable smoke or integration test | Demonstrates distributed architecture trade-offs instead of only synchronous REST. | | 4. AI fundamentals | `ai-engine`, RAG pipeline, prompt versions, generation schemas | AI generation is not proven useful or reliable enough for direct product trust | Build a real-LLM evaluation dataset and rubric for quiz and word-pass candidate generation | `ai-engine`, `docs`, optional `observability-platform` | JSON/Markdown eval report with pass rate by criterion, failures, prompt version, model target, and latency | Converts AI from a weak feature claim into a measurable engineering problem. | | 4. AI architecture | Split AI runtime, llama target store, runtime routing controls | The plugin boundary is still informal and mostly means "external llama endpoint" | Formalize thin-plugin mode and define the future hybrid plugin contract | `ai-engine`, `docs`, `platform-infra`, optional `contracts-and-schemas` | Plugin architecture doc; health/capability probe; routing smoke through selected plugin target | Makes the plugin idea concrete without prematurely moving every AI component out of the VPS. | | 4. AI responsible | Prompting rules and threat model cover some abuse cases | No dedicated responsible-AI policy | Create a Responsible AI policy covering privacy, prompt logging, sensitive content, human review, transparency, and limits | `docs`, `ai-engine`, BFF repos if behavior changes | Policy doc; tests or log checks proving prompt minimization; reviewed examples | Directly applies ethics, privacy, accountability, and safety from the master. |