ODS Architect Agent

docstore

COMPLIANT
commit 6759be6 prev 15e9eb5 date 2026-03-19 runtime Rust / Actix-web schema docstore port 8081
8
Checks Total
7
PASS
1
WARN
0
FAIL
Improvements in 6759be6 vs 15e9eb5
Audit propagation hardened: log_audit() now returns AppResult<()> and all callers use ? — audit failures abort mutations instead of being silently swallowed. Enforced by the type system; a regression to () would fail to compile.
DocumentResponse DTO introduced: storage_key excluded from all API responses (create, get, list, update). Information disclosure fix — internal storage paths no longer leak to clients.
Metadata validation added: validate_metadata() enforces depth ≤ 5 and keys ≤ 50, called in both domain validation and service layer on create and update paths.
Architecture Checks
01 PASS
Schema Isolation
Exclusively uses the docstore PostgreSQL schema. begin_tenant_tx() issues SET LOCAL search_path TO docstore, public on every transaction. No references to oid, pdf, workflow, or any other service schema detected in production code.
  • src/repository/db.rs:16 — SET LOCAL search_path TO docstore, public
  • src/repository/document.rs:30 — docstore.documents
  • All repositories: docstore.{folders,versions,tags,audit_logs}
02 PASS
Inter-Service Communication
No direct HTTP calls to other ODS services. reqwest is in [dev-dependencies] only — unavailable to production binaries. All state changes propagated via Redpanda CloudEvents on topic events.docstore using rdkafka.
  • Cargo.toml — reqwest in [dev-dependencies] only
  • src/events/producer.rs — rdkafka FutureProducer
  • 5 services publish events: document, folder, version, tag
03 PASS
Multi-Tenancy
tenant_id extracted from JWT claims only (RS256, issuer+audience+exp+nbf validated). RLS enabled on all 6 tables via app.current_tenant_id set per transaction. CloudEvents include tenantid extension attribute.
  • src/api/middleware.rs:8 — Claims.tenant_id from JWT, never body
  • migrations/001_init.sql:100 — RLS on 5 tables
  • migrations/002_audit_log.sql:30 — RLS on audit_logs
  • src/events/producer.rs:29 — tenantid in CloudEvent struct
04 PASS
Directory Structure
All required directories present: domain/, repository/, api/, service/, events/. Domain layer has zero imports from repository or api. API handlers delegate all business logic to service layer — pure HTTP routing.
  • grep: zero `use crate::repository` in src/domain/
  • grep: zero `use crate::api` in src/domain/
  • src/api/documents.rs — delegates to DocumentService only
05 PASS
No Hardcoded URLs
All production endpoints loaded from env vars via AppConfig::from_env(). OID_ISSUER, OID_PUBLIC_KEY, and DATABASE_URL are required with no defaults. URL literals (*.example.com, *.test.internal) appear only in #[cfg(test)] blocks.
  • src/config.rs — OID_ISSUER required, no default
  • src/config.rs — DATABASE_URL required, no default
  • src/config.rs:104,110,122 — test-only example URLs
06 PASS
Header Propagation
No outbound HTTP calls to other services — rule is vacuously satisfied (Redpanda-only inter-service communication). Inbound X-Correlation-Id is extracted from requests, generated as UUID v4 if absent, stored in AuthContext, and propagated to service layer and audit entries.
  • src/api/auth.rs:51 — X-Correlation-Id extraction + generation
  • src/api/documents.rs:20 — correlation_id passed to service
  • docstore.audit_logs.correlation_id — persisted per mutation
07 PASS
CloudEvents Compliance
All v1.0 required fields present: specversion ("1.0"), type (via #[serde(rename = "type")] on event_type), source ("/ods/docstore"), id (UUID v4), time (RFC 3339), tenantid extension, datacontenttype, data. Verified by integration test.
  • src/events/producer.rs:11 — #[serde(rename = "type")]
  • src/events/producer.rs:140 — test_cloud_event_serialization()
  • 9 event type constants cover all entity state changes
08 WARN
Error Handling
No .unwrap() in production code — all in #[cfg(test)] blocks. thiserror-based AppError masks internals from clients. Audit propagation improved this commit (AppResult<()> + ?). Two WARNs remain open: .expect() at startup; no X-Correlation-Id in error response JSON.
  • src/events/producer.rs:51 — .expect() in EventProducer::new [WARN]
  • src/error.rs:44 — error_response() missing correlation_id [WARN]
  • src/service/document_service.rs:152 — log_audit() IMPROVED
Architecture Diagram

Ctrl/Cmd + wheel to zoom — drag to pan — double-click to fit — click ⛶ to open full size

Loading...
Open Deviations
Severity Rule File Line Description
WARN Error Handling src/events/producer.rs 51 .expect("Failed to create Kafka producer") in EventProducer::new() Panics if broker config is invalid at startup. Suggest returning Result<Self, rdkafka::error::KafkaError> to enable graceful startup error handling and unit testing. Carried from 15e9eb5.
WARN Error Handling src/error.rs 44 error_response() JSON body does not include X-Correlation-Id Clients cannot correlate failed requests with server-side logs. Suggest adding correlation_id to error JSON or injecting it via Actix-web middleware that reads it from request context. Carried from 15e9eb5.