Appearance
Target Go Microservices Architecture
Phase: Architecture target with staged implementation Status: active; bounded native foundations, task packs, and non-default route rehearsals exist, while default routes remain proof-gated. Rule: this document is binding for Go foundation and cutover work; legacy source remains read-only.
Objective
Build a new Go backend under go-platform/ using Parallel Rewrite plus Strangler Fig. The current NestJS backend stays live while the Go API Gateway migrates one route group at a time from legacy proxy mode to native Go service mode.
The first target is compatibility, not redesign. Public /api/... routes, token shape, Vietnamese feature labels, import review behavior, SSE events, and exam/attempt snapshot semantics must remain stable until an explicit frontend migration phase.
Runtime Topology
| Component | Role | External Surface | Internal Surface |
|---|---|---|---|
api-gateway | Public compatibility gateway and auth context propagation | /api/*, /api/health/*, /metrics | HTTP to Go services, HTTP proxy to legacy API |
bff-service | Optional web/admin aggregation layer for screen-shaped responses | Frontend may call only api-gateway or gateway-approved BFF routes; no direct owner-service hostnames | HTTP to owner services |
iam-service | Account identity, credentials, JWT/JWKS, sessions, roles, permissions, access-control memberships | Gateway only | HTTP/gRPC-style JSON, events |
profile-service | Educational user profiles, student/teacher/parent/staff metadata, public profile views | Gateway only | HTTP, events |
organization-service (school-service current) | Organizations, schools/centers/campuses, units, tenant metadata, tenant validation, and IAM-synchronized membership read models | Gateway only | HTTP, events |
classroom-service | Classrooms, members, teacher assignments, class activity/read models | Gateway only | HTTP, events |
course-service | Courses, sections, lessons, enrollments, progress | Gateway only | HTTP, events |
file-service (document-service current) | Files/media assets, S3/MinIO object metadata, teaching documents | Gateway only | HTTP, object storage |
import-service (docx-import-service current) | DOCX/PDF/OCR import jobs, parsed previews, review drafts, approval orchestration | Gateway only, SSE through gateway | HTTP, worker, events |
formula-docx-service (go-formula-docx runtime behind docx-import-service) | DOCX/formula/table parsing and parser metrics | Internal only | HTTP/runtime worker |
ai-service (ai-classifier-service current) | AI classify/generate/explain/grade foundations, provider settings, usage events | Gateway only, SSE through gateway | HTTP, worker, events |
question-service (question-bank-service current) | Questions, answers, solutions, versions, folders, groups, tags, question types/taxonomy refs | Gateway only | HTTP, events |
exam-service | Exam authoring, folders, blueprints, templates, publish snapshots, assignments | Gateway only | HTTP, events |
attempt-service | Attempt creation, answer save, submit, grading, attempt events/results | Gateway only | HTTP, events |
notification-service | Notifications, preferences, event fanout | Gateway only | HTTP, events |
analytics-service | Read models for progress/results/mastery/dashboard | Gateway only | HTTP, event consumers |
billing-service | Plans, prices, subscriptions, invoices, commercial entitlements | Gateway only | HTTP, events |
wallet-service | AZ Credits, wallet balances, immutable credit ledger, grants/debits/refunds | Gateway only | HTTP, events |
usage-service (entitlement-service alias) | Quota periods, usage counters, feature gates, entitlement checks | Gateway only | HTTP, events |
payment-service | Payment orders, provider transactions, webhooks, reconciliation | Gateway only | HTTP, events |
search-service | Search indexes and sync checkpoints for copied/indexed data | Gateway only | HTTP, event consumers |
audit-service | Append-only compliance/security event history, retention metadata, and producer replay targets | Gateway only | HTTP, event consumers |
admin-service | Feature maintenance, admin dashboard/read models, operational controls | Gateway only | HTTP, events |
Wallet/AZ Credit public routes, subscription, billing, search, and standalone audit remain legacy-proxied until the corresponding Go service task pack is implemented and gateway route cutover evidence exists. payment-service has a native foundation for payment orders and webhook idempotency, and wallet-service has a native foundation for immutable AZ Credit ledger idempotency. billing-service has a native foundation for plan catalog, subscription, invoice, and entitlement idempotency. usage-service has a native foundation for entitlement materialization, quota counters, limit overrides, and idempotent check/consume/reset decisions, but the gateway must still keep /api/wallet, package/subscription, AI/import quota callers, and payment/webhook routes proxied unless a later task explicitly promotes a route group. search-service has a native foundation for rebuildable content indexes and sync checkpoints, but public search/catalog routes stay legacy-proxied until owner-service indexing and gateway route parity are documented. audit-service has a native append-only compliance/security event foundation, but public admin audit remains controlled by the existing admin-service/gateway route rehearsal until compatibility and backfill evidence are explicit. bff-service has a native no-primary-DB screen aggregation foundation for admin/teacher dashboard and operations shells plus frontend route metadata, but browser clients still reach it only through API Gateway route promotion. The current Go implementation also intentionally splits attempt-service from the broader exam domain and analytics-service from admin/operational dashboards so attempt runtime state and analytical projections have their own databases, task packs, and verification flows.
Platform Choices
| Concern | Choice | Rationale |
|---|---|---|
| Language | Go | Target rewrite language. |
| HTTP router | chi | Lightweight, explicit middleware chain, easy gateway adapters. |
| DB driver | pgx | Native Postgres support and good pooling. |
| SQL generation | sqlc | Compile-time checked SQL while keeping query ownership explicit. |
| Migrations | service-local SQL plus tools/migrator schema runner | Current Compose/K8s/Helm bootstrap runs schema-up --service=<service> against each service-owned database and records applied files in schema_migrations. |
| Cache/queue | Redis initially | Legacy already depends on Redis/BullMQ; easier strangler compatibility. |
| Event bus | NATS or Redis Streams | NATS preferred for new domains; Redis Streams acceptable for early local parity. |
| Object storage | S3-compatible MinIO | Preserve existing storage deployment and object keys. |
| Logging | slog or zap | Structured JSON logs with request/correlation IDs. |
| Metrics | Prometheus | Preserve /metrics operational model. |
| Tracing | OpenTelemetry | Required for gateway-to-service and worker traces. |
| API docs | OpenAPI | Legacy contract snapshot plus Go service contracts. |
| Local runtime | Docker Compose first, kind later | Compose is enough for initial service skeleton and route parity. |
Request Flow
- Frontend continues calling
/api/.... api-gatewayassigns or forwardsX-Request-IdandX-Correlation-Id.- Gateway validates access token compatibility where needed, then creates an internal auth context.
- Gateway chooses route target:
- migrated route -> Go service
- unmigrated route -> legacy Nest API
- Gateway normalizes response envelope and error shape when the native service does not yet match legacy shape.
- Gateway streams SSE for import/classification/attempt event routes without buffering full responses.
Service Communication Rules
- Services never read each other's databases.
- Synchronous calls are allowed only for user-facing request completion.
- Cross-domain side effects use events and idempotent consumers.
- No distributed transactions in Phase 2.
- IAM owns permission-bearing organization membership writes. The current
school-service/organization-servicemembership rows are synchronized read models for tenant validation and compatibility. - For exam attempts, snapshot data crosses boundaries by value, not by live foreign-key dependency.
- Gateway can call multiple services only when preserving a legacy route requires aggregation.
Data Ownership
Each service owns its own Postgres database. During migration, services may have read-only adapters against the legacy database for backfill and parity verification, but runtime writes must go to exactly one owning service database unless the route is still legacy-proxied.
Observability Baseline
Every binary must expose:
/healthz/readyz/metrics- structured JSON logs with
request_id,correlation_id,service,route,status,duration_ms - OpenTelemetry trace propagation using W3C trace context
The gateway additionally keeps legacy-compatible:
/api/health/live/api/health/ready/api/metricsif legacy clients depend on it
Security Baseline
- JWT secrets and provider credentials are environment-only.
- No production default secrets.
- Gateway enforces public route allowlist.
- Service-to-service calls include internal identity.
- Tenant context is explicit:
organization_idis part of request context, not an implicit global. - Admin routes require both authenticated role and explicit admin policy check.
First Native Domains
Recommended first native implementation order:
api-gatewayproxy-only mode with health, metrics, tracing.iam-service,profile-service, andorganization-serviceidentity/profile/tenant foundations.file-servicestorage metadata read path and presigned upload compatibility.import-servicejob shell and event model, initially wrapping existing Go Formula DOCX behavior.question-servicequestion types and read-only question list parity.exam-serviceexam read parity, then draft authoring.attempt-serviceanswer save/submit only after snapshot contract is proven.billing-service,wallet-service,usage-service, andpayment-servicebefore any AZ Credits/subscription route cutover.notification-service,search-service,audit-service,admin-service, andanalytics-servicefor operations, discovery, compliance, and dashboard read models once owner-service events/backfills are explicit.
Reasoning: DOCX import and question-bank are high-value, but storage/media and gateway observability are prerequisites for reliable import migration.