Skip to content

api-gateway Agent Tasks

Agent workflow: follow README.md for Audit -> Investigate -> Code -> Test -> Fix; keep this pack's writable scope and verification commands authoritative.

Dispatch type: per-service

Dispatch ID: SVC-001

Owns: services/api-gateway, assigned non-default deploy/gateway/*.json route rehearsal examples, and gateway route tests.

Must read:

  • docs/architecture/api-contract-strategy.md
  • docs/architecture/service-responsibility-matrix.md
  • docs/architecture/legacy-api-map.md

Legacy source evidence:

  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/main.ts
  • /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/api/src/modules/**
  • Legacy frontend API callers under /Users/velikho/Desktop/WORKING/HOCTAPAZ/node-platform/apps/web.

Writable files:

  • services/api-gateway/**
  • deploy/gateway/*.json only for assigned route rehearsals
  • gateway-specific tests and docs under docs/api/api-gateway.md

Orchestrator-owned files:

  • default route-table cutover decisions, shared Compose/Helm/K8s manifests, and service-owner API contracts unless explicitly delegated.

Initial tasks:

  • Audit all non-default native route examples and confirm frontend-only-via-gateway invariant.
  • Add route-table coverage when any service task introduces a native cutover candidate.
  • Keep JWT/JWKS verification compatible with iam-service claims. Gateway auth guards must accept IAM RS256 tokens through IAM_JWKS_URL while preserving the HS256 AUTH_JWT_SECRET fallback for local route rehearsals.
  • For learning public workflow cutovers, require service APIs first, then add route adapters/live smokes/browser smokes for question/course/exam/attempt.
  • Done locally: attempt start route rehearsal uses the gateway exam_start_adapter state for POST /api/exams/:examId/start. The adapter calls exam-service runtime access before attempt-service, attaches its shared internal Gateway authentication to both hops, and is covered by focused gateway tests plus make test-attempt-routes.
  • Done locally: DOCX_PHYSICS_GATEWAY_ATTEMPT_LOCAL_POSTGRES_CONFIRM=local-postgres make test-docx-physics-attempt-local-postgres runs a complete non-default candidate against fresh isolated IAM, Document, Classroom, Import, Question Bank, Exam, and Attempt databases. It compares the served dynamic route table exactly, registers teacher/student identities in one organization, imports the 28-question Physics fixture, publishes an online exam, then starts, saves, submits, and reads a GRADED attempt. The object store is in-memory and the proof neither uses a browser or Mistral credential nor changes the default route table.
  • Done locally: organization membership write rehearsal uses the gateway organization_membership_adapter state in non-default route tables. The adapter converts legacy userId add-member bodies to IAM accountId, routes member add/remove to iam-service, and keeps PATCH member updates plus other organization writes legacy-proxied. make test-organization-membership-write-live is available for the explicit add/remove live smoke with an IAM admin bearer token and a disposable member account id.
  • Done locally: auth-native read-only live smoke is available through make test-auth-routes-live. The self-test runs under make test-auth-routes; confirmed live mode requires AUTH_ROUTE_LIVE_CONFIRM=auth-native and checks IAM Google config, unauthenticated /api/auth/me, and a legacy sibling route without promoting the default route table. Latest local live proof on 2026-07-09 is under output/qa/auth-route-live-20260709-115133/, with Google config routed through auth-google-config/native_read, /api/auth/me routed through auth-me/native_read, and the sibling profile route on auth/legacy_proxy.
  • Done locally: auth-native browser smoke is available through make test-auth-routes-browser. The self-test also runs under make test-auth-routes; confirmed browser mode requires AUTH_ROUTE_BROWSER_CONFIRM=auth-native, opens /auth/login, clicks the Google Auth entry, and verifies browser-observed IAM route headers without promoting the default route table. Latest local browser proof on 2026-07-09 is under output/playwright/auth-route-browser-smoke-20260709-115940/, with gateway-handled CORS preflight, Google config routed through auth-google-config/native_read, /api/auth/me routed through auth-me/native_read, and the sibling profile route on auth/legacy_proxy.
  • Done locally: IAM/Profile rollback rehearsal is available through make test-iam-profile-route-rollback. It validates the auth/profile non-default route examples against the default rollback route table, and optional live mode requires IAM_PROFILE_ROUTE_ROLLBACK_CONFIRM=default-legacy.
  • Done locally: profile update live gateway smoke is available through make test-profile-routes-live. Confirmed live mode uses the non-default deploy/gateway/routes.profile-native-localhost-example.json route table, verifies PATCH /api/auth/me/profile through profile-base-update/native_write, verifies PATCH /api/auth/me/teacher-profile through profile-teacher-update/native_write, and keeps the sibling GET /api/auth/me route on auth/legacy_proxy. Latest local proof on 2026-07-09 is under output/qa/profile-route-live-20260709-121055/.
  • Done locally: profile update browser smoke is available through make test-profile-routes-browser. Confirmed browser mode opens the real /teacher/profile page, sends browser-originated profile update requests through api-gateway, verifies profile-base-update/native_write and profile-teacher-update/native_write, and keeps the sibling GET /api/auth/me route on auth/legacy_proxy. Latest local proof on 2026-07-09 is under output/playwright/profile-route-browser-smoke-20260709-121825/.
  • Done locally: gateway route-operation audit projection is available when AUDIT_SERVICE_URL/AUDIT_SERVICE_BASE_URL is set. The gateway posts one best-effort, redacted client-facing route event per matched /api/* route to audit-service POST /v1/audit-events with sourceService=api-gateway, sourceEventId=gateway:route:<requestId>, category=OPERATIONS, action=gateway.route.request, entity=GatewayRoute, retentionPolicy=gateway-route-operations, and metadataSchemaVersion=1. Disabled or failing audit projection never blocks the gateway response; no default route table was promoted for this slice.
  • Done locally: teacher Word print rehearsal is isolated in routes.teacher-print-export-bff-native-*.json. It maps only print-template create/list/update and durable DOCX export create/list/download to BFF, requires ADMIN/TEACHER plus organization scope, and preserves the broad /api/teacher legacy route in routes.json. The named static proof is make test-teacher-print-export-bff-routes; the hermetic Gateway test proves path rewrite, role/org denial, and replacement of forged actor headers.
  • Done locally: teacher AI preview rehearsal is isolated in routes.teacher-ai-preview-native-*.json. It maps only the exact generation and editor-solution preview POST routes to ai-classifier-service, plus reviewed generation-draft and canonical-solution writes to question-bank-service. Every route requires ADMIN/TEACHER plus organization scope, and the default broad /api/questions route remains legacy-proxied. The named static proof is make test-teacher-ai-preview-routes; the hermetic Gateway test proves path rewrite, forged-header replacement, student denial, and missing-organization denial.
  • Done locally: teacher exam blueprint rehearsal is isolated in routes.teacher-exam-blueprint-bff-native-*.json. It maps only matrix list/create/detail/update/delete through BFF, requires ADMIN/TEACHER plus organization scope, and leaves routes.json unchanged. The named proof is make test-teacher-exam-blueprint-bff-routes.

Acceptance:

  • Default route table remains safe for unproven routes.
  • Native examples route only exact approved paths.
  • Auth/role/org guards are tested for every protected native route.
  • RS256/JWKS and HS256 fallback verification stay covered before any protected default route promotion.
  • Audit projection metadata stays redacted: no authorization headers, cookies, raw request bodies, or query values.
  • Attempt start, auth/profile, and organization membership writes are not promoted by default until route/browser proof and rollback evidence exist.

Verification:

  • GOTOOLCHAIN=go1.25.11 go test ./services/api-gateway/...
  • make test-auth-routes test-auth-routes-live test-auth-routes-browser test-iam-profile-route-rollback test-organization-routes test-question-read-routes test-question-write-routes test-attempt-routes test-teacher-print-export-bff-routes test-teacher-exam-blueprint-bff-routes test-teacher-ai-preview-routes
  • GOTOOLCHAIN=go1.25.11 go test ./services/api-gateway/internal/gateway -run TeacherPrintExportBFF -count=1
  • GOTOOLCHAIN=go1.25.11 go test ./services/api-gateway/internal/gateway -run TeacherAIPreview -count=1
  • DOCX_PHYSICS_GATEWAY_ATTEMPT_LOCAL_POSTGRES_CONFIRM=local-postgres HOCTAPAZ_DOCX_CORPUS_DIR=/Users/velikho/Desktop/test-hoctapaz make test-docx-physics-attempt-local-postgres
  • AUTH_ROUTE_LIVE_CONFIRM=auth-native AUTH_ROUTE_LIVE_ARTIFACT_DIR=output/qa/auth-route-live-20260709-115133 GATEWAY_BASE_URL=http://localhost:18086 make test-auth-routes-live
  • AUTH_ROUTE_BROWSER_CONFIRM=auth-native AUTH_ROUTE_BROWSER_ARTIFACT_DIR=output/playwright/auth-route-browser-smoke-20260709-115940 AUTH_ROUTE_BROWSER_HEADLESS=1 WEB_BASE_URL=http://localhost:5205 GATEWAY_BASE_URL=http://localhost:18087 make test-auth-routes-browser
  • PROFILE_ROUTE_LIVE_CONFIRM=profile-native PROFILE_ROUTE_LIVE_SEED_CONFIRM=seed-profile PROFILE_ROUTE_LIVE_ARTIFACT_DIR=output/qa/profile-route-live-20260709-121055 GATEWAY_BASE_URL=http://localhost:18088 PROFILE_SERVICE_BASE_URL=http://localhost:8082 AUTH_JWT_SECRET=local-hoctapaz-development-secret-change-before-deploy make test-profile-routes-live
  • PROFILE_ROUTE_BROWSER_CONFIRM=profile-native PROFILE_ROUTE_BROWSER_SEED_CONFIRM=seed-profile PROFILE_ROUTE_BROWSER_ARTIFACT_DIR=output/playwright/profile-route-browser-smoke-20260709-121825 PROFILE_ROUTE_BROWSER_HEADLESS=1 WEB_BASE_URL=http://localhost:5212 GATEWAY_BASE_URL=http://localhost:18089 PROFILE_SERVICE_BASE_URL=http://localhost:8082 AUTH_JWT_SECRET=local-hoctapaz-development-secret-change-before-deploy make test-profile-routes-browser
  • JSON parse for touched deploy/gateway/*.json.

Go-platform documentation is generated from repository Markdown.