Production-Grade GraphQL Gateway | Fortress Security | Cloud-Native | Enterprise-Hardened
\"When speed meets security. When scale meets simplicity. When enterprise demands elegance.\"
ORACLE is a premium GraphQL platform engineered for enterprises that demand uncompromising security, lightning-fast performance, and transparent observability. Built with Spring Boot 3, Oracle Database, and cloud-native resilience patterns—ORACLE transforms complex backend architectures into elegant, typesafe GraphQL APIs.
- Overview
- Highlights
- Architecture
- Quick Start
- Configuration
- GraphQL & REST Interfaces
- Quality & Operations
- Troubleshooting
- Contributing
- License
ORACLE is the GraphQL intelligence layer for enterprises. A Spring Boot 3 powerhouse that seamlessly orchestrates complex backend architectures—Oracle databases, distributed storage, caching layers—and exposes them through a single, typesafe GraphQL interface.
Not your typical API gateway. ORACLE brings:
- Zero-Trust Security: JWT validation meets field-level authorization, cryptographically enforced per request
- Audit-First Design: Every login, every query, every permission check is immutably logged
- Enterprise Compliance: GDPR, SOX, and HIPAA-ready roadmap with multi-phase security hardening
- Performance at Scale: Caffeine + Redis caching with circuit breakers for distributed resilience
Key use cases include:
- Authenticating users via username/password and issuing signed JWT access tokens
- Managing user profiles through GraphQL queries and mutations
- Uploading artifacts to MinIO-compatible object storage services
- Monitoring system health with custom contributors for database files, JDBC connections, and MinIO reachability
✅ Built for scale – Oracle partitioning, Redis clustering, connection pooling optimized for millions of QPS
✅ Security DNA – Zero-trust from first request; JWT entropy validation + field-level auth enforced at GraphQL layer
✅ Compliance-native – GDPR/SOX roadmap; immutable audit logs; secrets rotation; encryption strategies
✅ DevOps-friendly – Spring Boot + Docker + Kubernetes native; self-contained Jetty with TLS built-in
✅ Observable end-to-end – Micrometer metrics, distributed traces, custom health contributors, Grafana-ready
✅ Open & extensible – Spring ecosystem, GraphQL-Java, Flyway migrations—plug in your tools, keep your freedom
| Capability | Enterprise Edge |
|---|---|
| Zero-Trust Execution | Cryptographic JWT validation + field-level GraphQL authorization—every operation audited |
| Type-Safe GraphQL API | Lean schema, mutation-driven workflows (login/MFA/profile), query-driven discovery |
| Multi-Tenant Ready | Oracle partitioning + Redis isolation = scale to millions without breaking a sweat |
| S3 & Object Storage | Native MinIO + S3-compatible integrations with health probes and retry logic |
| Real-Time Observability | Distributed tracing, composite health indicators, Prometheus-ready metrics |
| Compliance Roadmap | Phase-driven MFA (TOTP, WebAuthn, SMS), immutable audit logs, TDE encryption, dynamic RBAC |
| 99.9% SLA Architecture | Circuit breakers, connection pooling, bulkhead isolation—resilience by design |
clients ─┬─▶ HTTPS (Spring Boot + Jetty @ 8443)
│ ├─ GraphQL endpoint (/graphql)
│ ├─ GraphiQL IDE (/graphiql)
│ └─ REST auth endpoints (/api/auth/**)
│
├─▶ Security Pipeline
│ ├─ JwtAuthenticationFilter (servlet)
│ ├─ SecurityFilterChain (access rules)
│ └─ GraphQLAuthorizationInstrumentation
│
├─▶ Services & Data
│ ├─ UserService (JPA + Oracle)
│ ├─ MinIO client (object storage)
│ └─ AuditService (login/session logging)
│
└─▶ Observability
├─ Custom health indicators
└─ Spring Actuator (/actuator/**)
- Java 21 (LTS, configured via Gradle toolchains)
- Gradle 8+ (modern build orchestration)
- Oracle Database 19c+ (or Oracle XE for dev)
- Redis 7.4+ (cache/session store)
- (Optional) Docker + MinIO for local S3-compatible testing
⚠️ IMPORTANT: The following manual setup steps must be performed by a DBA with SYS/DBA privileges before running the application or Flyway migrations.
-
Create the application user (run as SYS or DBA):
Execute the scripts in
sql/users/as SYS/DBA:sqlplus / as sysdba SQL> @sql/users/create_user_with_grants.sql # For development only: SQL> @sql/users/create_user_with_debug_grants.sql
See
sql/users/README.mdfor full deployment instructions and password management. -
Automated Schema Setup (run via application):
The application uses Flyway to automatically create tables, sequences, and indexes on first startup. This is managed by:
./gradlew bootRun # OR docker-compose up # Includes automatic user creation via docker-entrypoint-initdb.d/01-init-user.sh
-
Default Admin User:
When the application starts for the first time, a default admin user is created with:
- Username:
admin - Password:
Admin@123(hashed in the database)
⚠️ Security Warning: Change the default admin password immediately after first login. - Username:
git clone https://github.com/your-org/graphqlScala.git
cd graphqlScala
# Run unit tests and build artifacts
./gradlew clean buildCreate a .env or export variables in your shell:
export ORACLE_HOST=localhost
export ORACLE_PORT=1521
export ORACLE_DB=FREEPDB1
export ORACLE_USER=APP_USER
export ORACLE_PASSWORD=APP_USER
export JWT_SECRET="paste-a-random-32-plus-character-secret-here"
export MINIO_ACCESS_KEY=minioadmin
export MINIO_SECRET_KEY=minioadmin
export MINIO_URL=http://localhost:9000
# Optional: provide a custom SSL keystore password
export KEYSTORE_PASSWORD=changeit🔐 Security Hardened:
JWT_SECRETenforces entropy validation—32+ chars withmin(20, length/2)distinct characters. For a 32-char secret, you need 16+ unique chars. This isn't paranoia; this is how enterprises stay breached-free.
⚠️ Database Password Warning: For production deployments, DO NOT use the default database passwordAPP_USERor any development-only value likeDevOnly_Password123!. SetDB_USER_PASSWORD(orORACLE_PASSWORD) to a strong, unique value in your deployment environment. Seedocs/SECURITY_ARCHITECTURE.mdfor guidance on secrets management.
The following environment variables MUST be set before starting the application. The application will fail fast with a clear error message if any are missing:
| Environment Variable | Purpose | Notes |
|---|---|---|
JWT_SECRET |
Symmetric key for signing and validating JWT tokens | Must be ≥32 characters and contain at least min(20, length/2) distinct characters (e.g., 16 distinct characters for a 32-char secret). |
MINIO_ACCESS_KEY |
Access key for MinIO object storage authentication | Cannot use default values; must be explicitly set. |
MINIO_SECRET_KEY |
Secret key for MinIO object storage authentication | Cannot use default values; must be explicitly set. |
TRACE_PII_SALT |
Salt for hashing PII in traces (userId, client_ip) | REQUIRED in production. Min 16 chars, must include uppercase, lowercase, digits, and special characters. Load from secure secrets manager (AWS Secrets Manager, Vault, etc.), NOT from hardcoded properties. |
CORS_ALLOWED_ORIGINS |
Comma-separated list of trusted origins for CORS | Optional in dev; required in production. Example: https://app.example.com,https://www.example.com. If not set, defaults to http://localhost:4200. |
Example: Setting Strong Credentials
# Generate a secure 32+ character JWT_SECRET
export JWT_SECRET=$(openssl rand -base64 32)
# MinIO credentials (use strong, unique values in production)
export MINIO_ACCESS_KEY=$(openssl rand -base64 16)
export MINIO_SECRET_KEY=$(openssl rand -base64 32)
# PII hash salt (must include uppercase, lowercase, digits, and special chars)
# For production, load from AWS Secrets Manager, Vault, or similar secure store
export TRACE_PII_SALT="Prod@Salt!2024#Secure$(openssl rand -hex 8)"
# CORS allowed origins (comma-separated, required for production)
export CORS_ALLOWED_ORIGINS="https://app.example.com,https://www.example.com"IMPORTANT: Never commit or hardcode secrets in your application. For production deployments, use a dedicated secrets manager:
# 1. Install Vault CLI and authenticate
vault login -method=ldap username=<your-username>
# 2. Retrieve secrets and set environment variables
export JWT_SECRET=$(vault kv get -field=jwt_secret secret/ssf/prod)
export MINIO_ACCESS_KEY=$(vault kv get -field=access_key secret/ssf/prod)
export MINIO_SECRET_KEY=$(vault kv get -field=secret_key secret/ssf/prod)
export TRACE_PII_SALT=$(vault kv get -field=trace_pii_salt secret/ssf/prod)
# 3. Start the application
./gradlew bootRun# 1. Install AWS CLI and configure credentials
aws configure
# 2. Retrieve secrets and set environment variables
export JWT_SECRET=$(aws secretsmanager get-secret-value --secret-id ssf/jwt_secret --query SecretString --output text)
export MINIO_ACCESS_KEY=$(aws secretsmanager get-secret-value --secret-id ssf/minio_access_key --query SecretString --output text)
export MINIO_SECRET_KEY=$(aws secretsmanager get-secret-value --secret-id ssf/minio_secret_key --query SecretString --output text)
export TRACE_PII_SALT=$(aws secretsmanager get-secret-value --secret-id ssf/trace_pii_salt --query SecretString --output text)
# 3. Start the application
./gradlew bootRunFor containerized environments, inject secrets via:
- Docker: Use
docker run --env-file .envor Docker Secrets - Kubernetes: Use Kubernetes Secrets mounted as environment variables or files
- Docker Compose: Reference secrets in
.envfile (keep.envoutside version control)
Example docker-compose.yml with secrets:
version: '3.8'
services:
app:
image: ssf-graphql:latest
environment:
JWT_SECRET: ${JWT_SECRET}
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
# ... other configuration./gradlew bootRunThe server boots with HTTPS on https://localhost:8443. Since a development keystore is bundled (src/main/resources/keystore.p12), your browser/HTTP client may require a trust override.
The application uses a self-signed certificate in the bundled keystore for local development. To test the GraphQL API with Postman:
-
Import the Self-Signed Certificate (Recommended for development):
- Open Postman → Settings (⚙️ icon) → Certificates → CA Certificates
- Click Select File and choose
src/main/resources/keystore.p12 - Enter password:
changeit(default development keystore password) - Reload Postman
-
Alternative: Temporarily Disable SSL Verification (NOT recommended for production):
- Open Settings (⚙️ icon) → General → SSL certificate verification: toggle OFF
⚠️ Warning: Only for development. Re-enable for any sensitive work.
-
Use the Postman Collection:
- Import
SSF-GraphQL-Postman-Collection.jsoninto Postman - Update environment variables:
base_url: Should resolve tohttps://localhost:8443(already set)username/password: Set to test account credentials
- All requests in the collection use the standardized full URL structure with explicit host, port, and path
- Import
For Production Deployments:
- Replace
keystore.p12with a certificate signed by a trusted Certificate Authority - Set
strictSSL: true(enforced by default in the Postman collection) - Use valid DNS names and update environment variables accordingly
# Oracle Database XE (example - development only, replace password before production)
docker run -d --name oracle-xe \
-p 1521:1521 -p 5500:5500 \
-e ORACLE_PASSWORD=DevOnly_Password123! \
gvenzl/oracle-xe:21-slim
# MinIO
docker run -d --name minio \
-p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
quay.io/minio/minio server /data --console-address :9001
# Redis Cache
docker run -d --name redis-cache \
-p 6379:6379 \
redis:7.4-alpineSpring Boot properties can be set via application.yml, profile-specific files, or environment variables. Key properties include:
| Property | Description | Required | Default |
|---|---|---|---|
server.port |
HTTPS port | No | 8443 |
server.ssl.* |
Keystore path, password, alias | No | Bundled PKCS12 keystore |
spring.datasource.url |
Oracle JDBC URL | No | jdbc:oracle:thin:@//${ORACLE_HOST}:${ORACLE_PORT}/${ORACLE_DB} |
spring.datasource.username / password |
Database credentials | No | APP_USER / APP_USER |
spring.redis.host |
Redis server hostname | No | localhost |
spring.redis.port |
Redis server port | No | 6379 |
app.jwt.secret |
Symmetric signing key for JWT | YES | None (must be set via JWT_SECRET environment variable) |
jwt.expiration |
Token lifetime (ms) | No | 86400000 (1 day) |
app.minio.url |
MinIO endpoint | No | http://localhost:9000 |
app.minio.access-key |
MinIO credentials | YES | None (must be set via MINIO_ACCESS_KEY environment variable) |
app.minio.secret-key |
MinIO credentials | YES | None (must be set via MINIO_SECRET_KEY environment variable) |
security.password.bcrypt.strength |
BCrypt cost factor for password hashing (4-31) | No | 12 |
app.avatar.max-size-mb |
Maximum avatar file size (MB) | No | 5 |
app.avatar.allowed-types |
Comma-separated MIME types for avatars | No | image/jpeg,image/png,image/webp |
cache.preferences.ttl-minutes |
User preferences cache TTL (Redis) | No | 60 |
BCrypt Strength Configuration:
The security.password.bcrypt.strength property controls the computational cost of password hashing. Valid range is 4-31, with higher values providing better security but slower performance:
- Strength 10: ~100ms per hash (suitable for development)
- Strength 12: ~400ms per hash (balanced security/performance)
- Strength 14: ~1600ms per hash (high security)
When increasing strength in production, load-test authentication endpoints to ensure acceptable response times. The default of 12 provides strong security for most deployments.
Content Security Policy (CSP):
The application implements a strict Content Security Policy (CSP) without 'unsafe-inline' directives to prevent XSS attacks. CSP nonces are automatically generated per request by the CspHeaderFilter and enforced at the CDN and backend levels. All inline scripts and styles use external files exclusively, or (if necessary) are protected with cryptographically secure nonces.
For detailed CSP implementation, architecture, and troubleshooting, see docs/CSP_IMPLEMENTATION.md.
Cross-Origin Resource Sharing (CORS):
The application configures CORS to allow requests from http://localhost:4200 for development purposes. This enables the Angular frontend running on the default development port to communicate with the backend. In production, CORS should be restricted to trusted origins only. The CORS policy is defined in SecurityConfig.java and allows GET, POST, PUT, DELETE, and OPTIONS methods with credentials.
Breaking Change: JWT_SECRET, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY no longer have unsafe default values. All three must be explicitly set via environment variables or the application will fail at startup with a clear error message.
For non-production work, source secrets from an ignored file instead of hardcoding them in application.yml. One simple approach is to create a .env.local (listed in .gitignore) containing only development credentials, then run set -a && source .env.local && set +a before ./gradlew bootRun. This keeps local experimentation convenient without ever committing secrets. Production deployments should continue to rely on a secrets manager or orchestration platform to inject JWT_SECRET and other sensitive values at runtime.
Profile-specific overrides live under src/main/resources/application-*.yml.
The partition maintenance script (scripts/partition-maintenance.sh) and database connections use secure credential handling to prevent password exposure. For detailed setup instructions including:
- Setting up a secure password file (chmod 600)
- Configuring the Oracle External Password Store (Wallet)
- Kubernetes/Docker deployment with secrets
- Auditing and monitoring best practices
See docs/SECURITY_ARCHITECTURE.md.
Quick Start:
# Create secrets directory
mkdir -p .secrets && chmod 700 .secrets
# Store database password securely
printf '%s' "your-secure-password" > .secrets/oracle-password
chmod 600 .secrets/oracle-password
# Add to .gitignore (already included)
echo ".secrets/" >> .gitignore
# Test partition maintenance
./scripts/partition-maintenance.shPOST https://localhost:8443/graphql— GraphQL operationsGET https://localhost:8443/graphiql— in-browser IDEPOST https://localhost:8443/api/auth/login— REST loginPOST https://localhost:8443/api/auth/validate— REST token validationGET https://localhost:8443/actuator/health— health probe
mutation {
login(username: "demo", password: "changeit") {
token
}
}Use the returned token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...query {
getUserByUsername(username: "demo") {
id
username
email
}
}query {
getUserPreferences {
theme
language
notificationEmails
notificationPush
notificationLoginAlerts
}
}mutation {
updateUserPreferences(preferences: {
theme: "dark"
language: "en"
notificationEmails: true
notificationPush: false
notificationLoginAlerts: true
notificationSecurityUpdates: true
}) {
theme
language
updatedAt
}
}mutation {
updatePassword(
currentPassword: "OldPassword123"
newPassword: "NewPassword456"
)
}mutation {
generateApiKey(input: {
keyName: "integration-key"
expiresInDays: 90
description: "Service-to-service authentication"
}) {
rawKey
keyPreview
expiresAt
warning
}
}query {
getApiKeys {
id
keyName
keyPreview
createdAt
expiresAt
lastUsedAt
status
}
}mutation {
revokeApiKey(keyId: 123) {
id
revokedAt
status
}
}mutation {
deactivateAccount(reason: "Taking a break") {
status
deactivatedAt
message
}
}mutation {
reactivateAccount {
status
message
}
}The user settings module also provides REST endpoints for avatar management:
Upload Avatar:
POST /api/user/avatar
Content-Type: multipart/form-data
file: <avatar_image_file>Response:
{
"avatarKey": "user_12345_a1b2c3d4.jpg",
"avatarUrl": "/api/user/avatar/user_12345_a1b2c3d4.jpg",
"message": "Avatar uploaded successfully"
}Download Avatar:
GET /api/user/avatar/user_12345_a1b2c3d4.jpgDelete Avatar:
DELETE /api/user/avatarAvatar Constraints:
- Maximum file size: 5 MB (configurable via
app.avatar.max-size-mb) - Supported formats: JPEG, PNG, WebP (configurable via
app.avatar.allowed-types) - Uploaded avatars are stored in MinIO with secure key generation
SSF-GraphQL-Postman-Collection.jsonis the hardened collection used for shared staging/production testing. It now enforcesstrictSSL=true, so Postman must trust the certificate chain before requests execute. Import the Jetty dev certificate into your OS/Postman trust store or configure Postman Settings → Certificates to trusthttps://localhost:8443.postman-collection.jsonis the lightweight developer-focused collection that drives the GraphQL samples in this repo. Its requests rely on thebase_urlvariable (defaulthttps://localhost:8443), so you only need to change that single variable to target another stack. URLs are built with a single{{base_url}}/graphqlstring to avoid accidentally duplicating the protocol prefix.- Local override: If you cannot trust the dev certificate, duplicate the production collection inside Postman and set
protocolProfileBehavior.strictSSL=falseonly in that private copy. Never disable strict SSL in workspace-wide or shared collections.
./gradlew test # Unit & integration tests
./gradlew jacocoTestReport # HTML coverage (build/jacocoHtml)The application includes Gatling performance tests that can be configured for different environments. Since Gatling is included as a test dependency, simulations run as standard Java applications:
# Run performance tests against local environment (default)
./gradlew test --tests "*UserSimulation*"
# Run against different base URL via system property
./gradlew test --tests "*UserSimulation*" -Dbase.url=https://staging.example.com
# Run against different base URL via environment variable
BASE_URL=https://production.example.com ./gradlew test --tests "*UserSimulation*"
# For CI environments with self-signed certificates, configure JVM truststore
./gradlew test --tests "*UserSimulation*" -Djavax.net.ssl.trustStore=/path/to/truststore.jks -Djavax.net.ssl.trustStorePassword=passwordPerformance Test Configuration:
- Base URL: Configurable via
base.urlsystem property orBASE_URLenvironment variable - Default:
https://localhost:8443(for local development) - SSL: Uses JVM's default truststore; override with system properties for custom certificates
- Load Profile: 5,000 users ramping over 3 minutes, then 50 users/sec for 2 minutes
- Assertions: 95% of requests under 1 second, max 5 seconds, 95% success rate
- Composite health contributor registers
databaseFile,databaseConnection, andminio - Custom Actuator indicator
yousurfaces AI readiness ({"ai":"I am up and running!"}) - Enable additional Actuator endpoints by adjusting
management.endpoints.web.exposure.include
The rolling partition script (scripts/partition-maintenance.sh) now refuses to embed credentials on the command line. Instead, it reads the Oracle password from a local file with 600 permissions. By default the script looks for .secrets/oracle-password at the repo root, or you can point to another location via ORACLE_PASSWORD_FILE.
mkdir -p .secrets
printf 'super-secret-password' > .secrets/oracle-password
chmod 600 .secrets/oracle-password
# optional: override location
export ORACLE_PASSWORD_FILE=$PWD/.secrets/oracle-password
./scripts/partition-maintenance.shBecause SQL*Plus now receives the password via stdin, it no longer appears in process listings or shell history. Metrics continue to land in metrics/partition-maintenance.prom by default and can be overridden with PARTITION_METRICS_FILE.
./gradlew bootBuildImage --imageName=ssf-graphql:latestThe Dockerfile supports configurable build arguments for flexibility across development, staging, and production environments:
Specifies the relative path to the pre-built Angular frontend distribution directory. Use this when the frontend build output is in a non-standard location.
# Custom frontend dist path (e.g., when building in a monorepo)
docker build \
--build-arg FRONTEND_DIST_PATH=apps/my-app/dist/my-app \
-t ssf-graphql:latest .
# Standard path (default)
docker build -t ssf-graphql:latest .Build-time Validation: The Dockerfile validates that the specified path contains files; build fails immediately with a clear error if the directory is missing or empty, preventing silent failures at runtime.
Specifies the Common Name (CN) for the self-signed TLS certificate generated at runtime. Use this to match your actual hostname for local development or testing environments.
# Development with custom hostname
docker build \
--build-arg CERT_CN=api.local \
-t ssf-graphql:latest .
# Production-like environment
docker build \
--build-arg CERT_CN=api.example.com \
-t ssf-graphql:latest .- Use a certificate issued by a trusted Certificate Authority (CA)
- Mount the CA-signed certificate into the container at runtime via Docker volumes or Kubernetes secrets
- Update the keystore with your CA-signed certificate before container startup
- Never rely on self-signed certificates in production—client applications will reject them unless explicitly configured to trust self-signed certs
# Build frontend assets (if not already built)
cd frontend && npm ci && npm run build && cd ..
# Build container with custom paths
docker build \
--build-arg FRONTEND_DIST_PATH=dist/frontend \
--build-arg CERT_CN=ssf-api.internal \
--tag ssf-graphql:v1.0.0 \
.
# Run with volume mount for production certificate
docker run \
-p 8443:8443 \
-v /etc/ssl/certs/my-ca.crt:/app/certs/ca.crt:ro \
-e SPRING_PROFILES_ACTIVE=production \
ssf-graphql:v1.0.0version: '3.8'
services:
app:
build:
context: .
args:
FRONTEND_DIST_PATH: dist/frontend
CERT_CN: localhost
environment:
JWT_SECRET: ${JWT_SECRET}
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev}
ports:
- "8443:8443"
depends_on:
- oracle
- redis
- minio| Symptom | Resolution |
|---|---|
IllegalStateException: Missing required environment variables |
Set JWT_SECRET, MINIO_ACCESS_KEY, and MINIO_SECRET_KEY environment variables before starting the app. See Required Environment Variables section above. |
IllegalStateException: JWT secret must be provided |
Set JWT_SECRET with ≥32 characters before starting the app |
ORA-01017 authentication errors |
Verify ORACLE_USER/ORACLE_PASSWORD; if running locally ensure Oracle XE container is healthy |
RedisConnectionFailureException: Unable to connect to Redis |
Start Redis locally (docker run redis:7.4-alpine or brew services start redis) or set REDIS_HOST/PORT so the app can reach an existing instance. |
GraphiQL reports Authentication required |
Supply a valid JWT token in the Authorization header. As a last resort for local development only, you may temporarily disable enforcement in SecurityConfig; never commit, push, or enable this bypass outside your machine. Prefer safer alternatives such as generating a valid JWT, using a temporary environment-only feature flag, or mocking auth locally, and audit commits plus CI/CD configs before merge/deploy. |
| MinIO health check is DOWN | Confirm MinIO container is reachable and credentials match minio.* properties |
SSF implements a comprehensive security roadmap targeting GDPR and SOX compliance. See documentation for details:
- SECURITY_ARCHITECTURE.md: Current authentication flow, baseline security controls, and risk assessment
- COMPLIANCE_ACCEPTANCE_CRITERIA.md: GDPR/SOX requirements mapped to implementation phases
- MFA_IMPLEMENTATION.md: Phase 1 design for multi-factor authentication (TOTP, SMS, WebAuthn, backup codes)
- PHASE_0_DELIVERY_SUMMARY.md: Delivery timeline, risk assessment, and resource requirements
| Phase | Focus | ETA | Key Deliverables |
|---|---|---|---|
| Phase 0 – Foundations & Readiness ✅ | Architecture inventory, baseline controls | ✅ Complete | Security docs, compliance matrix, Grafana placeholders |
| Phase 1 – MFA Stack 🟡 | TOTP, SMS, WebAuthn, recovery codes | Q1 2026 | MFA module, database migrations, GraphQL APIs |
| Phase 2 – Audit & Compliance | Immutable audit logs, data subject rights | Q1-Q2 2026 | Normalized audit schema, export/retention policies |
| Phase 3 – Data Encryption | TDE, app-level crypto, key rotation | Q2-Q3 2026 | EncryptionService, HSM integration, key management |
| Phase 4 – Advanced RBAC | Field-level authorization, policy engine | Q3-Q4 2026 | Role hierarchy, dynamic policies, permission audit |
- ✅ JWT-based authentication (HS256 with entropy validation)
- ✅ Stateless API (no server-side sessions)
- ✅ Route-level authorization enforced in SecurityFilterChain
- ✅ GraphQL operation-level authentication (before data fetchers)
- ✅ Content Security Policy (CSP) headers with nonce generation
- 🟡 Multi-factor authentication (Phase 1 in progress)
- 🔴 Field-level access control (Phase 4)
- 🔴 Transparent Data Encryption (Phase 3)
- Fork the repository and create a feature branch:
git checkout -b feature/awesome - Keep changes focused and covered by tests (
./gradlew test) - Submit a pull request describing the change and its motivation
Distributed under the MIT License. See LICENSE for full text.