Files
smoa/docs/database/DATABASE_SCHEMA.md
T
defiQUG a2dc194a49 Monorepo: Gitea CI, docs, auth/sync, backend APIs, gitignore
- Add Gitea Actions workflow; point README to gitea.d-bis.org/Sankofa_Phoenix/SMOA
- Expand .gitignore for Spring H2 data, secrets, Kotlin .kotlin/, tooling
- Track docs/api/generated ReDoc bundle; refresh api docs README
- Android: network/auth/sync, UI shell, tests; backend credentials/integrity APIs
- Docs, scripts (generate-api-docs), modules and core updates

Made-with: Cursor
2026-03-23 20:19:24 -07:00

222 lines
6.8 KiB
Markdown

# SMOA database schema (server + device)
**Version:** 2.0
**Last updated:** 2026-03-23
This document aligns **SMOA backend** (Flyway `V1__baseline.sql`, H2 or PostgreSQL) with **on-device Room** entities in this repository. Older rows that described only a generic local `credentials` table **without** a matching entity are removed.
---
## 1. Server database (SMOA backend)
Source of truth: `backend/src/main/resources/db/migration/V1__baseline.sql`.
JPA entities: `backend/src/main/kotlin/com/smoa/backend/domain/*.kt`.
### 1.1 `directory_entries`
| Column | SQL type | Description |
|--------|-----------|-------------|
| id | VARCHAR(255) PK | Directory entry id |
| name | VARCHAR(255) | Display name |
| title | VARCHAR(255) | Job title |
| unit | VARCHAR(255) | Unit / org |
| phone_number | VARCHAR(255) | Phone |
| extension | VARCHAR(255) | Extension |
| email | VARCHAR(255) | Email |
| secure_routing_id | VARCHAR(255) | Secure routing |
| role | VARCHAR(255) | Role |
| clearance_level | VARCHAR(255) | Clearance |
| last_updated | BIGINT | Epoch ms |
### 1.2 `orders`
| Column | SQL type | Description |
|--------|-----------|-------------|
| order_id | VARCHAR(255) PK | Order id |
| order_type | VARCHAR(255) | Enum string (see backend validation) |
| title | VARCHAR(255) | Title |
| content | CLOB | Body |
| issued_by | VARCHAR(255) | Issuer |
| issued_to | VARCHAR(255) | Recipient |
| issue_date | TIMESTAMP | Issued |
| effective_date | TIMESTAMP | Effective |
| expiration_date | TIMESTAMP | Expiry |
| status | VARCHAR(255) | Status enum |
| classification | VARCHAR(255) | Classification |
| jurisdiction | VARCHAR(255) | Jurisdiction |
| case_number | VARCHAR(255) | Case |
| updated_at | BIGINT | Epoch ms |
### 1.3 `evidence`
| Column | SQL type | Description |
|--------|-----------|-------------|
| evidence_id | VARCHAR(255) PK | Evidence id |
| case_number | VARCHAR(255) | Case |
| description | CLOB | Description |
| evidence_type | VARCHAR(255) | Type enum |
| collection_date | TIMESTAMP | Collected |
| collection_location | VARCHAR(255) | Location |
| collection_method | VARCHAR(255) | Method |
| collected_by | VARCHAR(255) | Collector |
| current_custodian | VARCHAR(255) | Custodian |
| storage_location | VARCHAR(255) | Storage |
| updated_at | BIGINT | Epoch ms |
### 1.4 `credentials` (server)
| Column | SQL type | Description |
|--------|-----------|-------------|
| credential_id | VARCHAR(255) PK | Credential id |
| holder_id | VARCHAR(255) | Subject / holder |
| credential_type | VARCHAR(255) | Canonical type (`SmoaCredentialType` + legacy; see `docs/reference/IDENTITY-TEMPLATE-ALIGNMENT.md`) |
| issuer | VARCHAR(255) | Issuing authority label |
| issued_at | BIGINT | Epoch ms (optional) |
| expires_at | BIGINT | Epoch ms (optional) |
| payload_json | CLOB | JSON object: format-specific fields, optional `issuingAuthority`, `completeCredentialDomain`, `extensions` |
| updated_at | BIGINT | Epoch ms |
**Issuance validation:** Parse `payload_json` as JSON, then validate with `docs/schemas/credential-payload-*.schema.json` for the given `credential_type` on the sync **request body** (not duplicated inside payload).
### 1.5 `reports`
| Column | SQL type | Description |
|--------|-----------|-------------|
| report_id | VARCHAR(255) PK | Report id |
| report_type | VARCHAR(255) | Type enum |
| title | VARCHAR(255) | Title |
| format | VARCHAR(255) | PDF, XML, JSON, CSV, EXCEL |
| generated_date | BIGINT | Epoch ms |
| generated_by | VARCHAR(255) | Generator |
| content | BLOB | Optional binary |
| metadata_json | CLOB | Optional JSON |
| updated_at | BIGINT | Epoch ms |
### 1.6 `sync_audit_log`
| Column | SQL type | Description |
|--------|-----------|-------------|
| id | BIGINT IDENTITY PK | Surrogate key |
| resource_type | VARCHAR(255) | Resource |
| resource_id | VARCHAR(255) | Id |
| operation | VARCHAR(255) | Operation |
| success | BOOLEAN | Outcome |
| principal | VARCHAR(255) | Optional actor |
| timestamp | TIMESTAMP | Event time |
---
## 2. On-device Room (implemented modules)
Room uses SQLite; module-specific databases. Below match Kotlin `@Entity` types.
### 2.1 Directory — `directory_entries`
`modules/directory/.../DirectoryEntity.kt`
| Column | Type | Notes |
|--------|------|--------|
| id | TEXT PK | |
| name | TEXT | |
| title | TEXT? | |
| unit | TEXT | |
| phoneNumber | TEXT? | camelCase in Kotlin → snake in DB per Room |
| extension | TEXT? | |
| email | TEXT? | |
| secureRoutingId | TEXT? | |
| role | TEXT? | |
| clearanceLevel | TEXT? | |
| lastUpdated | INTEGER | Epoch ms |
### 2.2 Orders — `orders`
`modules/orders/.../OrderEntity.kt`
| Column | Type | Notes |
|--------|------|--------|
| orderId | TEXT PK | |
| orderType | TEXT | Enum persisted via converter |
| title | TEXT | |
| content | TEXT | |
| issuedBy | TEXT | |
| issuedTo | TEXT? | |
| issueDate | INTEGER / Date | Type converters |
| effectiveDate | | |
| expirationDate | | |
| status | | Enum |
| classification | TEXT? | |
| jurisdiction | TEXT | |
| caseNumber | TEXT? | |
| createdAt | | |
| updatedAt | | |
### 2.3 Evidence — `evidence`
`modules/evidence/.../EvidenceEntity.kt`
| Column | Type | Notes |
|--------|------|--------|
| evidenceId | TEXT PK | |
| caseNumber | TEXT | |
| description | TEXT | |
| evidenceType | | Enum |
| collectionDate | | |
| collectionLocation | TEXT | |
| collectionMethod | TEXT | |
| collectedBy | TEXT | |
| currentCustodian | TEXT | |
| storageLocation | TEXT? | |
| createdAt | | |
| updatedAt | | |
### 2.4 Custody — `custody_transfers`
`modules/evidence/.../CustodyTransferEntity.kt`
| Column | Type | Notes |
|--------|------|--------|
| transferId | TEXT PK | |
| evidenceId | TEXT FK → evidence | |
| timestamp | Date | |
| fromCustodian | TEXT | |
| toCustodian | TEXT | |
| reason | TEXT | |
| evidenceCondition | TEXT | |
| signatureData | BLOB? | |
| notes | TEXT? | |
### 2.5 Credentials cache — `credential_cache`
`modules/credentials/.../CredentialCacheEntity.kt` (encrypted Room DB `credential_cache_database`)
| Column | Type | Notes |
|--------|------|--------|
| credentialId | TEXT PK | |
| holderId | TEXT | |
| credentialType | TEXT | |
| issuer | TEXT? | |
| issuedAt | INTEGER? | Epoch ms |
| expiresAt | INTEGER? | Epoch ms |
| payloadJson | TEXT? | JSON string |
| updatedAt | INTEGER | Epoch ms |
Populate from pull/sync merge logic in application code when wired; schema matches server `credentials` for offline display.
### 2.6 Reports (device)
No Room `ReportEntity` in this repo; reports remain server-backed unless a local entity is added later.
---
## 3. Indexes (server)
- `idx_sync_audit_timestamp` on `sync_audit_log(timestamp)`
---
## 4. References
- Backend Flyway: `backend/src/main/resources/db/migration/V1__baseline.sql`
- Identity / payload schemas: `docs/reference/IDENTITY-TEMPLATE-ALIGNMENT.md`, `docs/schemas/`
- Tenant model: `docs/security/TENANT-THREAT-MODEL.md`