@startuml !include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml LAYOUT_TOP_DOWN() title LOTTY Backend - C4 Component Container_Boundary(api, "Backend Container (Django + Django Ninja)") { Component(decision_endpoint, "Decision Endpoint", "api/v1/decision/endpoints.py", "POST /api/v1/decide") Component(decision_service, "Decision Service", "apps/decision/services.py", "Flag lookup, targeting DSL, limits/conflicts, hash-based assignment, decide-result cache, sync/async decision persistence") Component(events_endpoint, "Events Endpoint", "api/v1/events/endpoints.py", "POST /api/v1/events") Component(events_service, "Events Service", "apps/events/services.py", "Validation, dedup, exposure/conversion attribution, pending promotion") Component(events_tasks, "Events Tasks", "apps/events/tasks.py", "persist_decision, cleanup pending") Component(reports_endpoint, "Reports Endpoint", "api/v1/reports/endpoints.py", "GET /reports/{experiment_id}") Component(reports_service, "Reports Service", "apps/reports/services.py", "Per-variant metrics (ratio/count/average/percentile)") Component(guardrails_service, "Guardrails Service", "apps/guardrails/services.py", "Threshold checks, auto pause/rollback") } ContainerDb(db, "Relational DB", "PostgreSQL / SQLite", "Flags, experiments, variants, decisions, events, exposures") Container(cache, "Cache + Broker", "Valkey / Redis / LocMem", "Flag/active experiment/decide-result cache, Celery broker") Container(worker, "Celery Worker / Beat", "Celery", "Periodic guardrails/notifications/cleanup + async decision persistence") Rel(decision_endpoint, decision_service, "Delegates") Rel(decision_service, cache, "Reads cached flag / active experiment") Rel(decision_service, db, "Reads variants, writes Decision") Rel(events_endpoint, events_service, "Delegates batch") Rel(events_service, db, "Writes Event / Exposure / PendingEvent") Rel(events_tasks, db, "Writes Decision async") Rel(reports_endpoint, reports_service, "Builds report") Rel(reports_service, db, "Reads attributed events / exposures") Rel(guardrails_service, reports_service, "Uses metric calculations") Rel(guardrails_service, db, "Writes triggers, updates experiment status") Rel(worker, guardrails_service, "Periodic check_all") @enduml