Skip to content

System Design

Microservices Architecture

1. Project Overview


TrafficGrid consolidates vehicle records, traffic offences, parking fines, and payment processing for Harare into a single unified digital platform. Officers log offences via mobile. Citizens view their vehicle records and pay fines electronically. All actions are audited.

This document is version 2.1, superseding v2.0. The core microservices architecture is unchanged. This revision retires fines-service from the service inventory — it was planned but never built as a separate deployed process; fines and parking_tickets are a permanent part of payments-service instead (see Data Model.md §4.11 for the rationale) — and adds the trafficgrid.users Kafka topic introduced alongside that work. (v2.0 corrected the service inventory to make notifications-service a dedicated service rather than co-located in payments-service, removed system-parameters from the shared-library category, and added Kafka for all asynchronous communication.)

2. Service Inventory


The system is composed of 9 running processes. core-service is a shared Maven dependency (published to GitHub Packages) — it is not a running process.

Service Port Responsibility
discovery-service 8761 Eureka service registry - all services register here on startup
config-server 8888 Centralised configuration served to all services from Git or classpath
api-gateway 8080 Single entry point — auth validation, routing, rate limiting, SSL termination
auth-service 8081 User registration, login, JWT issuance, refresh token rotation, RBAC
audit-service 8082 Receives audit events and persists immutable audit_logs records
system-parameters-service 8083 settings in the system like currencies, notification channels, organizations, fine categories
vehicle-service 8084 vehicles, vehicle documents, citizen vehicle records
payments-service 8086 fines, parking tickets, payments, payment items
notifications-service 8088 notifications, notification preferences

fines-service retirement

fines-service (formerly port 8085) was planned as a dedicated service but was never built, and is no longer part of the architecture. payments-service permanently owns fines and parking tickets in addition to payments and payment items. Fines and the payments that settle them are tightly coupled: a successful payment must mark its fines PAID, and consolidating them keeps that state change inside one service and one schema instead of crossing a service boundary. The trafficgrid.fines topic and its fine.created / fine.status.updated events are unchanged; only the publisher is now payments-service. Fine categories remain in system-parameters-service. Port 8085 is unassigned.

core-service

core-service is a shared JAR dependency published to GitHub Packages. It is imported by all services as a Maven dependency. It is not deployed or registered with Eureka. It contains: response envelope shape, pagination wrappers, common exception types, and shared HTTP error handling. Domain-specific concerns (enums, entity classes, business logic) must never be placed in core-service — each service owns its own domain types unless it's explicitly needed to be a global dependency.

3. Architecture Style


Each domain service owns its own PostgreSQL schema (or separate database). No service queries another service's database directly. Cross-service data is accessed through HTTP API calls (via OpenFeign) or consumed via asynchronous events published to Kafka topics.

All client traffic (mobile, web, officer app) enters exclusively through the API Gateway. The gateway validates JWT tokens and forwards decoded claims as request headers (X-User-Id, X-User-Role, X-Organisation-Id) so downstream services do not need to call auth-service on each request.

3.1 Communication Patterns

Pattern When Used Example
Synchronous Rest (OpenFeign) Query-response where the caller needs data immediately payments-service calls vehicle-service to verify a vehicle exists before issuing a fine
OpenFeign to system-parameters Runtime reference data lookup Any service calls system-parameters to resolve currencies, notification channel config, or fine category details
Async Kafka events State changes that other services react to independently payments-service publishes to the trafficgrid.payments topic; notifications-service and audit-service both consume from it
Gateway header forwarding Propagating auth context to downstream services Gateway decodes JWT and sets X-User-Role: ZRP_OFFICER on every forwarded request

3.2 Kafka — Message Architecture

TrafficGrid uses Kafka topics, partitioned by aggregate ID, to decouple producers from consumers. A producer publishes to a topic and does not know which services consume the message; any service can subscribe by starting a new consumer group without requiring any change to the publisher. Full design detail — partitioning strategy, consumer groups, delivery semantics, retry/dead-letter handling — lives in the dedicated Kafka Design page. The summary below covers only the topic inventory.

Topic Design

Topic Partition Key Description
trafficgrid.vehicles vehicle_id Vehicle domain events
trafficgrid.fines fine_id Fine and parking ticket events
trafficgrid.payments payment_id Payment transaction events
trafficgrid.users entity_id / user_id User, role and permission management events
trafficgrid.notifications notification_id Notification dispatch commands (internal)

Events By Topic

Topic Event Type Publisher Consumers Trigger
trafficgrid.fines fine.created payments-service audit-service, notifications-service New fine issued against a vehicle
trafficgrid.fines fine.status.updated payments-service audit-service, notifications-service Fine cleared or cancelled by an admin
trafficgrid.fines fine.dispute.opened payments-service audit-service, notifications-service (planned) Citizen disputes a fine
trafficgrid.fines fine.dispute.withdrawn payments-service audit-service, notifications-service (planned) Citizen withdraws their dispute
trafficgrid.fines fine.dispute.decided payments-service audit-service, notifications-service (planned) Reviewer upholds or rejects a dispute
trafficgrid.payments payment.success payments-service payments-service (settles covered fines), audit-service, notifications-service Payment confirmed by provider
trafficgrid.payments payment.failed payments-service audit-service, notifications-service Payment declined or failed
trafficgrid.vehicles vehicle.document.expiry vehicle-service notifications-service Vehicle document within 30 days of expiry
trafficgrid.users user.created auth-service audit-service User account created
trafficgrid.users user.deactivated auth-service audit-service User account deactivated
trafficgrid.users role.created auth-service audit-service Role created
trafficgrid.users role.updated auth-service audit-service Role updated
trafficgrid.users role.deleted auth-service audit-service Role deleted
trafficgrid.users role.permissions.assigned auth-service audit-service Permissions assigned to a role

trafficgrid.users carries auth-service's own state-changing actions (user and role/permission management — see Roles and Permissions.md) and replaces its earlier single audit.events topic. Session lifecycle actions (login, logout, access-token refresh) deliberately publish no events.

Consumer Group Pattern Each consumer service subscribes with its own consumer group (e.g. notifications-service, audit-service). Every consumer group gets its own copy of every event on the topics it subscribes to, independent of what other groups consume — so adding a new consumer never requires changes to the publisher. Within a group, partitions are divided across instances, which is how a service scales horizontally without duplicate processing.

notifications-service Communication Model notifications-service is event-driven for sending notifications and exposes REST endpoints for notification history. It consumes events from Kafka (fine.created, fine.status.updated, payment.success, payment.failed, vehicle.document.expiry) to trigger outbound messages. No other service calls it directly to send a notification. REST endpoints (GET /notifications, GET/PUT /notifications/preferences) are called directly by authenticated clients via the API Gateway.

4. Stakeholders & Integrations


4.1 Organizations in Scope

Organisation Role Integration Type Status
ZRP Issues traffic fines. Officers log via mobile app. Manual entry — officer mobile app Active
City Council (Harare) Issues council fines and violations. Manual entry — council officer portal Active
ZINARA Source of vehicle licence and registration data. REST API integration (mocking for the meantime) Planned
VTS (Vehicle Theft Squad) Verifies VIN numbers and vehicle ownership. REST API integration (mocking for the meantime) Planned
City Parking Issues parking tickets. REST API integration (mocking for the meantime) Planned
System Provider (ShiftFocus) Builds and administers the platform. Full super-admin access Active

4.2 Out of Scope — Phase 1

  • ZIMRA — vehicle import duties and tax clearance
  • Foreign vehicle registration
  • Insurance provider API integration

5. User Roles


Role Internal Enum Description
General Public / Citizen CITIZEN Self-registered. Views own vehicles, fines, renewal reminders. Pays online.
ZRP Officer ZRP_OFFICER Logs traffic fines from mobile. Searches vehicle history. Cannot see unrelated records.
City Council Officer COUNCIL_OFFICER Logs council fines. Queries outstanding fines on a vehicle.
City Parking Officer PARKING_OFFICER Manages parking tickets. Scoped to parking data only.
Authority Admin AUTHORITY_ADMIN Supervisor within one organisation. Read-only reports scoped to their org.
Super Admin SUPER_ADMIN Full system access. User management, cross-authority reporting, audit log access.

6. Functional Requirements

6.1 Vehicle Management

  • Officers can create vehicle records when issuing fines against vehicles not yet in the system
  • Citizens link vehicles to their account by number plate
  • Each vehicle has a dashboard: registration details, active fines, linked documents, renewal dates
  • Vehicle data sourced from VTS and ZINARA via API (dummy data during develo pment)
  • Vehicle documents (licence, insurance, ZBC, fitness) tracked with expiry dates
  • Citizens can self-declare document expiry dates until ZINARA integration is live

6.2 Fines

  • ZRP and Council officers issue fines against a vehicle from their mobile device
  • Fine amount is copied from the category at issue time and frozen — never retroactively changed
  • Each fine has a status: PENDING, PAID, CLEARED, DISPUTED, CANCELLED
  • Default payment window: 30 days from issue date
  • Admins can manually clear or cancel fines with a mandatory reason for audit purposes
  • Citizens can dispute a pending fine once; an admin of the issuing organisation upholds (fine cleared) or rejects (fine payable again, with at least 7 days to pay) the dispute
  • Officers can record cash payments on the spot, creating an audited paper trail

6.3 Parking Tickets

Status: Planned — pending City Parking API integration. parking_tickets owned by payments-service.

  • Parking tickets sync from City Parking's system or are entered manually by parking officers
  • Tickets appear on the relevant vehicle's record
  • Tickets are payable through the same payments infrastructure as fines

6.4 Payments

  • Supported methods: EcoCash , bank transfer (swipe) , cash recorded by officer
  • A single payment can settle multiple fines and/or parking tickets in one transaction
  • Payment is idempotent — duplicate attempts using the same idempotency key are safely rejected
  • payment.success Kafka event automatically marks associated fines as PAID
  • Full payment receipts generated and accessible to the vehicle owner
  • Partial payments are out of scope for Phase 1

6.5 Notifications

  • Citizens receive notifications when a new fine is issued against their vehicle
  • Citizens receive reminders for upcoming vehicle document expiry (30 days before)
  • Citizens receive confirmation when a payment succeeds
  • Notification channels are configured in system-parameters; citizens choose their preferred channel per their notification_preferences record
  • Notification history is queryable via REST. Sending is triggered exclusively by Kafka events.

6.6 Audit & Transparency

  • Every write action logged with: actor, role, organisation, timestamp, IP, before/after state
  • Audit logs are immutable — never updated or deleted
  • Super admins access full audit log; authority admins see logs scoped to their organisation
  • Includes: fine creation, payment recording, manual clearances, user account changes

7. Non-functional requirements

Concern Requirement
Security JWT-based auth. RBAC enforced at gateway and within each service. Officer mobile sessions protected.
Rate Limiting API gateway enforces per-user and per-role rate limits on all endpoints.
Idempotency Payment endpoints are idempotent. Duplicate requests for the same fine never result in double charges.
Race Conditions Concurrent payment attempts on the same fine handled via optimistic locking or distributed lock on the fine ID.
Scalability Services are independently deployable and horizontally scalable. Initial scope is Harare — national expansion must not require re-architecture.
Auditability Every state-changing action emits an audit event consumed by audit-service. Logs stored as JSONB snapshots.
Availability Fine lookup and payment processing target high availability. Degraded mode acceptable for notifications.
Offline Support Officer mobile app supports offline fine logging with queue-and-sync when connectivity is restored.

8. Client Interfaces

Interface Users Notes
Citizen Mobile App General Public Android and iOS. Vehicle dashboard, fines, payments, renewal reminders. Mobile-first
Officer Mobile App ZRP and Council officers Android. Offline-capable fine logging. Secure login. Syncs on connectivity restore.
Web Portal Authority admins Query vehicle records, view scoped reports, manage manual clearances.
Admin Portal SUPER_ADMIN Full system oversight, user management, audit log access, cross-authority reporting.

USSD and WhatsApp interfaces are planned for a future phase to increase accessibility for users without smartphones.

9. Infrastructure


All infrastructure (PostgreSQL, Redis, Kafka) runs in Docker containers. Services themselves can run as plain Java processes connecting to containerised infrastructure, or all 9 services can be containerised and orchestrated via Docker Compose.

Component Docker Image
PostgreSQL postgres:16-alpine — one container, multiple databases or schemas per service
Redis redis:7-alpine
Kafka apache/kafka:3.7.0 — single-broker KRaft mode (no ZooKeeper)

A docker-compose.yml in the project root should define these three infrastructure services. Java services connect to them via config-server properties (spring.datasource.url, spring.kafka.bootstrap-servers, etc.).

9.2 Production (Future)

  • Containerisation: Docker — each service packaged as an image
  • Orchestration: Kubernetes — manages deployment, scaling, and self-healing
  • CI/CD: GitHub Actions — automated testing, image build, and K8s deployment on push
  • Message Broker: Kafka cluster — multiple brokers, topics replicated (replication factor ≥ 3) for HA
  • Database: PostgreSQL per service (separate instances in production)
  • API Documentation: Swagger / OpenAPI auto-generated from Spring Boot annotations

10. Open Questions & Risk

Item Notes
Data Ownership Vehicle and offence data legally belongs to ZRP and ZINARA. Platform acts as operational source of truth pending formal data governance agreements.
ZINARA / VTS API Access Integration feasibility and data access agreements not yet confirmed. Dummy data used during development.
City Parking Sync City Parking system exists but API availability is unconfirmed.
Officer Adoption UX and offline capability are critical. If the mobile app is cumbersome, officers will not use it.
Cash Payment Integrity Cash payments recorded by officers carry corruption risk. Audit trail mitigates this. Supervisory approval step may be needed.
Regulatory Approval A government body must formally oversee the system before official deployment. Security requirements may change significantly.
Concurrent Users Expected load not yet estimated. Architecture is designed to scale; load testing benchmarks to be defined.

Future Backlog


  • ZIMRA integration — vehicle import duties and tax clearance
  • Foreign vehicle handling — separate category and workflow
  • Partial and instalment payments
  • USSD interface — for users without smartphones
  • WhatsApp notifications — additional notification channel
  • National expansion — beyond Harare
  • Insurance provider API integration
  • Full regulatory compliance framework and data governance agreements
  • Offline sync conflict resolution strategy for officer mobile app
  • Database backup and point-in-time recovery
  • Redis high availability — current single instance is a SPOF for the token blocklist
  • Rate limiting on public auth endpoints