Skip to content

Latest commit

 

History

History
127 lines (106 loc) · 4.04 KB

File metadata and controls

127 lines (106 loc) · 4.04 KB

Architecture

C4 and component views for RetailBankingCore. Portfolio service, not a production bank core.

C4 Context

C4Context
  title Retail Banking Core - System Context
  Person(user, "Banking user", "Registers, opens accounts, transfers money")
  System(core, "Retail Banking Core", "JWT auth, accounts, double-entry transfers, domain events")
  SystemDb(pg, "PostgreSQL", "Users, accounts, transfers, ledger, outbox")
  SystemDb(redis, "Redis", "Distributed transfer rate limit")
  System_Ext(kafka, "Kafka", "Domain event bus")
  Rel(user, core, "HTTPS / JSON")
  Rel(core, pg, "JDBC via HikariCP")
  Rel(core, redis, "Token bucket Lua")
  Rel(core, kafka, "Outbox relay publish")
Loading

C4 Container

C4Container
  title Retail Banking Core - Containers
  Person(user, "Banking user")
  Container(api, "Spring Boot API", "Java 17 / Spring Boot 3.3", "Auth, accounts, transfers, outbox relay, Actuator")
  ContainerDb(pg, "PostgreSQL 16", "Flyway V1-V4", "Durable store + transactional outbox")
  ContainerDb(redis, "Redis 7", "In-memory", "Per-user transfer rate limit")
  Container_Ext(kafka, "Apache Kafka", "Message bus", "banking.domain-events topic")
  Container_Ext(ci, "GitHub Actions", "CI", "mvn verify + Testcontainers")
  Rel(user, api, "HTTPS")
  Rel(api, pg, "SQL")
  Rel(api, redis, "EVAL token-bucket")
  Rel(api, kafka, "producer (outbox relay)")
  Rel(ci, api, "build / test")
Loading

Component view (inside the API)

flowchart TB
  subgraph http [HTTP]
    AuthC[AuthController]
    AccC[AccountController]
    TrfC[TransferController]
    Health[/actuator/health]
  end

  subgraph security [Security]
    JwtF[JwtAuthenticationFilter]
    RateF[RateLimitFilter Redis]
  end

  subgraph app [Services]
    AuthS[AuthService]
    AccS[AccountService]
    TrfS[TransferService]
    JwtS[JwtService]
    OutboxPub[OutboxEventPublisher]
    Relay[OutboxRelay]
  end

  subgraph data [Persistence]
    Users[(app_users)]
    Accounts[(accounts)]
    Transfers[(transfers)]
    Ledger[(ledger_entries)]
    Outbox[(outbox_events)]
  end

  subgraph infra [Infrastructure]
    Redis[(Redis)]
    Kafka[(Kafka topic)]
  end

  AuthC --> AuthS --> Users
  AuthS --> JwtS
  AccC --> AccS --> Accounts
  AccS --> Ledger
  AccS --> OutboxPub
  TrfC --> RateF --> TrfS
  RateF --> Redis
  TrfS --> Accounts
  TrfS --> Transfers
  TrfS --> Ledger
  TrfS --> OutboxPub
  OutboxPub --> Outbox
  Relay --> Outbox
  Relay --> Kafka
  JwtF --> JwtS
Loading

Domain events (transactional outbox)

  1. Business TX (transfer / account change) writes ledger + audit and an outbox_events row.
  2. After commit, OutboxRelay claims with short TX (claimed_at, FOR UPDATE SKIP LOCKED).
  3. Kafka publish runs outside that TX (no long-held row locks under network I/O).
  4. Second short TX marks published_at (at-least-once; de-dupe on eventId).
  5. Stale claims are reclaimable; poison rows after max attempts are logged.
Event type Aggregate When
ACCOUNT_OPENED ACCOUNT Customer account open
ACCOUNT_FROZEN / UNFROZEN / CLOSED ACCOUNT Status change
TRANSFER_POSTED TRANSFER Successful transfer (not idempotent replay)
TRANSFER_REVERSED TRANSFER Compensating reversal

Rate limit

  • Redis Lua token bucket on POST /api/transfers and POST /api/transfers/{id}/reverse.
  • Key: authenticated username (or remote IP if unauthenticated).
  • Default fail mode CLOSED: Redis down returns HTTP 503 (no open flood window).

Ledger rules

  • OPENING: HOUSE funding DEBIT + customer CREDIT, shared journal_id
  • TRANSFER / REVERSAL: paired lines with transfer_id; reversal never mutates old rows
  • Ledger and audit tables are append-only (Postgres triggers)
  • accounts.balance = Σ CREDIT − Σ DEBIT; global Σ DEBIT = Σ CREDIT

Runtime packaging

  • Local: Compose (Postgres + Redis + Kafka + optional app container)
  • CI: JVM + Testcontainers (Postgres, Redis, Kafka)
  • Schema only via Flyway (V1V5), Hibernate ddl-auto=validate
  • OpenAPI UI: /swagger-ui.html