# Drop Srbija v2 — Tech Stack

# Drop Srbija v2 — Tech Stack

**ALAI Standard Stack (CEO Decision 2026-03-17)**

## Backend

| Component | Version | Purpose |
|-----------|---------|---------|
| **Kotlin** | 2.1.0 | Primary backend language (ALAI standard) |
| **Ktor** | 3.1.2 | Async HTTP framework, netty transport |
| **Exposed** | 0.58.0 | Kotlin-native ORM, DSL-based |
| **PostgreSQL** | 16 | Primary database (port 5436) |
| **Flyway** | 10.21.0 | Database migrations (22 scripts V1-V22) |
| **HikariCP** | 6.2.1 | Connection pooling |
| **Koin** | 4.0.2 | Dependency injection |
| **JWT (nimbus-jose-jwt)** | 9.46.1 | Authentication tokens (HS256) |
| **Kotest** | 5.9.1 | Testing framework (79 test files, 617 tests) |
| **Testcontainers** | 1.20.4 | Integration tests (PostgreSQL in Docker) |

## Frontend

| Component | Version | Purpose |
|-----------|---------|---------|
| **Next.js** | 15.1.3 | React framework, app router, server components |
| **React** | 19.0.0 | UI library |
| **TypeScript** | 5.7.2 | Type safety |
| **Tailwind CSS** | 4.0.0 | Utility-first CSS |
| **shadcn/ui** | Latest | Component library (ALAI standard) |
| **Lucide React** | Latest | Icon library (ALAI standard) |
| **next-intl** | Latest | i18n (Serbian sr-RS + English fallback) |
| **Vitest** | Latest | Unit testing (1721 passing / 1777 total) |
| **Playwright** | Latest | E2E testing (15 journeys) |

## Database

| Component | Purpose |
|-----------|---------|
| **PostgreSQL 16** | Primary database |
| **Port** | 5436 (separate from Drop Norway 5433, Bilko 5434) |
| **Timezone** | UTC+0 (TIMESTAMP WITH TIME ZONE) |
| **Tables** | 22 (via Flyway V1-V22) |
| **RLS** | PostgreSQL Row-Level Security for multi-tenancy |

### Database Tables

22 tables across 22 Flyway migrations:

1. **V1:** users, phone_verifications, recipients, transactions, nbs_ips_logs, merchants, settings
2. **V2:** nbs_ips_logs ISO20022 fields
3. **V3:** linked_accounts
4. **V4:** transaction idempotency_key_hash
5. **V5:** kyc_sessions
6. **V6:** users JMBG fields (encrypted + hash)
7. **V7:** aml_flags
8. **V8:** disclosure_acknowledged
9. **V9:** complaints
10. **V10:** phone_verifications max_attempts
11. **V11:** audit_log
12. **V12:** data_access_requests
13. **V13:** recipients enhanced (IBAN, country)
14. **V14:** merchants (business_name, national_id, bank_account, fee_rate, qr_hmac_key)
15. **V15:** exchange_rates
16. **V16:** notifications
17. **V17:** webhook_deliveries
18. **V18:** user_consents
19. **V19:** feature_flags
20. **V20:** withdrawal_requests
21. **V21:** cards_scaffold (stub for Phase 2)
22. **V22:** disputes

## Infrastructure

| Component | Purpose |
|-----------|---------|
| **Azure Container Apps** | Backend + frontend hosting |
| **Azure Container Registry** | Docker image registry |
| **Azure Database for PostgreSQL** | Managed PostgreSQL 16 |
| **Azure Cache for Redis** | Session store, rate limiting |
| **Azure DNS** | drop.rs domain management |
| **Azure Key Vault** | Secrets management |
| **Caddy** | Reverse proxy (prod/staging/dev profiles) |
| **Terraform** | IaC (11 modules) |

## Observability

| Component | Purpose |
|-----------|---------|
| **OpenTelemetry** | Distributed tracing (backend + frontend) |
| **Sentry** | Error tracking (client + server + edge) |
| **Prometheus** | Metrics collection |
| **Grafana** | Dashboards (3: overview, infra, errors) |
| **Loki** | Log aggregation |
| **Tempo** | Trace storage |
| **LGTM Stack** | Grafana + Loki + Tempo + Mimir (docker-compose profile) |

## Testing

| Type | Framework | Coverage |
|------|-----------|----------|
| **Backend Unit** | Kotest | 617 tests (79 files) |
| **Backend Integration** | Testcontainers | 11 tests (real PostgreSQL) |
| **Frontend Unit** | Vitest | 1721 passing / 1777 total |
| **E2E Journeys** | Playwright | 15 journeys |
| **Load Testing** | k6 | 4 scenarios |
| **Accessibility** | axe-core | 23 rules |
| **Contract Testing** | Pact | 12 interactions |
| **Visual Regression** | Playwright | Baseline snapshots |

### Coverage Gates

- **Backend:** 52% (JaCoCo gate, unit-only due to docker-java issue)
  - Target: 60% once docker-java issue fixed to restore integration tests
- **Frontend:** No strict gate (vitest coverage tracked)

## CI/CD

| Workflow | Trigger | Purpose |
|----------|---------|---------|
| **test.yml** | PR, push to develop/main | Unit + integration tests |
| **quality-gate.yml** | PR | Coverage gate enforcement |
| **security.yml** | PR, push | CORS, rate limiting, EnvGuard checks |
| **accessibility.yml** | PR, push | axe-core a11y testing |
| **contract.yml** | PR, push | Pact contract testing |
| **k6.yml** | PR, push to main | Load testing (4 scenarios) |
| **backup-verify.yml** | Daily | Backup/DR verification |
| **build.yml** | Push to develop | Docker image build |
| **deploy-staging.yml** | Push to develop | Staging deployment |
| **deploy-production.yml** | Tag v* | Production deployment |
| **sonar.yml** | PR, push | SonarCloud static analysis |

## Security

| Component | Purpose |
|-----------|---------|
| **CORS** | Configured via CORS.kt plugin |
| **Rate Limiting** | RateLimit.kt plugin (10 OTP/hour, 50 tx/hour) |
| **EnvGuard** | Startup validation (12 required env vars) |
| **AuditLogger** | V11 migration, logs all sensitive actions |
| **JWT HS256** | Stateless auth (24h expiry) |
| **SHA-256 Hashing** | OTP codes, idempotency keys |
| **PostgreSQL Encryption** | JMBG encrypted (KMS key rotation in Azure) |
| **mTLS** | NBS IPS API calls (Phase 5) |

## Configuration

### Environment Variables (12 required)

```bash
# Database
DATABASE_URL=postgresql://localhost:5436/dropsrbija_dev
DATABASE_USER=dropsrbija
DATABASE_PASSWORD=<secret>

# API
PORT=3002
JWT_SECRET=<64+ bytes>
JWT_EXPIRY_SECONDS=86400

# NBS IPS (Phase 5)
NBS_IPS_ENDPOINT=https://ips.nbs.rs/api/v1
NBS_IPS_API_KEY=<secret>

# Redis
REDIS_URL=redis://localhost:6380

# Frontend
NEXT_PUBLIC_API_URL=http://localhost:3003
NEXT_PUBLIC_APP_LANGUAGE=sr
```

## Development Setup

### Prerequisites

- Docker + Docker Compose
- Kotlin 21 (backend local dev)
- Node.js 20+ (frontend local dev)

### Quick Start

```bash
# Full stack
docker-compose up

# Or separate services
docker-compose up postgres redis -d
cd backend && ./gradlew run
cd frontend && npm run dev
```

### Services

- **Frontend:** http://localhost:3000
- **Backend API:** http://localhost:3003
- **PostgreSQL:** localhost:5436 (dropsrbija_dev)
- **Redis:** localhost:6380

## Comparison to Drop Norway

| Aspect | Drop Norway | Drop Srbija |
|--------|-------------|-------------|
| **Backend** | Hono + TypeScript | Kotlin + Ktor |
| **Frontend** | Next.js 15 | Next.js 15 (1:1 copy) |
| **Auth** | BankID | Phone OTP |
| **Payment Rails** | PSD2 Open Banking | NBS IPS |
| **Currency** | NOK | RSD (+ EUR corridor) |
| **Database Port** | 5433 | 5436 |
| **Issuer** | "drop-api" | "dropsrbija-api" |

---

**Last Updated:** 2026-04-17  
**Source:** `/Users/makinja/ALAI/products/DropSrbija`