Non-Compliant
Overall result
7 of 8 checks pass — 1 warning remains
87.5% compliant — improving trend (was 75% at 3e48f66)
SEC-FIX-2 resolved the Error Handling warning. Only the Directory Structure deviation (service layer bypass in split/merge/rotate) remains.
7
Checks Passed
of 8 total
1
Warnings
Directory Structure
2
Fixed (SEC-FIX-2)
vs prior review
0
Hard Failures
no FAIL checks
Compliance Checks — 8 rules
PASS
Schema Isolation
Uses only the pdf-engine schema. RLS enforced per-transaction via set_tenant_context(). No cross-schema table references found.
  • repository/mod.rs — set_config scoped per transaction
  • job_repo.rs, template_repo.rs — tenant_id in all WHERE clauses
  • No docstore / workflow / oid schema refs in source
PASS
Inter-Service Comms
No HTTP client libraries present (reqwest, hyper, ureq). All inter-service communication via Redpanda using rdkafka on topic events.pdf-engine.
  • Cargo.toml — no HTTP client dependencies
  • events/producer.rs — rdkafka FutureProducer only
  • No ODS service base URLs in production code paths
PASS
Multi-Tenancy
tenant_id extracted from JWT claims only. CloudEvents include tenantid extension on all 12 event types. All business tables carry tenant_id.
  • api/extractors.rs — JWT claims to AuthenticatedUser.tenant_id
  • events/producer.rs — tenantid in CloudEvent struct
  • Soft delete filter: deleted_at IS NULL on all queries
WARN
Directory Structure
Required dirs present. Domain correctly imports zero repository/API code. Templates and Jobs use service layer correctly. However, split/merge/rotate handlers bypass the service layer entirely.
  • api/split.rs:11 — imports processing::split directly
  • api/split.rs — emits CloudEvents from API handler
  • No SplitService / MergeService / RotateService in src/service/
  • api/merge.rs, rotate.rs — same bypass pattern
PASS
No Hardcoded URLs
No production service URLs embedded in source. All external endpoints read from environment. URL literals confined to test helpers only.
  • main.rs — DATABASE_URL, REDPANDA_BROKERS from env
  • Test URLs (oid.ods.dev, s3/output.pdf) inside #[test] blocks
PASS
Header Propagation
No outbound HTTP calls exist (rule N/A for HTTP headers). X-Correlation-Id extracted from inbound requests and propagated to CloudEvents via the correlationid extension field. Fixed by SEC-FIX-2.
  • api/extractors.rs:254 — extract_correlation_id()
  • api/split.rs:46, merge.rs, rotate.rs — propagation added
PASS
CloudEvents v1.0
All events include specversion, id, source, type, time, tenantid, correlationid, and datacontenttype. 12 factory methods covering template, job, split, merge, and rotate lifecycle.
  • events/producer.rs — CloudEvent struct with all required fields
  • source = /ods/pdf-engine, type = ods.pdf-engine.*
  • topic: events.pdf-engine via RedpandaProducer
PASS
Error Handling
No unwrap() in production code. InMemoryProducer mutex calls converted to .expect() with context (SEC-FIX-2). PdfError enum sanitizes DB internals from client responses.
  • events/producer.rs:232 — .expect("poisoned") fixed
  • error.rs — Conflict/Internal sanitized, no schema leak
  • All remaining unwrap() verified inside #[test] blocks only
Architecture Diagram

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

Loading...
Correct path (via service layer) Violation (bypasses service layer / direct emit) solid border — compliant dashed border — missing / violation
Remaining Deviations (1 rule, 3 files)
Rule File Line Description Fix Required
Directory Structure src/api/split.rs 11 split_pdf_handler() imports and directly calls processing::split::split_pdf() and emits split.failed / split.completed events from the API handler. Orchestration logic belongs in a SplitService, not the API layer. Create src/service/split_service.rs. Move processing call + event emission into SplitService. Handler calls service only.
Directory Structure src/api/merge.rs merge_pdf_handler() directly calls processing::merge::merge_pdfs() and emits merge.completed / merge.failed events from the API handler. Same bypass pattern as split.rs. Create src/service/merge_service.rs. Covered by the same fix cycle.
Directory Structure src/api/rotate.rs rotate_pdf_handler() directly calls processing::rotate::rotate_pdf() and emits rotate.completed / rotate.failed events from the API handler. Same bypass pattern as split.rs. Create src/service/rotate_service.rs. Covered by the same fix cycle.
SEC-FIX-2 Changes — commit 7d59f13
Progress since 3e48f66: SEC-FIX-2 resolved 2 of the 3 previously reported deviations, raising the compliance score from 6/8 (75%) to 7/8 (87.5%). The service layer bypass for split/merge/rotate was not addressed in this cycle and remains the sole outstanding item.
Issue Before (3e48f66) After (4e2570c) Status
InMemoryProducer mutex
events/producer.rs:232
.unwrap() — silent panic on mutex poison, in production code path .expect("InMemoryProducer events mutex poisoned") — contextual panic message on all three call sites FIXED
X-Correlation-Id propagation
api/split.rs, merge.rs, rotate.rs
Events used auto-generated corr-{uuid} — inbound correlation IDs were dropped, breaking distributed tracing extract_correlation_id(&req) called in all three handlers; result propagated to CloudEvents correlationid field FIXED
Service layer bypass
api/split.rs, merge.rs, rotate.rs
API handlers call processing directly and emit events from the API layer Same — not addressed in SEC-FIX-2 OPEN