AquaX API Architecture

Owner: Backend & Architecture
Reviewers: Web, Mobile, QA, Security, DevOps
Status: Draft - Current-Code Baseline
Version: 0.1
Last Updated: 2026-09-17
Review Cycle: Per API runtime, module boundary, auth, integration or deployment change

1. Purpose And Scope

This document describes the current AquaX API architecture as implemented in the repository. It focuses on runtime structure, module boundaries, request flow, authentication, authorization, validation, response conventions, data access, client integration, IoT integration and operational risks.

This document is different from docs/08_API Specification.md:

  • 08_API Specification.md lists API contracts and endpoint inventory.
  • API_Architecture.md explains how the API is designed, bootstrapped, secured, layered and integrated.

Sources reviewed:

  • backend/main.ts
  • backend/app.module.ts
  • backend/common/**
  • backend/modules/**
  • web/src/core/config/axios.config.ts
  • web/src/core/constants/api-url.ts
  • mobile/src/core/config/api-client.ts
  • mobile/src/core/constants/apiURL.constants.ts
  • docs/08_API Specification.md
  • docs/current/architecture/backend-architecture.md

2. High-Level API Context

AquaX backend is a NestJS REST API. It is the server-side source of truth for:

  • authentication and session management;
  • user, role, farm and pond scope;
  • farm, pond and crop operations;
  • water quality, sensors, thresholds and telemetry;
  • devices, device commands and auto-rules;
  • alerts, tickets, notifications and activity logs;
  • feeding records, farming logs and reports;
  • handbook and locations;
  • dashboard and settings.

Current global API prefix:

/api

Runtime Swagger documentation:

/api/docs

Default local port:

3001

3. Runtime Bootstrap

backend/main.ts creates the Nest application and configures API-wide concerns.

Concern Current implementation
Framework NestJS on Express adapter
Global prefix app.setGlobalPrefix("api")
Validation Global ValidationPipe with whitelist, forbidNonWhitelisted, transform
CORS Configured from CORS_ORIGINS, with localhost defaults
Credentials CORS credentials enabled
Allowed methods GET, POST, PUT, PATCH, DELETE
Allowed headers Content-Type, Authorization, x-client-type, x-refresh-token
Cookie parsing Lightweight parser for req.cookies, used by refresh token flow
Swagger SwaggerModule.setup("api/docs", ...)
Request logging Successful /api requests logged except Swagger assets
Port PORT env or 3001

Runtime flow:

HTTP client
  -> CORS and cookie parsing
  -> /api global prefix
  -> validation pipe
  -> throttler guard
  -> controller
  -> use case/service
  -> repository/Prisma/GCS/cache/email/MQTT
  -> response DTO wrapper

4. Application Module Composition

backend/app.module.ts wires global infrastructure and feature modules.

Global infrastructure:

Item Current code
Config ConfigModule.forRoot({ isGlobal: true, envFilePath: ".env" })
Rate limit ThrottlerModule global default 100 requests per minute per IP
Scheduling ScheduleModule.forRoot()
Common services CommonModule
Global guard ThrottlerGuard
Global filter PrismaExceptionFilter

Imported feature modules:

Module Responsibility
AuthModule Login, logout, refresh, password reset, profile, sessions
UsersModule User CRUD, scope assignment, audit logs, technician assignment
FarmsModule Farm CRUD, owner/viewer/technician views, farm dashboard
PondsModule Pond CRUD, assignments, water/device/feeding/log/warning/report/dashboard tabs
CropsModule Crop lifecycle, species, size ranges
SensorsModule Sensor CRUD, readings and chart data
ParameterThresholdsModule Pond/environment threshold configuration
HealthModule Health and status routes
AlertsModule Alert lifecycle and read state
DevicesModule Device CRUD, commands, auto-rules
FarmingLogsModule Water, mineral, siphon, productivity and attachments
FeedingModule Feed types, feeding records, suggestion, PCR/FCR
TicketsModule Ticket lifecycle, attachment and comment flow
NotificationsModule Notifications, device tokens and notification config
HandbookModule Articles, versions, bookmarks and approval workflow
ReportsModule Operational reports and Excel export jobs
LocationsModule Provinces and wards
IotIngestModule IoT telemetry, command ACK and device registration controls
SettingsModule Incident response settings
ActivityLogsModule Activity listing and export
TodoTasksModule Mobile/user task list
DashboardModule Owner/viewer dashboard APIs

5. Common Infrastructure Layer

CommonModule is marked @Global() and exports shared providers.

Provider Token/class Behavior
Database PrismaService Prisma Client access to PostgreSQL/TimescaleDB schema
File storage GcsService Google Cloud Storage integration for uploads/attachments/reports
Cache CACHE_SERVICE_TOKEN Uses Redis when REDIS_HOST exists; otherwise falls back to in-memory cache
Email EMAIL_SERVICE_TOKEN Uses Gmail SMTP when EMAIL_PROVIDER=gmail; otherwise console email

Architectural rule:

  • Feature modules should depend on the exported CommonModule providers instead of creating direct infrastructure clients ad hoc.
  • New email providers, cache providers or storage providers should be added through CommonModule/provider tokens.

6. Layering Pattern

The codebase uses a pragmatic NestJS module architecture. Not every module has identical internal folders, but the dominant pattern is:

controller
  -> use-case/service
  -> repository
  -> PrismaService / external provider

Common module folders:

backend/modules/<module>/
  dto/
  entities/
  repositories/
  services/
  use-cases/
  <module>.controller.ts
  <module>.module.ts

Implementation note:

  • Some mature modules use repositories and use cases.
  • Some modules still use direct service methods.
  • New work should follow the local pattern inside the module being changed instead of forcing a repo-wide refactor.

7. API Surface Map

All paths below are mounted under /api.

Area Base route(s) Architecture role
Health /health, /status.json Runtime health checks
Auth /auth Identity, session and password lifecycle
Users /users User management, scope, KTV assignment
Farms /farms Farm management and role-specific farm views
Ponds /ponds Pond management, assignment and pond operational tabs
Crops /crops Crop lifecycle and catalog data
Sensors /sensors Sensor metadata and sensor readings
Parameter thresholds /parameter-thresholds Environment threshold configuration
Devices /devices Device CRUD, command logs and auto-rules
IoT ingest /iot/v1 Device telemetry, command ACK, registration and control
Alerts /alerts Alert workflow
Tickets /tickets Issue/ticket workflow
Notifications /notifications, /notifications/config Notification inbox, tokens and config
Farming logs /farming-logs Manual water, mineral, siphon, productivity and attachment logs
Feeding /feeding-records Feed types, feeding records and calculated metrics
Reports /reports Report views and Excel jobs
Handbook /handbook Knowledge base and article approval lifecycle
Locations /locations Provinces and wards
Settings /settings Operational settings
Activity logs /activity-logs Activity audit view/export
Todo tasks /todo-tasks Task list APIs
Dashboard /dashboard Owner/viewer dashboard aggregation

For endpoint-level detail, use docs/08_API Specification.md or runtime Swagger at /api/docs.

8. Authentication Architecture

8.1 Access Token Flow

Protected API routes use bearer access tokens:

Authorization: Bearer <accessToken>

JwtAuthGuard:

  1. Extracts the bearer token.
  2. Verifies token signature and expiry through JwtTokenService.
  3. Checks account active state from token payload.
  4. Validates session state through SessionService.
  5. Updates session activity.
  6. Attaches request.user.

Attached user shape:

id
email
roles
farmIds
pondIds
sessionId

8.2 Refresh Token Flow

Web:

  • Login sets refresh token in an httpOnly cookie named refreshToken.
  • /auth/refresh reads the cookie.

Mobile:

  • Mobile sends x-client-type: mobile.
  • Login/refresh responses can include refreshToken in JSON.
  • Refresh can send token in body or x-refresh-token header.

8.3 Session Model

Access token validation is not purely stateless. JwtAuthGuard validates the session with SessionService, so server-side session revocation and idle/absolute timeout policies can affect subsequent API calls.

9. Authorization And Scope Model

Current authorization layers:

Layer Implementation Status
JWT authentication JwtAuthGuard CONFIRMED
Role metadata @Roles(...) + RolesGuard PARTIAL usage
Admin-only checks AdminGuard in users module TEMPORARY BYPASS present
Farm/pond scope farmIds, pondIds, services/use cases PARTIAL, many temporary bypasses
IoT ingest token IotIngestTokenGuard CONFIRMED

Known risk:

  • Multiple services/use cases contain TEMPORARY BYPASS comments for role, farm, pond and historical-record checks.
  • AdminGuard currently returns true even when the user is not ADMIN because the ForbiddenException is commented out.
  • This must be treated as production-readiness risk, not as final permission behavior.

Architecture rule:

  • Any new protected business endpoint should explicitly document its auth guard, role requirement and farm/pond scope behavior.
  • Temporary bypasses must be tracked before production hardening.

10. IoT API Architecture

IoT-facing APIs are under:

/api/iot/v1

Current route groups:

  • telemetry ingest;
  • command acknowledgement;
  • device registration list/detail/map/assign;
  • device registration enable/disable;
  • device registration controls;
  • output mode update.

Security:

  • Telemetry and command ACK use IotIngestTokenGuard.
  • Guard expects IOT_INGEST_TOKEN.
  • Token is compared using timingSafeEqual.

Integration role:

MQTT device / iot-worker
  -> /api/iot/v1/telemetry
  -> backend validation and persistence
  -> sensors/readings/devices/alerts domain data

Production gap:

  • IoT production topology is still documented as TBD in deployment docs.
  • Device provisioning and production token rotation policy should be finalized.

11. Request And Response Conventions

11.1 Validation

Global validation behavior:

  • strips unknown fields through whitelist;
  • rejects non-whitelisted fields through forbidNonWhitelisted;
  • transforms payloads based on DTO metadata;
  • keeps implicit conversion disabled.

DTO rule:

  • Request DTOs should define validation decorators for all accepted fields.
  • Query DTOs should define type transformation explicitly where numeric/boolean values are expected.

11.2 Standard Response Shapes

Item response:

{
  "data": {},
  "message": "Thanh cong"
}

Paginated response:

{
  "data": [],
  "meta": {
    "page": 1,
    "take": 10,
    "itemCount": 0,
    "pageCount": 0,
    "hasPreviousPage": false,
    "hasNextPage": false
  },
  "message": "Thanh cong"
}

Common pagination fields:

Field Default Rule
search "" string
order DESC enum
orderBy createdAt string
page 1 integer, min 1
take 10 integer, min 1, max 100

11.3 Error Handling

Global Prisma exception mapping:

Prisma code HTTP status Meaning
P2000 400 Value too long
P2002 409 Unique constraint
P2003 400 Foreign key violation
P2025 404 Record not found
other known Prisma error 500 Generic database error

Validation and auth errors follow NestJS defaults unless overridden by controller/use-case code.

12. Data Access Architecture

Primary database access:

PrismaService -> Prisma Client -> PostgreSQL/TimescaleDB

Domain data clusters:

Cluster Models
Auth/user User, Session, AuditLog, FarmMember, PondAssignment
Farm/pond/crop Farm, Pond, Crop, CropSpecies, CropSizeRange
Logs/feeding ManualWaterRecord, MineralRecord, SiphonRecord, ProductivityRecord, FarmingLogAttachment, FeedingRecord, FeedType
IoT/device Sensor, SensorReading, ParameterThreshold, Device, DeviceCommandLog, AutoRule
Alerts/tickets Alert, AlertStatusHistory, Ticket, TicketAttachment, TicketComment, TicketStatusHistory, TicketWaterParameter
Knowledge/notification Notification, NotificationConfig, HandbookArticle, HandbookVersion, ArticleBookmark
Reports/location ReportHistory, Province, Ward

Database migration rule:

  • Production should use prisma migrate deploy.
  • prisma db push is not a production migration strategy.
  • Seed should not run in production unless explicitly approved and idempotent.

13. Client Integration Architecture

13.1 Web Client

Web API integration:

  • Axios config under web/src/core/config/axios.config.ts.
  • Endpoint constants under web/src/core/constants/api-url.ts.
  • Feature service wrappers under web/src/core/services/*.

Architecture rule:

  • Web pages/components should call service wrappers and hooks, not hardcode raw endpoints in UI components.
  • Endpoint constants intentionally omit /api; the base URL should include the API prefix when configured.

13.2 Mobile Client

Mobile API integration:

  • API client under mobile/src/core/config/api-client.ts.
  • Endpoint constants under mobile/src/core/constants/apiURL.constants.ts.
  • Feature service wrappers under mobile/src/core/services/api/*.

Mobile-specific auth behavior:

  • Mobile stores tokens client-side.
  • Mobile refresh flow can send x-client-type: mobile and x-refresh-token.

14. External Integrations

Integration Current API role
PostgreSQL/TimescaleDB Primary transactional and time-series persistence
Redis Session/cache provider when REDIS_HOST is configured
Google Cloud Storage Attachments, report files and uploaded objects
Gmail SMTP or console email Forgot password and email notifications
MQTT/IoT worker Telemetry, device command lifecycle and command ACK
Swagger/OpenAPI Runtime API documentation

15. Observability And Operations

Current confirmed behavior:

  • Successful API requests are logged by method, URL, status and duration.
  • Swagger asset requests are excluded from the success log.
  • Health endpoint exists at /api/health.
  • Status endpoint exists at /api/status.json.
  • Prisma known request errors are normalized by a global filter.

Current gaps:

  • No production metrics provider is confirmed.
  • No distributed tracing is confirmed.
  • No centralized log provider is confirmed.
  • No API SLO/SLI definitions are confirmed.

Recommended API signals:

Signal Purpose
Request rate by route/status Detect traffic and error spikes
P95/P99 latency Detect slow API paths
Auth failures Detect credential or session issues
Prisma error codes Detect data consistency and unique constraint issues
IoT ingest failures Detect device/worker integration problems
Report/export failures Detect async job issues
GCS/email failures Detect external provider issues

16. Versioning And Compatibility

Current versioning:

  • Main app APIs are not URL-versioned beyond the global /api prefix.
  • IoT API uses route-level version namespace /iot/v1.
  • Swagger document version is 1.0.0.

Compatibility rules:

  • Breaking response-shape changes must update 08_API Specification.md, client services, QA test cases and release notes.
  • New public routes should include Swagger decorators and DTO validation.
  • If route-level versioning expands beyond IoT, define a consistent API versioning policy before adding /v2 routes.

17. Security And Production Readiness Risks

ID Risk Impact Required follow-up
API-ARCH-01 Temporary auth/scope bypasses exist in multiple modules Users may access or mutate data beyond final intended scope Remove bypasses or document approved exception before production
API-ARCH-02 AdminGuard currently does not block non-admin users Admin-only APIs may be exposed Re-enable ForbiddenException and regression-test admin routes
API-ARCH-03 Some modules have uneven layering Changes may bypass consistent authorization/validation patterns Standardize new work around controller -> use case/service -> repository
API-ARCH-04 No confirmed metrics/tracing provider Incidents may be harder to diagnose Add centralized logs, metrics and alerting
API-ARCH-05 IoT token is a shared bearer token Token leakage could expose ingest endpoints Define rotation, scope and device provisioning strategy
API-ARCH-06 Main REST API has no formal URL versioning policy Future breaking changes may be hard to coordinate Define versioning policy before major API changes
API-ARCH-07 Web/mobile endpoint constants can drift from controllers Client regressions Keep 08_API Specification.md and service constants updated per API change

18. Change Rules

When changing API architecture or contracts:

  1. Update controller DTOs and Swagger decorators.
  2. Update docs/08_API Specification.md for endpoint contract changes.
  3. Update this file for runtime/layer/security/integration architecture changes.
  4. Update web/mobile endpoint constants and service wrappers.
  5. Add or update tests for auth, scope and response behavior.
  6. Record release notes for breaking changes.

19. Traceability

Source Architecture evidence
backend/main.ts Runtime bootstrap, prefix, CORS, validation, Swagger, logging
backend/app.module.ts Global modules, throttler, Prisma filter and feature module imports
backend/common/common.module.ts Prisma, cache, email and GCS providers
backend/common/dtos/* Response and pagination conventions
backend/common/filters/prisma-exception.filter.ts Prisma error mapping
backend/modules/auth/** Access token, refresh token and session architecture
backend/modules/iot-ingest/** IoT ingest API and token guard
backend/modules/**/**.controller.ts Route map and API surface
web/src/core/config/axios.config.ts Web API client runtime
web/src/core/constants/api-url.ts Web endpoint constants
mobile/src/core/config/api-client.ts Mobile API client runtime
mobile/src/core/constants/apiURL.constants.ts Mobile endpoint constants
docs/08_API Specification.md Endpoint-level API specification