Files
smoa/backend/README.md
defiQUG 5a8c26cf5d Backend, sync, infra, docs: ETag, API versioning, k8s, web scaffold, Android 16, domain stubs
- Backend: ShallowEtagHeaderFilter for /api/v1/*, API-VERSIONING.md, README (tenant, CORS, Flyway, ETag)
- k8s: backend-deployment.yaml (Deployment, Service, Secret/ConfigMap)
- Web: scaffold with directory pull, 304 handling, touch-friendly UI
- Android 16: ANDROID-16-TARGET.md; BuildConfig STUN/signaling, SMOAApplication configures InfrastructureManager
- Domain: CertificateManager revocation stub, ReportService signReports, ZeroTrust/ThreatDetection minimal docs
- TODO.md and IMPLEMENTATION_STATUS.md updated; communications README for endpoint config

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 20:37:01 -08:00

5.5 KiB
Raw Permalink Blame History

SMOA Backend

Ground-up backend with REST APIs for the Secure Mobile Operations Application (SMOA) Android app. Provides sync endpoints for directory, orders, evidence, credentials, and reports, with optional API key auth and OpenAPI docs.

Requirements

  • JDK 17
  • Gradle 8.x (wrapper included in repo root; run from backend/ with ../gradlew or install Gradle)

Quick Start

cd backend
../gradlew bootRun

Or with explicit profile:

../gradlew bootRun --args='--spring.profiles.active=dev'
  • API base: http://localhost:8080
  • Health: GET http://localhost:8080/health
  • API info: GET http://localhost:8080/api/v1/info
  • Swagger UI: http://localhost:8080/swagger-ui.html
  • OpenAPI JSON: http://localhost:8080/v3/api-docs

Sync API (for the mobile app)

All sync endpoints accept JSON and return a SyncResponse that matches the mobile SyncAPI contract in core/common/SyncAPI.kt:

Endpoint Method Request body Response
/api/v1/sync/directory POST DirectorySyncRequest SyncResponse
/api/v1/sync/order POST OrderSyncRequest SyncResponse
/api/v1/sync/evidence POST EvidenceSyncRequest SyncResponse
/api/v1/sync/credential POST CredentialSyncRequest SyncResponse
/api/v1/sync/report POST ReportSyncRequest SyncResponse

Delete (sync delete): DELETE /api/v1/sync/directory/{id}, DELETE /api/v1/sync/order/{orderId}, DELETE /api/v1/sync/evidence/{evidenceId}, DELETE /api/v1/sync/credential/{credentialId}, DELETE /api/v1/sync/report/{reportId} — each returns SyncResponse.

Pull / GET (refresh or initial load): GET /api/v1/directory (optional unit, X-Unit), GET /api/v1/orders (since, limit, jurisdiction / X-Unit), GET /api/v1/evidence, GET /api/v1/credentials, GET /api/v1/reports (since, limit, optional filters).

SyncResponse fields: success, itemId, serverTimestamp, conflict, remoteData (optional), message (optional). When conflict: true, remoteData is base64-encoded JSON of the server version.

Conflict detection: send lastUpdated (directory) or clientUpdatedAt (others). If the server has a newer version, the response has conflict: true and remoteData with the server payload.

Authentication

  • Development: No API key required when smoa.api.key is empty (default in dev profile).
  • Production: Set SMOA_API_KEY (or smoa.api.key). Clients must send:
    • Header: X-API-Key: <key>, or
    • Query: ?api_key=<key>

Configuration

Property Default Description
server.port 8080 Server port
spring.datasource.url H2 file ./data/smoa DB URL (use PostgreSQL in production)
smoa.api.key (empty) API key; empty = no auth
smoa.api.key-header X-API-Key Header name for API key
smoa.cors.allowed-origins * CORS origins (comma-separated); * = any, no credentials
smoa.rate-limit.enabled true Rate limit on /api/v1/* (per API key or IP)
smoa.rate-limit.requests-per-minute 120 Max requests per minute; 429 when exceeded
smoa.tenant.require-unit false When true, require X-Unit (or unit query) for all /api/v1 requests
smoa.cors.allowed-origins * Production: set to your web app origin(s) (e.g. https://smoa.example.com) for CORS

Tracing: Each request gets an X-Request-Id header (or preserves incoming one); use for logs and support.

Caching: GET list endpoints support ETag and If-None-Match; send If-None-Match: <etag> to receive 304 Not Modified when unchanged.

Profiles:

  • dev relaxed auth, H2 console at /h2-console, debug logging.
  • prod set SPRING_PROFILES_ACTIVE=prod and SMOA_API_KEY, and switch datasource to PostgreSQL as needed.

Database

  • Default: H2 file database at ./data/smoa. Flyway runs migrations from db/migration/; ddl-auto: update in dev.
  • Production: Use PostgreSQL: set spring.datasource.url=jdbc:postgresql://..., driver-class-name=org.postgresql.Driver, and add org.postgresql:postgresql dependency. Use ddl-auto: validate (set in application-prod.yml) so Flyway owns the schema.

Building

cd backend
../gradlew build

JAR:

../gradlew bootJar
# output: build/libs/smoa-backend-1.0.0.jar
java -jar build/libs/smoa-backend-1.0.0.jar

Docker (build from repo root):

docker build -f backend/Dockerfile .
docker run -p 8080:8080 <image-id>

Sync and delete operations are audit logged (resource type, id, operation, success).

Connecting the Android app

  1. Point the apps sync base URL to this backend (e.g. http://<host>:8080).
  2. Implement a real SyncAPI (e.g. with Retrofit) that:
    • Serializes domain models to JSON matching the backend DTOs (DirectorySyncRequest, OrderSyncRequest, etc.).
    • POSTs to /api/v1/sync/directory, /api/v1/sync/order, etc.
    • Parses SyncResponse (and handles conflict / remoteData when present).

Request DTOs align with the apps directory, order, evidence, report, and credential concepts; field names and types are chosen for easy mapping from the mobile side.

Gap analysis and roadmap

See docs/BACKEND-GAPS-AND-ROADMAP.md for a full review: what's covered, completed gaps (delete sync, pull/GET, enum validation, rate limiting, audit, tests, Dockerfile), and optional follow-ups (prod profile, unit/tenant scoping, migrations).