diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5698431
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+.idea
+.env
+.env.*
+!.env.example
+
+# Generated build output
+target/
+
+# Local workflow guidance
+GIT_WORKFLOW_CONVENTION.md
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..f2bbabf
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,65 @@
+# syntax=docker/dockerfile:1
+
+# ─── Stage 1: Dependency Cache ────────────────────────────────────────────────
+FROM eclipse-temurin:25-jdk-alpine AS dependencies
+
+WORKDIR /app
+
+# Copy root and all module POM files for precise dependency caching
+COPY pom.xml ./
+COPY payguard-proto/pom.xml ./payguard-proto/
+COPY payguard-api-gateway/pom.xml ./payguard-api-gateway/
+COPY payguard-wallet-service/pom.xml ./payguard-wallet-service/
+COPY payguard-loan-service/pom.xml ./payguard-loan-service/
+COPY payguard-collateral-service/pom.xml ./payguard-collateral-service/
+
+COPY --chmod=0755 mvnw ./mvnw
+COPY .mvn/ .mvn/
+
+# Download dependencies offline to leverage Docker layer caching
+RUN ./mvnw --batch-mode --no-transfer-progress dependency:go-offline -B || true
+
+
+# ─── Stage 2: Application Build ───────────────────────────────────────────────
+FROM dependencies AS builder
+
+WORKDIR /app
+
+# Copy source code and configurations for all modules
+COPY config/ ./config/
+COPY payguard-proto/ ./payguard-proto/
+COPY payguard-api-gateway/./payguard-api-gateway/
+COPY payguard-wallet-service/ ./payguard-wallet-service/
+COPY payguard-loan-service/ ./payguard-loan-service/
+COPY payguard-collateral-service/ ./payguard-collateral-service/
+
+# Receive service name via Build Arg (defaults to wallet service)
+ARG SERVICE_NAME=payguard-wallet-service
+
+# Build the target service package along with internal dependencies (-am) without running tests
+RUN ./mvnw --batch-mode --no-transfer-progress clean package -pl :${SERVICE_NAME} -am -DskipTests
+
+
+# ─── Stage 3: Runtime ─────────────────────────────────────────────────────────
+FROM eclipse-temurin:25-jre-alpine AS runtime
+
+WORKDIR /app
+
+# High security: Create a non-root system user and isolate the data directory
+RUN addgroup -S payguard \
+ && adduser -S payguard -G payguard \
+ && mkdir -p /var/lib/payguard \
+ && chown -R payguard:payguard /var/lib/payguard
+
+ARG SERVICE_NAME=payguard-wallet-service
+
+# Copy the output JAR file from the build stage to the lightweight JRE runtime image
+COPY --from=builder --chown=payguard:payguard /app/${SERVICE_NAME}/target/*.jar ./app.jar
+
+# Run the container as a non-privileged user
+USER payguard
+
+EXPOSE 8080
+
+# Java 25 runtime optimizations
+ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-XX:MaxRAMPercentage=75.0", "-jar", "/app/app.jar"]
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..00f1ec3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,305 @@
+
+
+# PayGuard
+
+**A modular fintech backend for wallet ledgering, loan origination, and digital-collateral risk management.**
+
+[](#)
+[](https://openjdk.org)
+[](https://spring.io/projects/spring-boot)
+[](https://alistair.cockburn.us/hexagonal-architecture/)
+[](LICENSE)
+
+[Overview](#overview) •
+[Services](#services) •
+[Architecture](#architecture) •
+[Key Engineering Decisions](#key-engineering-decisions) •
+[Getting Started](#getting-started) •
+[API Documentation](#api-documentation) •
+[Roadmap](#roadmap)
+
+
+
+---
+
+## Overview
+
+PayGuard is a backend system for a single, coherent financial story: a customer locks digital assets as collateral, borrows against them, and pays the loan back — while the system continuously monitors the collateral's value and protects itself automatically if that value falls too far.
+
+The project is built as a set of **independently deployable microservices**, each owning its own database and communicating only through explicit contracts — never through a shared schema. It is a deliberate engineering exercise in the domain problems that sit underneath every regulated lending product:
+
+- Double-entry bookkeeping and derived, never-stored balances
+- Loan amortization, repayment waterfalls, and delinquency state machines
+- Loan-to-Value (LTV) risk monitoring, margin calls, and liquidation
+- Idempotent financial operations under concurrent access
+- Service-to-service communication boundaries (REST at the edge, gRPC where latency matters)
+
+It is not a payment-card switch or a full core-banking platform. The scope is intentionally narrow so that every part of it can be built, understood, and defended in depth.
+
+---
+
+## Core Capabilities
+
+### Implemented / In Progress
+
+- [ ] Account creation and double-entry ledger posting (`wallet-service`)
+- [ ] Hold → capture → release flow for provisional balance reservations
+- [ ] Loan application, approval, and amortization-schedule generation (`loan-service`)
+- [ ] Repayment waterfall (fees → interest → principal)
+- [ ] Collateral locking and Loan-to-Value calculation (`collateral-service`)
+- [ ] Margin-call and liquidation risk monitoring
+- [ ] API Gateway routing (REST-in, gRPC-out to internal services)
+
+### Planned
+
+- [ ] Kafka-based domain events between services (e.g. loan approval → collateral linkage)
+- [ ] Full CI pipeline (build, test, static analysis) via GitHub Actions
+- [ ] Expanded integration and concurrency test coverage
+
+> This README describes the target architecture and is kept in sync with implementation status via the checkboxes above — see [Current Limitations](#current-limitations) for what is intentionally out of scope for now.
+
+---
+
+## Services
+
+| Service | Responsibility | Persistence | Current State |
+|---|---|---|---|
+| `wallet-service` | Account balances, double-entry ledger, holds/captures | PostgreSQL/Oracle via **jOOQ** (append-only, no ORM overhead) | In development |
+| `loan-service` | Loan lifecycle, amortization schedules, repayments | Oracle via JPA/Hibernate | In development |
+| `collateral-service` | Collateral locking, price valuation, LTV monitoring, liquidation | Oracle via JPA/Hibernate | In development |
+| `api-gateway` | Single entry point; REST from clients, gRPC to internal services | — | Planned |
+
+> `wallet-service` deliberately uses jOOQ instead of JPA: a ledger is append-only, and jOOQ gives explicit control over `INSERT`-only SQL with no risk of an accidental `UPDATE` slipping in through dirty-checking. `loan-service` and `collateral-service` manage mutable, CRUD-shaped state, where JPA is a better fit.
+
+---
+
+## Architecture
+
+### System Overview
+
+```mermaid
+flowchart LR
+ client["Client (REST)"]
+ gateway["API Gateway
(REST in, gRPC out)"]
+ wallet["wallet-service
(Ledger)"]
+ loan["loan-service"]
+ collateral["collateral-service"]
+ oracle["Oracle 23c"]
+ redis["Redis 7
(price cache, distributed locks)"]
+ kafka["Kafka (KRaft)
domain events"]
+
+ client --> gateway
+ gateway -->|gRPC| wallet
+ gateway -->|gRPC| loan
+ gateway -->|gRPC| collateral
+
+ loan -->|REST: disburse/repay| wallet
+ loan -->|REST: check LTV| collateral
+ collateral -->|REST: outstanding balance| loan
+ collateral --> redis
+
+ wallet --> oracle
+ loan --> oracle
+ collateral --> oracle
+
+ loan -.->|planned| kafka
+ collateral -.->|planned| kafka
+```
+
+### Hexagonal Structure (per service)
+
+```mermaid
+flowchart LR
+ Inbound["Inbound Adapters
REST Controllers"]
+ Application["Application Layer
Use-Case Services"]
+ Domain["Domain Layer
Aggregates / Value Objects / Invariants"]
+ Ports["Outbound Ports"]
+ Outbound["Outbound Adapters
jOOQ / JPA / HTTP Clients"]
+
+ Inbound --> Application
+ Application --> Domain
+ Application --> Ports
+ Outbound --> Ports
+```
+
+### Dependency Rules
+
+- Domain code has no Spring, persistence, or HTTP dependencies — invariants (e.g. debit = credit) are testable without a running application.
+- Each service owns its own database schema; no service queries another's tables directly.
+- Cross-service calls happen only through the declared client ports (`WalletServiceClient`, `LoanServiceClient`, `CollateralServiceClient`), each with a REST adapter today and a gRPC adapter available for the gateway path.
+- Dependencies point inward, toward the domain core.
+
+---
+
+## Key Engineering Decisions
+
+### No stored balance column
+
+`wallet-service` never persists a mutable `balance` field. Every balance is derived from the sum of immutable `ledger_entry` rows. This eliminates an entire class of race conditions that come from concurrent `UPDATE balance = balance - x` statements, at the cost of computing balances on read — a trade-off documented here rather than hidden.
+
+### Holds are not ledger entries
+
+A hold (reservation) reduces *available* balance without touching the *ledger* balance. Only capture — the actual settlement of a hold — creates real, immutable ledger entries. This mirrors the authorize-then-capture pattern used throughout the payments industry.
+
+### Concurrency: inserts don't need locks, holds do
+
+Posting a ledger transaction is a pure `INSERT` and needs no row locking. Creating a *hold* does need one (`SELECT ... FOR UPDATE` or a Redis-based distributed lock), because two concurrent hold requests could otherwise both read a stale available balance and jointly overdraw the account.
+
+### gRPC only at the gateway boundary
+
+Internal service-to-service calls use plain REST. gRPC is used exclusively between the API Gateway and the internal services, where the latency and schema-contract benefits are worth the added operational complexity — not applied uniformly out of habit.
+
+### Derived, never-stored LTV
+
+Loan-to-Value is calculated on demand from the latest price snapshot and the loan's current outstanding principal, never cached as a stored "current LTV" field. This keeps the number provably correct at the moment it's checked, which matters more here than raw read speed.
+
+---
+
+## Getting Started
+
+### Prerequisites
+
+- Java 25 or newer
+- Docker with Docker Compose
+- Maven Wrapper (included, no separate Maven install required)
+
+```bash
+java -version
+docker --version
+docker compose version
+```
+
+### 1. Clone the Repository
+
+```bash
+git clone https://github.com//payguard.git
+cd payguard
+```
+
+### 2. Configure the Environment
+
+Create a `.env` file in the repository root:
+
+```env
+# Oracle
+ORACLE_IMAGE=gvenzl/oracle-free:23-slim-faststart
+ORACLE_HOST_PORT=1521
+ORACLE_PASSWORD=change-me-for-local-development
+
+# Redis
+REDIS_IMAGE=redis:7-alpine
+REDIS_HOST_PORT=6379
+
+# Kafka (KRaft mode — no Zookeeper)
+KAFKA_CLUSTER_ID=replace-with-a-generated-cluster-id
+
+# Per-service ports
+WALLET_SERVICE_PORT=8081
+LOAN_SERVICE_PORT=8082
+COLLATERAL_SERVICE_PORT=8083
+API_GATEWAY_PORT=8080
+```
+
+> Never commit real credentials. The values above are placeholders for local development.
+
+### 3. Start Infrastructure
+
+```bash
+docker compose up -d payguard-oracle payguard-redis payguard-kafka --wait
+```
+
+### 4. Run a Service
+
+```bash
+./mvnw spring-boot:run -pl payguard-wallet-service
+```
+
+### 5. Open the API Documentation
+
+```text
+http://localhost:8081/swagger-ui/index.html
+```
+
+To stop the infrastructure:
+
+```bash
+docker compose down
+```
+
+---
+
+## API Documentation
+
+Each service exposes its own OpenAPI specification and Swagger UI at `/swagger-ui/index.html`. Representative endpoints:
+
+| Service | Method | Path | Purpose |
+|---|---|---|---|
+| wallet-service | `POST` | `/accounts/{id}/holds` | Reserve funds ahead of a capture |
+| wallet-service | `GET` | `/accounts/{id}/balance` | Ledger and available balance |
+| loan-service | `POST` | `/loans/{id}/approve` | Generate the amortization schedule |
+| loan-service | `POST` | `/loans/{id}/repayments` | Apply a payment through the waterfall |
+| collateral-service | `GET` | `/collateral/{id}` | Current position and live LTV |
+| collateral-service | `POST` | `/collateral/refresh-prices` | Re-evaluate risk against latest prices |
+
+The OpenAPI document for each service is the source of truth for exact request/response schemas.
+
+---
+
+## Code Quality
+
+| Check | Tool | Execution |
+|---|---|---|
+| Build & tests | Maven | CI and local |
+| Formatting / static analysis | *(planned)* | CI |
+
+```bash
+./mvnw clean verify
+```
+
+Install the local Git hook so every `git push` runs the same verification first:
+
+```bash
+./mvnw -Pinstall-git-hooks initialize
+```
+
+---
+
+## Roadmap
+
+### wallet-service
+- [ ] Account CRUD
+- [ ] Direct transfer flow (Flow A)
+- [ ] Hold → capture/release flow (Flow B)
+- [ ] Idempotency-key enforcement
+
+### loan-service
+- [ ] Loan application and state machine
+- [ ] Amortization schedule generation
+- [ ] Repayment waterfall
+- [ ] Delinquency/default detection
+
+### collateral-service
+- [ ] Collateral locking
+- [ ] Price-oracle integration
+- [ ] LTV monitoring and margin calls
+- [ ] Liquidation flow
+
+### Platform
+- [ ] API Gateway (REST → gRPC)
+- [ ] Kafka domain events
+- [ ] Full CI via GitHub Actions
+
+---
+
+## Current Limitations
+
+- PayGuard is an engineering-demonstration project, not a production lending platform.
+- No real price feed, KYC, or payment-network integration is connected; these are simulated or stubbed.
+- Continuous deployment is out of scope for the current phase — the focus is on correctness and depth of the core domain services.
+- Each service currently assumes a single instance; distributed-lock behavior for holds is documented but not yet load-tested at scale.
+
+---
+
+## License
+
+This project is licensed under the [MIT License](LICENSE).
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..6bb8e6b
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,68 @@
+name: ${COMPOSE_PROJECT_NAME}
+
+services:
+ oracle:
+ image: gvenzl/oracle-free:23-slim-faststart
+ container_name: payguard-oracle
+ ports:
+ - "${ORACLE_PORT}:1521"
+ environment:
+ ORACLE_PASSWORD: ${ORACLE_PASSWORD}
+ APP_USER: ${ORACLE_APP_USER}
+ APP_PASSWORD: ${ORACLE_APP_PASSWORD}
+ healthcheck:
+ test: ["CMD-SHELL", "/opt/oracle/checkDBStatus.sh"]
+ interval: 10s
+ timeout: 5s
+ retries: 10
+ start_period: 30s
+ volumes:
+ - oracle_data:/opt/oracle/oradata
+
+ redis:
+ image: redis:7-alpine
+ container_name: payguard-redis
+ ports:
+ - "${REDIS_PORT}:6379"
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 5s
+ timeout: 3s
+ retries: 5
+ start_period: 5s
+ volumes:
+ - redis_data:/data
+
+ kafka:
+ image: apache/kafka:latest
+ container_name: payguard-kafka
+ ports:
+ - "${KAFKA_PORT}:9092"
+ environment:
+ KAFKA_NODE_ID: 1
+ KAFKA_PROCESS_ROLES: broker,controller
+ KAFKA_LISTENERS: INTERNAL://0.0.0.0:29092,EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
+ KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:29092,EXTERNAL://localhost:${KAFKA_PORT}
+ KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
+ KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT
+ KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
+ KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+ KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
+ KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
+ KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
+ KAFKA_LOG_DIRS: /tmp/kraft-combined-logs
+ CLUSTER_ID: ${KAFKA_CLUSTER_ID}
+ healthcheck:
+ test: ["CMD-SHELL", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 --list"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ start_period: 15s
+ volumes:
+ - kafka_data:/tmp/kraft-combined-logs
+
+volumes:
+ oracle_data:
+ redis_data:
+ kafka_data:
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 0000000..cd53718
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": [
+ "config:recommended"
+ ],
+ "baseBranchPatterns": [
+ "main"
+ ],
+ "branchPrefix": "chore/update-",
+ "semanticCommits": "enabled",
+ "semanticCommitType": "chore",
+ "semanticCommitScope": "deps",
+ "commitMessageAction": "update",
+ "commitMessageTopic": "{{depName}}",
+ "commitMessageExtra": "to {{newVersion}}",
+ "prBodyTemplate": "## Summary\n\nAutomated dependency update managed by Renovate.\n\n## Verification\n\nReview the GitHub Actions results for the current commit.\n\n## Risks\n\nReview the release notes below for potential breaking changes.\n\n## Database Changes\n\nNone\n\n---\n\n### Renovate Details\n\n{{{table}}}\n\n{{{warnings}}}\n\n{{{notes}}}\n\n{{{changelogs}}}",
+ "packageRules": [
+ {
+ "matchUpdateTypes": [
+ "minor",
+ "patch"
+ ],
+ "groupName": "all minor and patch dependencies",
+ "commitMessageTopic": "non-major dependencies",
+ "matchPackageNames": [
+ "*"
+ ]
+ }
+ ]
+}