Bank Teller
Sign In
Back to About

Tech Stack

The full technology stack powering Mithaq Branch Teller.

Frontend

Next.js 16.2 · React 19 · Tailwind CSS 4

App Router with server components and TypeScript strict mode. Runs inside Docker on the Synology NAS. Browser calls relative /api/*; Next.js rewrites to teller_api_dev:5200 server-side — NEXT_PUBLIC_API_URL intentionally unset.

API

.NET 9 · Minimal API · EF Core 9

Endpoint-based routing — no controllers. Entity Framework Core manages schema migrations; MigrateAsync runs on startup. Three auth modes: USE_DEV_AUTH=true → USE_KEYCLOAK_AUTH=true → Entra ID (prod). Priority is evaluated in that order.

Database

PostgreSQL 15 · teller_refactor

Three schemas: core (transactional state — Drawers, Vaults, BranchApprovals), admin (config — Branches, ApprovalPolicies, CashLimits), audit (immutable logs — BranchAuditLogs). All monetary columns are numeric(19,6). Per-entity DB separation via TellerDb-{EntityId} connection string — zero code change required.

Auth

Keycloak 26.2 · PKCE · realm: mithaq-bank

Browser uses PKCE authorization code flow — no client secret in the browser. Custom JWT claims: bank_entity, bank_branch_id. Split-brain fix: internal Docker URL used for JWKS fetch; public DDNS URL appears in the token's iss claim. IssuerSigningKeyResolver handles the mapping with a 10-min key cache.

Policy

OPA sidecar · banking.rego · ABAC

Open Policy Agent sidecar gates all POST /transactions/*, /vault/*, /branch/*. Cash limits are data-driven per entity + currency, pushed from PostgreSQL to OPA at startup and after every admin mutation. Hard-deny when OPA is unreachable (fail-closed). Rego policy live-editable via the Admin Portal.

Observability

OpenTelemetry · SigNoz v0.125.1 EE

.NET API exports traces + metrics + logs to SigNoz via gRPC :4317; EF Core SQL queries are visible as spans (SetDbStatementForText=true). Next.js exports via HTTP :4318 (@vercel/otel). Keycloak traces via KC_TRACING_ENABLED. PostgreSQL metrics via otel-collector scraping :5432 every 30s. 3 dashboards, 5 alert rules, syslog container logs from all services.

ESB

.NET 9 mock · port 5100 · CBS adapter layer

Enterprise Service Bus decouples the teller platform from the Core Banking System. The mock simulates CBS responses for full end-to-end testing. EsbClientFactory resolves the correct EsbClient per entity from config (Esb__Entities__{EntityId}__BaseUrl). Pluggable — swap the mock for any real CBS adapter without touching the teller API.

Deployment & Infrastructure

Runtime

All services run in Docker containers managed by Compose on a Synology NAS. Services share a banking-net Docker network. Never start app, API, web, Keycloak, or OPA locally.

E2E Testing

Playwright suite runs on an OCI cloud VM (VM.Standard.E5.Flex, 4 OCPU / 48 GB, Abu Dhabi region). Auto-started, tested against the live Synology deployment, then stopped per run to save cost.

Service Ports

API: 5200 · Web: 3012 (Next.js 3002 inside) · ESB mock: 5100 · Keycloak: 8871 · OPA: 8181 · SigNoz: 3301

Keycloak split-brain

KEYCLOAK_AUTHORITY is the internal Docker URL (for JWKS fetch); Keycloak__Issuer is the external DDNS URL (appears in the token iss claim). Both env vars must remain set — removing either breaks auth.