Architecture Review — redpanda (ods-events SDK)

Commit: 6f99451 Date: 2026-03-18 Branch: dev Type: Shared Rust Crate (SDK)
Non-Compliant
4
Passed
2
Warnings
2
Failed
8
Total

Architecture Checks

1. Schema Isolation

Pass
No database access in this crate. SDK operates exclusively at the Redpanda/Kafka layer. No SQL queries or cross-schema references exist.

2. Inter-Service Communication

Pass
No direct HTTP calls to ODS services. No reqwest or hyper dependencies. All inter-service communication flows through Redpanda topics.

3. Multi-Tenancy

Pass
tenant_id is a required parameter on CloudEvent::new() and Producer::emit(). tenantid extension attribute is validated as non-empty.
  • src/event.rs:37 — CloudEvent::new() requires tenant_id: Uuid
  • src/event.rs:77-86 — validate() enforces tenantid non-empty
  • src/producer.rs:68-69 — emit() requires tenant_id + correlation_id
  • src/producer.rs:90 — tenant_id logged in tracing span

4. Directory Structure

Fail
Flat src/ directory with 12 .rs files. Expected structure includes src/domain/, src/repository/, src/api/, src/events/ subdirectories. While this is an SDK, logical grouping would improve maintainability.
  • src/ — 12 files: lib.rs, event.rs, consumer.rs, producer.rs, topic.rs, provisioning.rs, health.rs, metrics.rs, alerting.rs, monitoring.rs, replication.rs, error.rs
  • No subdirectories exist

5. No Hardcoded URLs

Warn
Real infrastructure IP 10.0.0.3:9092 found in lib.rs docstring. Test code localhost references are acceptable. No hardcoded URLs in production code paths.
  • src/lib.rs:16 — docstring: ProducerConfig::new("10.0.0.3:9092", ...)

6. Header Propagation

Warn
No HTTP header propagation code. Expected for an SDK crate — header handling (X-Tenant-Id, X-Correlation-Id, X-Source-Service) is the consuming service's responsibility. The crate propagates tenant_id and correlation_id via CloudEvent extension attributes instead.
  • src/event.rs:19-20 — tenantid + correlationid as CloudEvent extensions
  • No HTTP layer in this crate

7. CloudEvents Compliance

Pass
Full CloudEvents v1.0 implementation. Required attributes: specversion (1.0), type, source, id (UUID v4), time (ISO 8601). ODS extensions: tenantid, correlationid. Topic naming: events.{source}.
  • src/event.rs:10-21 — CloudEvent struct with all required fields
  • src/event.rs:33-55 — new() sets specversion='1.0', UUID v4 id, ISO time
  • src/event.rs:57-91 — validate() checks all required attributes
  • src/event.rs:93-95 — topic() returns 'events.{source}'

8. Error Handling

Fail
CORRECTED: Multiple .unwrap() calls found in PRODUCTION code. The test module in monitoring.rs starts at line 320 — all .unwrap() calls at lines 88-239 are in PrometheusExporter::export_cluster_metrics() and export_consumer_lag() production methods. Writing to a String is infallible but using .unwrap() violates the no-unwrap-in-production rule. The EventError enum and Result returns elsewhere are excellent — only monitoring.rs is non-compliant.
  • src/monitoring.rs:88 — writeln!(...).unwrap() in export_cluster_metrics() [PRODUCTION — test module starts at line 320]
  • src/monitoring.rs:94,101,109,115,122,130,136,143 — additional writeln!().unwrap() in export_cluster_metrics()
  • src/monitoring.rs:157,163,171,182,191 — writeln!().unwrap() in per-topic loop
  • src/monitoring.rs:211,217,227,239 — writeln!().unwrap() in export_consumer_lag()
  • src/replication.rs:284 — msg.key().unwrap_or_default() [ACCEPTABLE — safe fallback]
  • src/error.rs:1-22 — EventError enum with 6 variants via thiserror [GOOD]

Deviations

SeverityRuleLocationDescription
FAIL Directory Structure src/ Flat module structure. 12 .rs files in root with no subdirectories. Organize into logical groupings (events/, monitoring/, replication/).
FAIL Error Handling src/monitoring.rs:88-239 20+ .unwrap() calls in PrometheusExporter production methods (test module starts at line 320). Writing to String is infallible but .unwrap() violates no-panic rule. Fix: use let _ = writeln!(...) or .expect("write to String is infallible").
WARN No Hardcoded URLs src/lib.rs:16 Docstring example uses real infra IP '10.0.0.3:9092'. Replace with 'redpanda:9092' or 'localhost:9092'.
WARN Missing Specs Architecture reference docs not found: context/architecture.md, business-rules.md, specs/redpanda/spec.md.
WARN Missing Migrations No SQL migration files found. CLAUDE.md references schema 'redpanda' with RLS — migrations should be tracked.
WARN Missing Integration Tests No tests/ directory. All tests are inline #[cfg(test)]. Integration tests with testcontainers should be separated.

ODS Architecture Context

graph TB
    subgraph Products
        DS[DocSign
Tauri/React/Rust] OS[OSIGN SaaS
.NET 9/PostgreSQL] end subgraph SharedServices["Shared Services"] DOCS[DocStore] PDF[PDF Engine] WF[Workflow Engine] FORM[Form Engine] NOTIF[Notification Hub] AGENDA[Agenda] SMAIL[SecureMail] DEDIT[DocEditor] end subgraph EventBus["ods-events SDK (this crate)"] direction TB PRODUCER[Producer
CloudEvents v1.0] CONSUMER[Consumer
Group-based] TOPICS[Topic Registry
19 topics defined] MONITOR[Monitoring
Prometheus + Webhooks] REPL[Replicator
Cross-cluster] end subgraph Redpanda["Redpanda Cluster"] ET_OID[events.oid] ET_DS[events.docstore] ET_PDF[events.pdf] ET_WF[events.workflow] ET_NOTIF[events.notifications] ET_FORMS[events.forms] ET_BILLING[events.billing] ET_SMAIL[events.securemail] CDC[cdc.* topics
7 topics] BILL[billing.* topics
4 topics] end subgraph DataPlatform["Data Platform (Zero-ETL)"] DBZ[Debezium CDC] CH[ClickHouse OLAP] MB[Metabase BI] end subgraph Infra["Infrastructure"] OID[OID Identity
OIDC/JWT] PG[(PostgreSQL 17
schema per service)] end DS & OS --> PRODUCER SharedServices --> PRODUCER PRODUCER --> Redpanda Redpanda --> CONSUMER CONSUMER --> SharedServices CDC --> DBZ --> CH --> MB OID -.->|JWT with tenant_id| PRODUCER SharedServices --> PG style EventBus fill:#1e40af,stroke:#3b82f6,color:#fff style Redpanda fill:#7f1d1d,stroke:#ef4444,color:#fff

Topic Registry (19 topics)

graph LR
    subgraph EventTopics["Event Topics (3 partitions, 7d retention)"]
        E1[events.oid]
        E2[events.docstore]
        E3[events.pdf]
        E4[events.workflow]
        E5[events.notifications]
        E6[events.forms]
        E7[events.billing]
        E8[events.securemail]
    end

    subgraph CDCTopics["CDC Topics (1 partition, 3d retention, compact)"]
        C1[cdc.oid.users]
        C2[cdc.oid.tenants]
        C3[cdc.docstore.documents]
        C4[cdc.docstore.versions]
        C5[cdc.billing.subscriptions]
        C6[cdc.billing.invoices]
        C7[cdc.billing.usage]
    end

    subgraph BillingTopics["Billing Topics (3 partitions, 30d retention)"]
        B1[billing.usage.raw]
        B2[billing.usage.aggregated]
        B3[billing.invoices.generated]
        B4[billing.payments.received]
    end

    style EventTopics fill:#1e3a5f,stroke:#3b82f6,color:#e2e8f0
    style CDCTopics fill:#3b1f2b,stroke:#ec4899,color:#e2e8f0
    style BillingTopics fill:#3b2f1f,stroke:#f59e0b,color:#e2e8f0