Implementation Documentation v1
AIEE.DEV implementation direction — multi-tenant modular SaaS, Laravel + PostgreSQL + React, base platform, core/optional modules, and delivery phasing.
IMPL-SOQ-TMS-v1 · Platform Topology Lock
| Field | Value |
|---|---|
| Doc-ID | IMPL-SOQ-TMS-v1 |
| Stack freeze | Laravel 11 · PostgreSQL 15 · React/Next.js 16 · Redis 7 |
| Pattern | Modular monolith → selective extraction |
| Authority | HK (CSO) · Andy Koh (CTO) |
1 · Architectural decision record summary
| ADR | Decision | Rationale |
|---|---|---|
| ADR-001 | Modular monolith first | Time-to-SWDA-conformance; avoid distributed tracing tax |
| ADR-002 | SwdaHub isolation | 40+ API surface · credential blast radius · independent deploy candidate |
| ADR-003 | Outbox for external IO | Request thread MUST NOT block on gov HTTP |
| ADR-004 | TMS SoR for orders | Xero = GL only; prevent dual-write |
| ADR-005 | tenant_id column day-1 | Multi-tenant-ready without self-service admin MVP |
2 · Module registry
| Module | Aggregate roots | Exposes |
|---|---|---|
Identity | User, Role, Session | Auth API |
Catalogue | Programme, Course, CourseRun | Catalogue API |
Admissions | Application, Offer | Admissions API |
Enrolment | Enrolment, ClassAssignment | Enrolment API |
Attendance | Session, AttendanceFact | Attendance API |
Assessment | Assessment, Result | Assessment API |
Crm | Lead, Opportunity | CRM API |
FinanceOrders | Order, OrderLine, Payment | Finance API |
Reporting | Read models | Report API |
Platform | AuditLog, Notification, Config | Platform API |
Integration modules (not domain):
| Module | Direction | Protocol |
|---|---|---|
SwdaHub | Outbound/inbound | REST + webhook |
Xero | Outbound | OAuth2 REST |
3 · Inter-module communication rules
``` ALLOWED: ModuleA --DomainEvent--> Outbox --> ModuleB listener FORBIDDEN: ModuleA --direct Eloquent--> ModuleB model FORBIDDEN: ModuleA --HTTP--> SwdaHub (use Outbox only) ```
Application services orchestrate cross-aggregate workflows within same module or via events across modules.
4 · Directory topology
Canonical tree: CRD §04 /docs/proposed-directory-structure
CI enforcement: dependency-cruiser + eslint-plugin-boundaries on merge to main.
5 · Data layer
| Concern | Implementation |
|---|---|
| Primary DB | RDS PostgreSQL Multi-AZ |
| Migrations | Laravel forward-only |
| Read models | student_360_mv, pipeline_mv refreshed by queue |
| Files | S3 SSE-KMS; pre-signed URLs TTL 900s |
| Search | Postgres FTS MVP; OpenSearch candidate P2 |
Outbox table (normative)
```sql CREATE TABLE outbox ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), aggregate_type VARCHAR(64) NOT NULL, aggregate_id UUID NOT NULL, event_type VARCHAR(128) NOT NULL, payload JSONB NOT NULL, idempotency_key VARCHAR(255) UNIQUE NOT NULL, published_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX outbox_unpublished_idx ON outbox (created_at) WHERE published_at IS NULL; ```
6 · API surface
- Base:
/api/v1 - OpenAPI 3.1 spec generated from Laravel attributes/controllers
- Client codegen:
packages/api-clientvia CI on spec change - Auth: Bearer JWT staff · Session cookie portals · Singpass OIDC public WSQ
Rate limits: public catalogue 100 rpm/IP; authenticated 1000 rpm/user; SWDA workers token-bucket per subscription quota.
7 · Frontend architecture
| App | Rendering | Auth |
|---|---|---|
public-web | RSC + ISR catalogue | Anonymous + applicant session |
admin-workspace | CSR + RSC hybrid | Staff SSO + MFA |
student-portal | PWA-capable CSR | Student session |
trainer-portal | Mobile-first CSR | Trainer session |
Shared: packages/ui design tokens · packages/api-client · TanStack Query cache policy staleTime=30s ops views.
8 · Async / workers
| Queue | Consumer | Concurrency |
|---|---|---|
default | notifications, emails | 10 |
swda | SwdaHub adapters | 5 (rate limited) |
xero | invoice/payment sync | 3 |
reports | MV refresh | 2 |
Horizon monitoring mandatory. Failed jobs → DLQ table failed_jobs + Slack P1 after 3 retries.
9 · Security controls
| Control | Implementation |
|---|---|
| Secrets | AWS Secrets Manager |
| SWDA creds | Never in FE env vars |
| RBAC | Middleware + policy classes |
| Row-level | tenant_id + scope filters |
| Audit | Append-only audit_log |
| Encryption | TLS 1.3 transit · RDS at-rest AES |
10 · Deployment topology (MVP)
``` Route53 → CloudFront → ALB → ECS (api, workers) → RDS + ElastiCache ↘ S3 ```
Region: ap-southeast-1. Blue/green via ECS task definition swap. DB migrations run as pre-deploy hook job.
11 · Phase binding
| Phase | Modules live | Exit test |
|---|---|---|
| P0 | Docs + ADR | Discovery DQ-* closed |
| P1 | Catalogue, Admissions, Enrolment, Attendance (partial) | k6 registration path |
| P2 | SwdaHub | Parallel-run checklist |
| P3 | FinanceOrders, Xero | Reconciliation zero diff |
| P4 | Crm | Funnel E2E test |
| P5 | Assessment advanced, Diploma | UAT sign-off |
12 · Change control
- ADR required for stack or boundary change
- PRD FR change → version bump + regression suite
- SWDA field map change → adapter version + golden file update
13 · Related artifacts
- PRD:
SOQ_TMS_PRD_v1.1_clean.md - Attachment A:
SOQ_Training_Management_System_Proposal.pdf - CRD §04 Directory · §17 Architecture · §22 Backend
Implementation authority: Andy Koh (CTO)