# Go Hexagonal Architecture

Production-ready Go backend template with hexagonal architecture, 12-factor compliance, and Keycloak OIDC integration.

## Table of Contents

1. [Quick Start](#quick-start)
2. [Documentation](#documentation)
3. [Project Structure](#project-structure)
4. [Core Principles](#core-principles)
5. [Commands](#commands)
6. [Environment Variables](#environment-variables)

---

## Quick Start

### 1. Prerequisites

- Go 1.21+
- PostgreSQL 15+
- OpenBao (for staging/production) or `.env` file (for local)

### 2. Configuration

**Local development** - create `.env` file:

```env
APP_ENV=local
APP_MODE=debug
APP_PORT=8080
APP_ALLOWED_ORIGINS=http://localhost:3000

PERSISTENCE_DSN=postgres://user:pass@localhost:5432/messaging?sslmode=disable
CACHE_DSN=postgres://user:pass@localhost:5432/messaging?sslmode=disable&search_path=cache

KEYCLOAK_JWKS_URL=https://auth.pharos.id/realms/production/protocol/openid-connect/certs
KEYCLOAK_CLIENT_ID=exodus

LOG_LEVEL=debug
LOG_FORMAT=json
```

### 3. Build

```bash
make build
```

### 4. Run Migrations

```bash
./bin/messaging-be migrate
```

### 5. Run Server

```bash
./bin/messaging-be
```

### 6. Verify

```bash
curl http://localhost:8080/healthz
```

---

## Documentation

| File | Contents |
|------|----------|
| [references/ARCHITECTURE.md](references/ARCHITECTURE.md) | Hexagonal patterns, DDD, provider |
| [references/12-FACTOR.md](references/12-FACTOR.md) | 12-factor methodology |
| [references/CONFIGURATION.md](references/CONFIGURATION.md) | OpenBao, env loading |
| [references/AUTHENTICATION.md](references/AUTHENTICATION.md) | Keycloak JWT |
| [references/DATABASE.md](references/DATABASE.md) | PostgreSQL, migrations |
| [references/DEPLOYMENT.md](references/DEPLOYMENT.md) | Docker, CI/CD, admin CLI |
| [references/CODING-STANDARDS.md](references/CODING-STANDARDS.md) | REST, SOLID, error handling |

---

## Project Structure

```
.
├── cmd/
│   ├── server/           # HTTP server
│   └── migrate/          # Migration commands
├── config/               # Configuration loading
├── internal/
│   ├── core/
│   │   ├── domain/      # Domain entities, events
│   │   ├── port/        # Inbound/outbound interfaces
│   │   └── usecase/     # Business logic
│   ├── adapter/
│   │   ├── inbound/     # HTTP handlers
│   │   └── outbound/    # DB, cache, keycloak adapters
│   └── provider/         # Dependency provider
├── middlewares/          # HTTP middleware (auth, logging)
├── pkg/
│   ├── logger/          # Structured logging
│   ├── metrics/         # Prometheus metrics
│   ├── response/         # HTTP response utilities
│   ├── tracing/         # OpenTelemetry
│   └── buildinfo/       # Build information
├── db/migrations/        # Database migrations
└── deployments/          # Docker, CI/CD
```

---

## Core Principles

### SOLID Design

- **SRP**: Single Responsibility - One usecase per operation
- **DIP**: Dependency Inversion - Depend on ports (interfaces), not implementations
- See [references/ARCHITECTURE.md](references/ARCHITECTURE.md) for detailed examples

### Hexagonal Architecture

- Domain contains business logic, no external dependencies
- Ports define interfaces (contracts)
- Adapters implement ports and handle external concerns
- Services use ports, not adapters

### 12-Factor Compliance

All 12 factors implemented. See [references/12-FACTOR.md](references/12-FACTOR.md).

### Domain-Driven Design

- Entities: User, with NIP as primary key
- Value Objects: NIP, Email with validation
- Domain Events: UserCreated, UserUpdated
- See [references/ARCHITECTURE.md](references/ARCHITECTURE.md)

### Critical Rules

- **NEVER skip error checking** - Always handle or return errors
- **NEVER use panic** - Return errors to parent
- See [references/CODING-STANDARDS.md](references/CODING-STANDARDS.md)

---

## Commands

```bash
# Server (daemon mode - default)
./messaging-be
./messaging-be server

# Migrations
./messaging-be migrate           # Default: up
./messaging-be migrate up
./messaging-be migrate down 1   # Disabled in production

# Version
./messaging-be version
```

### Docker Operations

```bash
# Run container
docker run -p 8080:8080 messaging-be

# Run migrations in container
docker exec <container> ./messaging-be migrate
```

---

## Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `APP_ENV` | Environment (local/staging/production) | `local` |
| `APP_MODE` | Gin mode (debug/release) | `release` |
| `APP_PORT` | HTTP server port | `8080` |
| `APP_ALLOWED_ORIGINS` | CORS origins | `*` |
| `PERSISTENCE_DSN` | PostgreSQL connection string | Required |
| `CACHE_DSN` | Cache DB connection string | Required |
| `KEYCLOAK_JWKS_URL` | Keycloak JWKS endpoint | Required |
| `KEYCLOAK_CLIENT_ID` | Keycloak client ID | Required |
| `LOG_LEVEL` | Logging level | `info` |
| `LOG_FORMAT` | Log format (json/text) | `json` |
| `OPENBAO_ADDR` | OpenBao server (non-local) | - |
| `OPENBAO_TOKEN` | OpenBao token (non-local) | - |
| `OPENBAO_SECRET_PATH` | Secret path (non-local) | - |

### Configuration Strategy

| Environment | Config Source |
|-------------|--------------|
| `local` | `.env` file |
| `staging` | OpenBao v2 KV |
| `production` | OpenBao v2 KV |

See [references/CONFIGURATION.md](references/CONFIGURATION.md) for OpenBao setup.

---

## Authentication

Keycloak JWT authentication via keyfunc/v3 (Resource Server pattern).

### JWT Claims Mapping

| JWT Claim | Field |
|-----------|-------|
| `nip` | Primary key |
| `name` | Full name |
| `email` | Email |
| `resource_access.exodus.roles` | Authorization roles |

### Protected Routes

```go
// Use auth middleware
r.Use(middlewares.AuthMiddleware(authSvc))

// Require specific role
admin.Use(middlewares.RequireRole(authSvc, "team-trade.admin"))
```

See [references/AUTHENTICATION.md](references/AUTHENTICATION.md).

---

## Database

PostgreSQL with pgx connection pooling and unlogged tables for caching.

### Schema

```sql
CREATE TABLE users (
    nip VARCHAR(20) PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255),
    is_active BOOLEAN DEFAULT true,
    last_login_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```

See [references/DATABASE.md](references/DATABASE.md) for full schema and migrations.

---

## Next Steps

1. [references/ARCHITECTURE.md](references/ARCHITECTURE.md) - Understand the architecture
2. [references/CONFIGURATION.md](references/CONFIGURATION.md) - Set up OpenBao for production
3. [references/DEPLOYMENT.md](references/DEPLOYMENT.md) - Deploy with Docker/CI-CD
