# Golang Backend Blueprint: Clean Architecture with Wire DI & Cassandra

**Version:** 1.0
**Last Updated:** November 2025
**Based on:** maplepress-backend architecture

This document provides a step-by-step guide to building a new Golang backend using the same architecture, authentication system, and reusable components from the MaplePress backend. Use this as a reference when creating new backend projects from scratch.

---

## Table of Contents

1. [Architecture Overview](#architecture-overview)
2. [Project Initialization](#project-initialization)
3. [Directory Structure](#directory-structure)
4. [Core Dependencies](#core-dependencies)
5. [Configuration System](#configuration-system)
6. [Dependency Injection with Wire](#dependency-injection-with-wire)
7. [Reusable pkg/ Components](#reusable-pkg-components)
8. [Authentication System](#authentication-system)
9. [Clean Architecture Layers](#clean-architecture-layers)
10. [Database Setup (Cassandra)](#database-setup-cassandra)
11. [Middleware Implementation](#middleware-implementation)
12. [HTTP Server Setup](#http-server-setup)
13. [Docker & Infrastructure](#docker--infrastructure)
14. [CLI Commands (Cobra)](#cli-commands-cobra)
15. [Development Workflow](#development-workflow)
16. [Testing Strategy](#testing-strategy)
17. [Production Deployment](#production-deployment)

---

## 1. Architecture Overview

### Core Principles

Our backend architecture follows these fundamental principles:

1. **Clean Architecture** - Separation of concerns with clear dependency direction
2. **Dependency Injection** - Using Google Wire for compile-time DI
3. **Multi-tenancy** - Tenant isolation at the application layer
4. **Security-first** - CWE-compliant security measures throughout
5. **Code Reuse** - Extensive use of shared `pkg/` components

### Architecture Layers

```
┌─────────────────────────────────────────────────────────────┐
│                    Interface Layer (HTTP)                    │
│  • Handlers (HTTP endpoints)                                 │
│  • DTOs (Data Transfer Objects)                              │
│  • Middleware (JWT, API Key, Rate Limiting, CORS)           │
└──────────────────────┬──────────────────────────────────────┘
                       ↓
┌─────────────────────────────────────────────────────────────┐
│                      Service Layer                           │
│  • Orchestration logic                                       │
│  • Transaction management (SAGA pattern)                     │
│  • Cross-use-case coordination                               │
└──────────────────────┬──────────────────────────────────────┘
                       ↓
┌─────────────────────────────────────────────────────────────┐
│                      Use Case Layer                          │
│  • Focused, single-responsibility operations                 │
│  • Business logic encapsulation                              │
│  • Validation and domain rules                               │
└──────────────────────┬──────────────────────────────────────┘
                       ↓
┌─────────────────────────────────────────────────────────────┐
│                    Repository Layer                          │
│  • Data access implementations                               │
│  • Database queries (Cassandra CQL)                          │
│  • Cache operations (Redis)                                  │
└──────────────────────┬──────────────────────────────────────┘
                       ↓
┌─────────────────────────────────────────────────────────────┐
│                      Domain Layer                            │
│  • Entities (domain models)                                  │
│  • Repository interfaces                                     │
│  • Domain errors                                             │
└─────────────────────────────────────────────────────────────┘

              Shared Infrastructure (pkg/)
┌─────────────────────────────────────────────────────────────┐
│  • Logger (Zap)          • Security (JWT, Password, API Key)│
│  • Database (Cassandra)  • Cache (Redis, Two-Tier)          │
│  • Storage (S3)          • Rate Limiting                     │
│  • Email (Mailgun)       • Search (Meilisearch)             │
│  • Distributed Mutex     • Validation                        │
└─────────────────────────────────────────────────────────────┘
```

### Dependency Direction

**Critical Rule:** Dependencies flow INWARD only (outer layers depend on inner layers).

```
Interface → Service → Use Case → Repository → Domain
    ↓           ↓         ↓           ↓
    └───────────┴─────────┴───────────┴──→ pkg/ (Infrastructure)
```

---

## 2. Project Initialization

### Step 1: Create Project Structure

```bash
# Create new project directory
mkdir -p cloud/your-backend-name
cd cloud/your-backend-name

# Initialize Go module
go mod init codeberg.org/mapleopentech/monorepo/cloud/your-backend-name

# Create initial directory structure
mkdir -p {app,cmd,config,internal,pkg,migrations,static,docs}
```

### Step 2: Initialize Go Workspace (if using monorepo)

```bash
# From monorepo root
cd /path/to/monorepo
go work use ./cloud/your-backend-name
```

### Step 3: Add Core Dependencies

```bash
# Core dependencies
go get github.com/google/wire@v0.7.0
go get github.com/spf13/cobra@v1.10.1
go get go.uber.org/zap@v1.27.0

# Database & Cache
go get github.com/gocql/gocql@v1.7.0
go get github.com/redis/go-redis/v9@v9.16.0
go get github.com/golang-migrate/migrate/v4@v4.19.0

# Security
go get github.com/golang-jwt/jwt/v5@v5.3.0
go get golang.org/x/crypto@v0.41.0
go get github.com/awnumar/memguard@v0.23.0

# HTTP & Utilities
go get github.com/google/uuid@v1.6.0

# Install Wire CLI
go install github.com/google/wire/cmd/wire@latest
```

---

## 3. Directory Structure

### Complete Directory Layout

```
your-backend-name/
├── app/                          # Dependency injection (Wire)
│   ├── wire.go                   # Wire dependency providers
│   ├── wire_gen.go               # Generated by Wire (gitignore)
│   └── app.go                    # Application bootstrapper
│
├── cmd/                          # CLI commands (Cobra)
│   ├── root.go                   # Root command
│   ├── daemon/
│   │   └── daemon.go             # Main server command
│   ├── migrate/
│   │   └── migrate.go            # Database migrations
│   └── version/
│       └── version.go            # Version command
│
├── config/                       # Configuration
│   ├── config.go                 # Config loader
│   └── constants/
│       ├── constants.go          # Global constants
│       └── session.go            # Session context keys
│
├── internal/                     # Private application code
│   ├── domain/                   # Domain entities & interfaces
│   │   ├── user/
│   │   │   ├── entity.go         # User domain entity
│   │   │   └── repository.go    # User repository interface
│   │   └── tenant/
│   │       ├── entity.go         # Tenant domain entity
│   │       └── repository.go    # Tenant repository interface
│   │
│   ├── repository/               # Repository implementations
│   │   ├── user/
│   │   │   ├── impl.go           # Repository struct
│   │   │   ├── create.go         # Create operations
│   │   │   ├── get.go            # Read operations
│   │   │   ├── update.go         # Update operations
│   │   │   ├── delete.go         # Delete operations
│   │   │   └── models/
│   │   │       └── user.go       # Database models
│   │   └── tenant/
│   │       └── ...               # Similar structure
│   │
│   ├── usecase/                  # Use cases (focused operations)
│   │   ├── user/
│   │   │   ├── create_user_entity.go
│   │   │   ├── save_user_to_repo.go
│   │   │   ├── validate_user_email_unique.go
│   │   │   └── get.go
│   │   └── gateway/
│   │       ├── login.go
│   │       ├── hash_password.go
│   │       └── verify_password.go
│   │
│   ├── service/                  # Service layer (orchestration)
│   │   ├── provider.go           # Service providers for Wire
│   │   ├── session.go            # Session management service
│   │   ├── gateway/
│   │   │   ├── login.go          # Login orchestration
│   │   │   ├── register.go       # Registration orchestration
│   │   │   └── provider.go       # Gateway service providers
│   │   └── user/
│   │       ├── create.go         # User creation orchestration
│   │       └── provider.go       # User service providers
│   │
│   ├── interface/http/           # HTTP interface layer
│   │   ├── server.go             # HTTP server & routing
│   │   ├── handler/              # HTTP handlers
│   │   │   ├── healthcheck/
│   │   │   │   └── healthcheck_handler.go
│   │   │   ├── gateway/
│   │   │   │   ├── login_handler.go
│   │   │   │   ├── register_handler.go
│   │   │   │   └── refresh_handler.go
│   │   │   └── user/
│   │   │       ├── create_handler.go
│   │   │       └── get_handler.go
│   │   ├── dto/                  # Data Transfer Objects
│   │   │   ├── gateway/
│   │   │   │   ├── login_dto.go
│   │   │   │   └── register_dto.go
│   │   │   └── user/
│   │   │       ├── create_dto.go
│   │   │       └── get_dto.go
│   │   └── middleware/
│   │       └── tenant.go         # Tenant context middleware
│   │
│   ├── http/middleware/          # Shared HTTP middleware
│   │   ├── jwt.go                # JWT authentication
│   │   ├── apikey.go             # API key authentication
│   │   ├── ratelimit.go          # Rate limiting
│   │   ├── security_headers.go   # Security headers (CORS, CSP)
│   │   ├── request_size_limit.go # Request size limits
│   │   └── provider.go           # Middleware providers
│   │
│   └── scheduler/                # Background schedulers (cron)
│       ├── quota_reset.go        # Monthly quota reset
│       └── ip_cleanup.go         # GDPR IP cleanup
│
├── pkg/                          # Reusable packages (copy from maplepress-backend)
│   ├── logger/                   # Structured logging (Zap)
│   │   ├── logger.go
│   │   └── sanitizer.go          # PII sanitization
│   ├── security/                 # Security utilities
│   │   ├── jwt/                  # JWT provider
│   │   ├── password/             # Password hashing & validation
│   │   ├── apikey/               # API key generation & hashing
│   │   ├── clientip/             # IP extraction & validation
│   │   ├── ipcrypt/              # IP encryption (GDPR)
│   │   └── validator/            # Credential validation
│   ├── storage/
│   │   ├── database/             # Cassandra client
│   │   │   ├── cassandra.go
│   │   │   └── migrator.go
│   │   ├── cache/                # Redis client
│   │   │   └── redis.go
│   │   └── object/               # S3-compatible storage
│   │       └── s3.go
│   ├── cache/                    # Two-tier caching
│   │   ├── redis.go
│   │   ├── cassandra.go
│   │   └── twotier.go
│   ├── ratelimit/                # Rate limiting
│   │   ├── ratelimiter.go
│   │   └── login_ratelimiter.go
│   ├── distributedmutex/         # Distributed locking
│   │   └── distributedmutex.go
│   ├── validation/               # Input validation
│   │   └── validator.go
│   ├── httperror/                # HTTP error handling
│   │   └── error.go
│   ├── httpresponse/             # HTTP response helpers
│   │   └── response.go
│   └── transaction/              # SAGA pattern
│       └── saga.go
│
├── migrations/                   # Cassandra migrations (CQL)
│   ├── 000001_create_users.up.cql
│   ├── 000001_create_users.down.cql
│   ├── 000002_create_tenants.up.cql
│   └── 000002_create_tenants.down.cql
│
├── static/                       # Static files (if needed)
├── docs/                         # Documentation
├── .env.sample                   # Sample environment variables
├── .env                          # Local environment (gitignored)
├── .gitignore                    # Git ignore rules
├── docker-compose.dev.yml        # Development docker compose
├── Dockerfile                    # Production dockerfile
├── dev.Dockerfile                # Development dockerfile
├── Taskfile.yml                  # Task runner configuration
├── go.mod                        # Go module definition
├── go.sum                        # Go module checksums
├── main.go                       # Application entry point
└── README.md                     # Project documentation
```

---

## 4. Core Dependencies

### Essential go.mod Dependencies

```go
module codeberg.org/mapleopentech/monorepo/cloud/your-backend-name

go 1.24.4

require (
	// Dependency Injection
	github.com/google/wire v0.7.0

	// CLI Framework
	github.com/spf13/cobra v1.10.1

	// Logging
	go.uber.org/zap v1.27.0

	// Database & Cache
	github.com/gocql/gocql v1.7.0
	github.com/redis/go-redis/v9 v9.16.0
	github.com/golang-migrate/migrate/v4 v4.19.0

	// Security
	github.com/golang-jwt/jwt/v5 v5.3.0
	golang.org/x/crypto v0.41.0
	github.com/awnumar/memguard v0.23.0  // Secure memory handling

	// HTTP & Utilities
	github.com/google/uuid v1.6.0

	// Distributed Locking
	github.com/bsm/redislock v0.9.4

	// Background Jobs (optional)
	github.com/robfig/cron/v3 v3.0.1

	// Optional: Email (Mailgun)
	github.com/mailgun/mailgun-go/v4 v4.23.0

	// Optional: Search (Meilisearch)
	github.com/meilisearch/meilisearch-go v0.34.1

	// Optional: GeoIP (for IP country blocking)
	github.com/oschwald/geoip2-golang v1.13.0

	// Optional: AWS S3
	github.com/aws/aws-sdk-go-v2 v1.36.3
	github.com/aws/aws-sdk-go-v2/config v1.29.14
	github.com/aws/aws-sdk-go-v2/credentials v1.17.67
	github.com/aws/aws-sdk-go-v2/service/s3 v1.80.0
)
```

---

## 5. Configuration System

### config/config.go

Create a centralized configuration system that loads from environment variables:

```go
package config

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
)

// Config holds all application configuration
type Config struct {
	App      AppConfig
	Server   ServerConfig
	HTTP     HTTPConfig
	Security SecurityConfig
	Database DatabaseConfig
	Cache    CacheConfig
	Logger   LoggerConfig
	// Add more config sections as needed
}

// AppConfig holds application-level configuration
type AppConfig struct {
	Environment string // development, staging, production
	Version     string
	JWTSecret   string
}

// ServerConfig holds HTTP server configuration
type ServerConfig struct {
	Host string
	Port int
}

// HTTPConfig holds HTTP request handling configuration
type HTTPConfig struct {
	MaxRequestBodySize int64         // Maximum request body size in bytes
	ReadTimeout        time.Duration // Maximum duration for reading the entire request
	WriteTimeout       time.Duration // Maximum duration before timing out writes
	IdleTimeout        time.Duration // Maximum amount of time to wait for the next request
}

// SecurityConfig holds security-related configuration
type SecurityConfig struct {
	TrustedProxies  []string // CIDR blocks of trusted reverse proxies
	IPEncryptionKey string   // 32-character hex key for IP encryption (GDPR)
	AllowedOrigins  []string // CORS allowed origins
}

// DatabaseConfig holds Cassandra database configuration
type DatabaseConfig struct {
	Hosts          []string
	Keyspace       string
	Consistency    string
	Replication    int
	MigrationsPath string
}

// CacheConfig holds Redis cache configuration
type CacheConfig struct {
	Host     string
	Port     int
	Password string
	DB       int
}

// LoggerConfig holds logging configuration
type LoggerConfig struct {
	Level  string // debug, info, warn, error
	Format string // json, console
}

// Load loads configuration from environment variables
func Load() (*Config, error) {
	cfg := &Config{
		App: AppConfig{
			Environment: getEnv("APP_ENVIRONMENT", "development"),
			Version:     getEnv("APP_VERSION", "0.1.0"),
			JWTSecret:   getEnv("APP_JWT_SECRET", "change-me-in-production"),
		},
		Server: ServerConfig{
			Host: getEnv("SERVER_HOST", "0.0.0.0"),
			Port: getEnvAsInt("SERVER_PORT", 8000),
		},
		HTTP: HTTPConfig{
			MaxRequestBodySize: getEnvAsInt64("HTTP_MAX_REQUEST_BODY_SIZE", 10*1024*1024), // 10 MB
			ReadTimeout:        getEnvAsDuration("HTTP_READ_TIMEOUT", 30*time.Second),
			WriteTimeout:       getEnvAsDuration("HTTP_WRITE_TIMEOUT", 30*time.Second),
			IdleTimeout:        getEnvAsDuration("HTTP_IDLE_TIMEOUT", 60*time.Second),
		},
		Security: SecurityConfig{
			TrustedProxies:  getEnvAsSlice("SECURITY_TRUSTED_PROXIES", []string{}),
			IPEncryptionKey: getEnv("SECURITY_IP_ENCRYPTION_KEY", "00112233445566778899aabbccddeeff"),
			AllowedOrigins:  getEnvAsSlice("SECURITY_CORS_ALLOWED_ORIGINS", []string{}),
		},
		Database: DatabaseConfig{
			Hosts:          getEnvAsSlice("DATABASE_HOSTS", []string{"localhost"}),
			Keyspace:       getEnv("DATABASE_KEYSPACE", "your_keyspace"),
			Consistency:    getEnv("DATABASE_CONSISTENCY", "QUORUM"),
			Replication:    getEnvAsInt("DATABASE_REPLICATION", 3),
			MigrationsPath: getEnv("DATABASE_MIGRATIONS_PATH", "file://migrations"),
		},
		Cache: CacheConfig{
			Host:     getEnv("CACHE_HOST", "localhost"),
			Port:     getEnvAsInt("CACHE_PORT", 6379),
			Password: getEnv("CACHE_PASSWORD", ""),
			DB:       getEnvAsInt("CACHE_DB", 0),
		},
		Logger: LoggerConfig{
			Level:  getEnv("LOGGER_LEVEL", "info"),
			Format: getEnv("LOGGER_FORMAT", "json"),
		},
	}

	// Validate configuration
	if err := cfg.validate(); err != nil {
		return nil, fmt.Errorf("invalid configuration: %w", err)
	}

	return cfg, nil
}

// validate checks if the configuration is valid
func (c *Config) validate() error {
	if c.Server.Port < 1 || c.Server.Port > 65535 {
		return fmt.Errorf("invalid server port: %d", c.Server.Port)
	}

	if c.Database.Keyspace == "" {
		return fmt.Errorf("database keyspace is required")
	}

	if len(c.Database.Hosts) == 0 {
		return fmt.Errorf("at least one database host is required")
	}

	if c.App.JWTSecret == "" {
		return fmt.Errorf("APP_JWT_SECRET is required")
	}

	// Production security checks
	if c.App.Environment == "production" {
		if strings.Contains(strings.ToLower(c.App.JWTSecret), "change-me") {
			return fmt.Errorf("SECURITY ERROR: JWT secret is using default value in production")
		}

		if len(c.App.JWTSecret) < 32 {
			return fmt.Errorf("SECURITY ERROR: JWT secret is too short for production (minimum 32 characters)")
		}
	}

	return nil
}

// Helper functions

func getEnv(key, defaultValue string) string {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	return value
}

func getEnvAsInt(key string, defaultValue int) int {
	valueStr := os.Getenv(key)
	if valueStr == "" {
		return defaultValue
	}

	value, err := strconv.Atoi(valueStr)
	if err != nil {
		return defaultValue
	}

	return value
}

func getEnvAsInt64(key string, defaultValue int64) int64 {
	valueStr := os.Getenv(key)
	if valueStr == "" {
		return defaultValue
	}

	value, err := strconv.ParseInt(valueStr, 10, 64)
	if err != nil {
		return defaultValue
	}

	return value
}

func getEnvAsSlice(key string, defaultValue []string) []string {
	valueStr := os.Getenv(key)
	if valueStr == "" {
		return defaultValue
	}

	// Simple comma-separated parsing
	var result []string
	for _, item := range strings.Split(valueStr, ",") {
		trimmed := strings.TrimSpace(item)
		if trimmed != "" {
			result = append(result, trimmed)
		}
	}

	if len(result) == 0 {
		return defaultValue
	}

	return result
}

func getEnvAsDuration(key string, defaultValue time.Duration) time.Duration {
	valueStr := os.Getenv(key)
	if valueStr == "" {
		return defaultValue
	}

	value, err := time.ParseDuration(valueStr)
	if err != nil {
		return defaultValue
	}

	return value
}
```

### config/constants/constants.go

Define global constants:

```go
package constants

// Context keys for request context
type ContextKey string

const (
	// Session context keys
	SessionIsAuthorized ContextKey = "session_is_authorized"
	SessionID           ContextKey = "session_id"
	SessionUserID       ContextKey = "session_user_id"
	SessionUserUUID     ContextKey = "session_user_uuid"
	SessionUserEmail    ContextKey = "session_user_email"
	SessionUserName     ContextKey = "session_user_name"
	SessionUserRole     ContextKey = "session_user_role"
	SessionTenantID     ContextKey = "session_tenant_id"

	// API Key context keys
	APIKeyIsAuthorized ContextKey = "apikey_is_authorized"
	APIKeySiteID       ContextKey = "apikey_site_id"
	APIKeyTenantID     ContextKey = "apikey_tenant_id"
)

// User roles
const (
	RoleAdmin  = "admin"
	RoleUser   = "user"
	RoleGuest  = "guest"
)

// Tenant status
const (
	TenantStatusActive   = "active"
	TenantStatusInactive = "inactive"
	TenantStatusSuspended = "suspended"
)
```

### .env.sample

Create a sample environment file:

```bash
# Application Configuration
APP_ENVIRONMENT=development
APP_VERSION=0.1.0
APP_JWT_SECRET=change-me-in-production-use-openssl-rand-base64-64

# HTTP Server Configuration
SERVER_HOST=0.0.0.0
SERVER_PORT=8000

# HTTP Timeouts & Limits
HTTP_MAX_REQUEST_BODY_SIZE=10485760  # 10 MB
HTTP_READ_TIMEOUT=30s
HTTP_WRITE_TIMEOUT=30s
HTTP_IDLE_TIMEOUT=60s

# Security Configuration
# Trusted proxies for X-Forwarded-For validation (comma-separated CIDR)
SECURITY_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
# IP encryption key for GDPR compliance (32 hex characters)
SECURITY_IP_ENCRYPTION_KEY=00112233445566778899aabbccddeeff
# CORS allowed origins (comma-separated)
SECURITY_CORS_ALLOWED_ORIGINS=https://yourdomain.com

# Cassandra Database Configuration
DATABASE_HOSTS=localhost:9042
DATABASE_KEYSPACE=your_keyspace
DATABASE_CONSISTENCY=QUORUM
DATABASE_REPLICATION=3
DATABASE_MIGRATIONS_PATH=file://migrations

# Redis Cache Configuration
CACHE_HOST=localhost
CACHE_PORT=6379
CACHE_PASSWORD=
CACHE_DB=0

# Logger Configuration
LOGGER_LEVEL=info
LOGGER_FORMAT=json
```

---

## 6. Dependency Injection with Wire

### Overview

We use Google Wire for compile-time dependency injection. Wire generates code at build time, eliminating runtime reflection and providing type safety.

### app/wire.go

This file defines all providers for Wire:

```go
//go:build wireinject
// +build wireinject

package app

import (
	"github.com/google/wire"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/http/middleware"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/handler/gateway"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/handler/healthcheck"
	userrepo "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/repository/user"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/service"
	gatewaysvc "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/service/gateway"
	gatewayuc "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/usecase/gateway"
	userusecase "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/usecase/user"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/cache"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/logger"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/security"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/security/password"
	rediscache "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/storage/cache"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/storage/database"
)

// InitializeApplication wires up all dependencies
func InitializeApplication(cfg *config.Config) (*Application, error) {
	wire.Build(
		// Infrastructure layer (pkg/)
		logger.ProvideLogger,
		database.ProvideCassandraSession,

		// Cache layer
		rediscache.ProvideRedisClient,
		cache.ProvideRedisCache,
		cache.ProvideCassandraCache,
		cache.ProvideTwoTierCache,

		// Security layer
		security.ProvideJWTProvider,
		password.NewPasswordProvider,
		password.NewPasswordValidator,
		password.NewBreachChecker,
		security.ProvideClientIPExtractor,

		// Repository layer
		userrepo.ProvideRepository,

		// Use case layer
		userusecase.ProvideCreateUserEntityUseCase,
		userusecase.ProvideSaveUserToRepoUseCase,
		userusecase.ProvideGetUserUseCase,
		gatewayuc.ProvideLoginUseCase,
		gatewayuc.ProvideHashPasswordUseCase,
		gatewayuc.ProvideVerifyPasswordUseCase,

		// Service layer
		service.ProvideSessionService,
		gatewaysvc.ProvideLoginService,

		// Middleware layer
		middleware.ProvideJWTMiddleware,
		middleware.ProvideSecurityHeadersMiddleware,
		middleware.ProvideRequestSizeLimitMiddleware,

		// Handler layer
		healthcheck.ProvideHealthCheckHandler,
		gateway.ProvideLoginHandler,

		// HTTP server
		http.ProvideServer,

		// Application
		ProvideApplication,
	)

	return nil, nil
}
```

### app/app.go

Application bootstrapper:

```go
package app

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http"
)

// Application represents the main application
type Application struct {
	config     *config.Config
	httpServer *http.Server
	logger     *zap.Logger
}

// ProvideApplication creates the application instance
func ProvideApplication(
	cfg *config.Config,
	httpServer *http.Server,
	logger *zap.Logger,
) *Application {
	return &Application{
		config:     cfg,
		httpServer: httpServer,
		logger:     logger,
	}
}

// Start starts the application
func (app *Application) Start() error {
	app.logger.Info("Starting application",
		zap.String("environment", app.config.App.Environment),
		zap.String("version", app.config.App.Version))

	// Start HTTP server in goroutine
	go func() {
		if err := app.httpServer.Start(); err != nil {
			app.logger.Fatal("HTTP server failed", zap.Error(err))
		}
	}()

	// Wait for interrupt signal
	app.waitForShutdown()

	return nil
}

// waitForShutdown waits for interrupt signal and performs graceful shutdown
func (app *Application) waitForShutdown() {
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	<-quit
	app.logger.Info("Shutting down application...")

	// Create context with timeout for graceful shutdown
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Shutdown HTTP server
	if err := app.httpServer.Shutdown(ctx); err != nil {
		app.logger.Error("HTTP server shutdown failed", zap.Error(err))
	}

	app.logger.Info("Application shutdown complete")
}
```

### Generate Wire Code

```bash
# Navigate to app directory
cd app

# Run wire to generate wire_gen.go
wire

# You should see: wire_gen.go created
```

### Add to .gitignore

```
app/wire_gen.go
```

---

## 7. Reusable pkg/ Components

The `pkg/` directory contains infrastructure components that can be copied directly from `maplepress-backend` and reused across projects.

### Components to Copy

#### 7.1 Logger (pkg/logger/)

**Copy from:** `cloud/maplepress-backend/pkg/logger/`

**Purpose:** Structured logging with Zap, including PII sanitization

**Key files:**
- `logger.go` - Logger provider and configuration
- `sanitizer.go` - Email and sensitive data sanitization

**Usage:**
```go
logger := logger.ProvideLogger(cfg)
logger.Info("User logged in", zap.String("user_id", userID))
logger.Error("Operation failed", zap.Error(err))
```

#### 7.2 Security (pkg/security/)

**Copy from:** `cloud/maplepress-backend/pkg/security/`

**Purpose:** Comprehensive security utilities

**Subpackages:**

##### JWT (pkg/security/jwt/)
```go
// Generate JWT tokens
jwtProvider := security.ProvideJWTProvider(cfg)
accessToken, accessExpiry, err := jwtProvider.GenerateToken(sessionID, 15*time.Minute)

// Validate JWT
sessionID, err := jwtProvider.ValidateToken(tokenString)
```

##### Password (pkg/security/password/)
```go
// Hash password
passwordProvider := password.NewPasswordProvider()
hashedPassword, err := passwordProvider.HashPassword("user-password")

// Verify password
isValid, err := passwordProvider.VerifyPassword("user-password", hashedPassword)

// Check for breached passwords (CWE-521)
breachChecker := password.NewBreachChecker()
isBreached, err := breachChecker.CheckPassword("user-password")
```

##### API Key (pkg/security/apikey/)
```go
// Generate API key
generator := apikey.ProvideGenerator()
apiKey := generator.Generate()  // Returns: "mp_live_abc123..."

// Hash API key for storage
hasher := apikey.ProvideHasher()
hashedKey, err := hasher.Hash(apiKey)

// Verify API key
isValid, err := hasher.Verify(apiKey, hashedKey)
```

##### Client IP (pkg/security/clientip/)
```go
// Extract client IP with X-Forwarded-For validation (CWE-348)
extractor := security.ProvideClientIPExtractor(cfg)
clientIP, err := extractor.ExtractIP(r)
```

##### IP Encryption (pkg/security/ipcrypt/)
```go
// Encrypt IP for GDPR compliance (CWE-359)
encryptor := ipcrypt.ProvideIPEncryptor(cfg)
encryptedIP, err := encryptor.Encrypt("192.168.1.1")
decryptedIP, err := encryptor.Decrypt(encryptedIP)
```

#### 7.3 Database (pkg/storage/database/)

**Copy from:** `cloud/maplepress-backend/pkg/storage/database/`

**Purpose:** Cassandra connection and migration management

```go
// Connect to Cassandra
session, err := database.ProvideCassandraSession(cfg, logger)

// Run migrations
migrator := database.NewMigrator(cfg, logger)
err := migrator.Up()
```

#### 7.4 Cache (pkg/cache/ and pkg/storage/cache/)

**Copy from:**
- `cloud/maplepress-backend/pkg/cache/`
- `cloud/maplepress-backend/pkg/storage/cache/`

**Purpose:** Redis client and two-tier caching (Redis + Cassandra)

```go
// Two-tier cache (fast Redis + persistent Cassandra)
cache := cache.ProvideTwoTierCache(redisCache, cassandraCache, logger)

// Set with TTL
err := cache.Set(ctx, "key", value, 1*time.Hour)

// Get
value, err := cache.Get(ctx, "key")

// Delete
err := cache.Delete(ctx, "key")
```

#### 7.5 Rate Limiting (pkg/ratelimit/)

**Copy from:** `cloud/maplepress-backend/pkg/ratelimit/`

**Purpose:** Redis-based rate limiting with configurable limits

```go
// Create rate limiter
limiter := ratelimit.NewRateLimiter(redisClient, logger)

// Check rate limit
allowed, err := limiter.Allow(ctx, "user:123", 100, time.Hour)
if !allowed {
	// Rate limit exceeded
}
```

#### 7.6 Distributed Mutex (pkg/distributedmutex/)

**Copy from:** `cloud/maplepress-backend/pkg/distributedmutex/`

**Purpose:** Redis-based distributed locking to prevent race conditions

```go
// Acquire lock
mutex := distributedmutex.ProvideDistributedMutexAdapter(redisClient, logger)
lock, err := mutex.Lock(ctx, "resource:123", 30*time.Second)
if err != nil {
	// Failed to acquire lock
}
defer lock.Unlock(ctx)

// Critical section protected by lock
// ...
```

#### 7.7 Validation (pkg/validation/)

**Copy from:** `cloud/maplepress-backend/pkg/validation/`

**Purpose:** Input validation utilities

```go
validator := validation.NewValidator()

// Validate email
if !validator.IsValidEmail("user@example.com") {
	// Invalid email
}

// Validate UUID
if !validator.IsValidUUID("123e4567-e89b-12d3-a456-426614174000") {
	// Invalid UUID
}
```

#### 7.8 HTTP Utilities (pkg/httperror/ and pkg/httpresponse/)

**Copy from:**
- `cloud/maplepress-backend/pkg/httperror/`
- `cloud/maplepress-backend/pkg/httpresponse/`

**Purpose:** Consistent HTTP error and response handling

```go
// Send error response
httperror.SendError(w, http.StatusBadRequest, "Invalid input", err)

// Send JSON response
httpresponse.SendJSON(w, http.StatusOK, map[string]interface{}{
	"message": "Success",
	"data": data,
})
```

#### 7.9 Transaction SAGA (pkg/transaction/)

**Copy from:** `cloud/maplepress-backend/pkg/transaction/`

**Purpose:** SAGA pattern for distributed transactions

```go
// Create SAGA
saga := transaction.NewSaga(logger)

// Add compensation steps
saga.AddStep(
	func(ctx context.Context) error {
		// Forward operation
		return createUser(ctx, user)
	},
	func(ctx context.Context) error {
		// Compensation (rollback)
		return deleteUser(ctx, user.ID)
	},
)

// Execute SAGA
err := saga.Execute(ctx)
if err != nil {
	// SAGA failed and all compensations were executed
}
```

### Copy Script

Create a script to copy all reusable components:

```bash
#!/bin/bash
# copy-pkg.sh - Copy reusable pkg/ components from maplepress-backend

SOURCE_DIR="../maplepress-backend/pkg"
DEST_DIR="./pkg"

# Create destination directory
mkdir -p "$DEST_DIR"

# Copy all pkg components
cp -r "$SOURCE_DIR/logger" "$DEST_DIR/"
cp -r "$SOURCE_DIR/security" "$DEST_DIR/"
cp -r "$SOURCE_DIR/storage" "$DEST_DIR/"
cp -r "$SOURCE_DIR/cache" "$DEST_DIR/"
cp -r "$SOURCE_DIR/ratelimit" "$DEST_DIR/"
cp -r "$SOURCE_DIR/distributedmutex" "$DEST_DIR/"
cp -r "$SOURCE_DIR/validation" "$DEST_DIR/"
cp -r "$SOURCE_DIR/httperror" "$DEST_DIR/"
cp -r "$SOURCE_DIR/httpresponse" "$DEST_DIR/"
cp -r "$SOURCE_DIR/httpvalidation" "$DEST_DIR/"
cp -r "$SOURCE_DIR/transaction" "$DEST_DIR/"

# Optional components (copy if needed)
# cp -r "$SOURCE_DIR/emailer" "$DEST_DIR/"
# cp -r "$SOURCE_DIR/search" "$DEST_DIR/"
# cp -r "$SOURCE_DIR/dns" "$DEST_DIR/"

echo "✅ All pkg/ components copied successfully"

# Update import paths
echo "⚠️  Remember to update import paths in copied files from:"
echo "   codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend"
echo "   to:"
echo "   codeberg.org/mapleopentech/monorepo/cloud/your-backend-name"
```

Run the script:

```bash
chmod +x copy-pkg.sh
./copy-pkg.sh
```

### Update Import Paths

After copying, you'll need to update import paths in all copied files:

```bash
# Find and replace import paths
find ./pkg -type f -name "*.go" -exec sed -i '' \
  's|codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend|codeberg.org/mapleopentech/monorepo/cloud/your-backend-name|g' \
  {} +
```

---

## 8. Authentication System

Our authentication system uses JWT tokens with session management stored in a two-tier cache (Redis + Cassandra).

### 8.1 Authentication Flow

```
┌──────────┐
│  Client  │
└─────┬────┘
      │ 1. POST /api/v1/login
      │    {email, password}
      ↓
┌─────────────────────────┐
│   Login Handler         │
└────────┬────────────────┘
         │ 2. Validate input
         ↓
┌─────────────────────────┐
│   Login Service         │
└────────┬────────────────┘
         │ 3. Verify credentials
         │ 4. Create session
         │ 5. Generate JWT tokens
         ↓
┌─────────────────────────┐
│   Session Service       │
│   (Two-Tier Cache)      │
└────────┬────────────────┘
         │ 6. Store in Redis (fast)
         │ 7. Store in Cassandra (persistent)
         ↓
┌─────────────────────────┐
│   Response              │
│   - access_token        │
│   - refresh_token       │
│   - user_info           │
└─────────────────────────┘
```

### 8.2 Session Service Implementation

**internal/service/session.go:**

```go
package service

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/google/uuid"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/domain"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/cache"
)

const (
	SessionTTL = 24 * time.Hour // Session expires after 24 hours
)

// SessionService handles session management
type SessionService interface {
	CreateSession(ctx context.Context, userID uint64, userUUID uuid.UUID, email, name, role string, tenantID uuid.UUID) (*domain.Session, error)
	GetSession(ctx context.Context, sessionID string) (*domain.Session, error)
	DeleteSession(ctx context.Context, sessionID string) error
	InvalidateUserSessions(ctx context.Context, userUUID uuid.UUID) error
}

type sessionService struct {
	cache  cache.TwoTierCacher
	logger *zap.Logger
}

// ProvideSessionService provides a session service instance
func ProvideSessionService(cache cache.TwoTierCacher, logger *zap.Logger) SessionService {
	return &sessionService{
		cache:  cache,
		logger: logger.Named("session-service"),
	}
}

// CreateSession creates a new session and stores it in cache
func (s *sessionService) CreateSession(
	ctx context.Context,
	userID uint64,
	userUUID uuid.UUID,
	email, name, role string,
	tenantID uuid.UUID,
) (*domain.Session, error) {
	// Generate unique session ID
	sessionID := uuid.New().String()

	// Create session object
	session := &domain.Session{
		ID:        sessionID,
		UserID:    userID,
		UserUUID:  userUUID,
		UserEmail: email,
		UserName:  name,
		UserRole:  role,
		TenantID:  tenantID,
		CreatedAt: time.Now().UTC(),
		ExpiresAt: time.Now().UTC().Add(SessionTTL),
	}

	// Serialize to JSON
	sessionJSON, err := json.Marshal(session)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal session: %w", err)
	}

	// Store in two-tier cache (Redis + Cassandra)
	cacheKey := fmt.Sprintf("session:%s", sessionID)
	if err := s.cache.Set(ctx, cacheKey, sessionJSON, SessionTTL); err != nil {
		return nil, fmt.Errorf("failed to store session: %w", err)
	}

	s.logger.Info("Session created",
		zap.String("session_id", sessionID),
		zap.String("user_uuid", userUUID.String()))

	return session, nil
}

// GetSession retrieves a session from cache
func (s *sessionService) GetSession(ctx context.Context, sessionID string) (*domain.Session, error) {
	cacheKey := fmt.Sprintf("session:%s", sessionID)

	// Get from two-tier cache (tries Redis first, falls back to Cassandra)
	sessionJSON, err := s.cache.Get(ctx, cacheKey)
	if err != nil {
		return nil, fmt.Errorf("session not found: %w", err)
	}

	// Deserialize from JSON
	var session domain.Session
	if err := json.Unmarshal(sessionJSON, &session); err != nil {
		return nil, fmt.Errorf("failed to unmarshal session: %w", err)
	}

	// Check if session is expired
	if time.Now().UTC().After(session.ExpiresAt) {
		// Delete expired session
		_ = s.DeleteSession(ctx, sessionID)
		return nil, fmt.Errorf("session expired")
	}

	return &session, nil
}

// DeleteSession removes a session from cache
func (s *sessionService) DeleteSession(ctx context.Context, sessionID string) error {
	cacheKey := fmt.Sprintf("session:%s", sessionID)
	return s.cache.Delete(ctx, cacheKey)
}

// InvalidateUserSessions invalidates all sessions for a user (CWE-384: Session Fixation Prevention)
func (s *sessionService) InvalidateUserSessions(ctx context.Context, userUUID uuid.UUID) error {
	// Note: This is a simplified implementation
	// In production, you should maintain a user->sessions mapping in cache
	// For now, sessions will naturally expire after SessionTTL
	s.logger.Info("Invalidating user sessions",
		zap.String("user_uuid", userUUID.String()))
	return nil
}
```

### 8.3 Domain Session Entity

**internal/domain/session.go:**

```go
package domain

import (
	"time"

	"github.com/google/uuid"
)

// Session represents a user session
type Session struct {
	ID        string    `json:"id"`
	UserID    uint64    `json:"user_id"`
	UserUUID  uuid.UUID `json:"user_uuid"`
	UserEmail string    `json:"user_email"`
	UserName  string    `json:"user_name"`
	UserRole  string    `json:"user_role"`
	TenantID  uuid.UUID `json:"tenant_id"`
	CreatedAt time.Time `json:"created_at"`
	ExpiresAt time.Time `json:"expires_at"`
}
```

### 8.4 JWT Middleware

**internal/http/middleware/jwt.go:**

```go
package middleware

import (
	"context"
	"net/http"
	"strings"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config/constants"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/service"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/security/jwt"
)

// JWTMiddleware validates JWT tokens and populates session context
type JWTMiddleware struct {
	jwtProvider    jwt.Provider
	sessionService service.SessionService
	logger         *zap.Logger
}

// NewJWTMiddleware creates a new JWT middleware
func NewJWTMiddleware(
	jwtProvider jwt.Provider,
	sessionService service.SessionService,
	logger *zap.Logger,
) *JWTMiddleware {
	return &JWTMiddleware{
		jwtProvider:    jwtProvider,
		sessionService: sessionService,
		logger:         logger.Named("jwt-middleware"),
	}
}

// ProvideJWTMiddleware provides JWT middleware for Wire
func ProvideJWTMiddleware(
	jwtProvider jwt.Provider,
	sessionService service.SessionService,
	logger *zap.Logger,
) *JWTMiddleware {
	return NewJWTMiddleware(jwtProvider, sessionService, logger)
}

// Handler validates JWT and populates context
func (m *JWTMiddleware) Handler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Get Authorization header
		authHeader := r.Header.Get("Authorization")
		if authHeader == "" {
			ctx := context.WithValue(r.Context(), constants.SessionIsAuthorized, false)
			next.ServeHTTP(w, r.WithContext(ctx))
			return
		}

		// Expected format: "JWT <token>"
		parts := strings.Split(authHeader, " ")
		if len(parts) != 2 || parts[0] != "JWT" {
			ctx := context.WithValue(r.Context(), constants.SessionIsAuthorized, false)
			next.ServeHTTP(w, r.WithContext(ctx))
			return
		}

		token := parts[1]

		// Validate token
		sessionID, err := m.jwtProvider.ValidateToken(token)
		if err != nil {
			ctx := context.WithValue(r.Context(), constants.SessionIsAuthorized, false)
			next.ServeHTTP(w, r.WithContext(ctx))
			return
		}

		// Get session from cache
		session, err := m.sessionService.GetSession(r.Context(), sessionID)
		if err != nil {
			ctx := context.WithValue(r.Context(), constants.SessionIsAuthorized, false)
			next.ServeHTTP(w, r.WithContext(ctx))
			return
		}

		// Populate context with session data
		ctx := r.Context()
		ctx = context.WithValue(ctx, constants.SessionIsAuthorized, true)
		ctx = context.WithValue(ctx, constants.SessionID, session.ID)
		ctx = context.WithValue(ctx, constants.SessionUserUUID, session.UserUUID.String())
		ctx = context.WithValue(ctx, constants.SessionUserEmail, session.UserEmail)
		ctx = context.WithValue(ctx, constants.SessionUserName, session.UserName)
		ctx = context.WithValue(ctx, constants.SessionUserRole, session.UserRole)
		ctx = context.WithValue(ctx, constants.SessionTenantID, session.TenantID.String())

		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// RequireAuth ensures the request is authenticated
func (m *JWTMiddleware) RequireAuth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		isAuthorized, ok := r.Context().Value(constants.SessionIsAuthorized).(bool)
		if !ok || !isAuthorized {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}
```

### 8.5 Login Handler Example

**internal/interface/http/handler/gateway/login_handler.go:**

```go
package gateway

import (
	"encoding/json"
	"net/http"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/dto/gateway"
	gatewaysvc "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/service/gateway"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/httperror"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/httpresponse"
)

// LoginHandler handles user login
type LoginHandler struct {
	loginService gatewaysvc.LoginService
	logger       *zap.Logger
}

// ProvideLoginHandler provides a login handler for Wire
func ProvideLoginHandler(
	loginService gatewaysvc.LoginService,
	logger *zap.Logger,
) *LoginHandler {
	return &LoginHandler{
		loginService: loginService,
		logger:       logger.Named("login-handler"),
	}
}

// Handle processes login requests
func (h *LoginHandler) Handle(w http.ResponseWriter, r *http.Request) {
	// Parse request
	var req gateway.LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httperror.SendError(w, http.StatusBadRequest, "Invalid request body", err)
		return
	}

	// Validate input
	if req.Email == "" || req.Password == "" {
		httperror.SendError(w, http.StatusBadRequest, "Email and password are required", nil)
		return
	}

	// Execute login
	response, err := h.loginService.Login(r.Context(), &gatewaysvc.LoginInput{
		Email:    req.Email,
		Password: req.Password,
	})
	if err != nil {
		h.logger.Error("Login failed", zap.Error(err))
		httperror.SendError(w, http.StatusUnauthorized, "Invalid credentials", err)
		return
	}

	// Send response
	httpresponse.SendJSON(w, http.StatusOK, response)
}
```

---

## 9. Clean Architecture Layers

### Layer Structure

#### 9.1 Domain Layer (internal/domain/)

**Purpose:** Core business entities and repository interfaces

**Example: User Entity**

```go
// internal/domain/user/entity.go
package user

import (
	"time"

	"github.com/google/uuid"
)

// User represents a user entity
type User struct {
	ID        uuid.UUID
	TenantID  uuid.UUID
	Email     string
	Name      string
	Role      string
	Password  string // Hashed
	Status    string
	CreatedAt time.Time
	UpdatedAt time.Time
}
```

**Example: User Repository Interface**

```go
// internal/domain/user/repository.go
package user

import (
	"context"

	"github.com/google/uuid"
)

// Repository defines user data access interface
type Repository interface {
	Create(ctx context.Context, user *User) error
	GetByID(ctx context.Context, id uuid.UUID) (*User, error)
	GetByEmail(ctx context.Context, email string) (*User, error)
	Update(ctx context.Context, user *User) error
	Delete(ctx context.Context, id uuid.UUID) error
}
```

#### 9.2 Repository Layer (internal/repository/)

**Purpose:** Data access implementations

**Example: User Repository Implementation**

```go
// internal/repository/user/impl.go
package user

import (
	"context"

	"github.com/gocql/gocql"
	"github.com/google/uuid"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/domain/user"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/cache"
)

type repository struct {
	session *gocql.Session
	cache   cache.TwoTierCacher
	logger  *zap.Logger
}

// ProvideRepository provides a user repository for Wire
func ProvideRepository(
	session *gocql.Session,
	cache cache.TwoTierCacher,
	logger *zap.Logger,
) user.Repository {
	return &repository{
		session: session,
		cache:   cache,
		logger:  logger.Named("user-repository"),
	}
}

// Create creates a new user
func (r *repository) Create(ctx context.Context, user *user.User) error {
	query := `
		INSERT INTO users (id, tenant_id, email, name, role, password, status, created_at, updated_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
	`

	return r.session.Query(query,
		user.ID,
		user.TenantID,
		user.Email,
		user.Name,
		user.Role,
		user.Password,
		user.Status,
		user.CreatedAt,
		user.UpdatedAt,
	).WithContext(ctx).Exec()
}

// GetByID retrieves a user by ID
func (r *repository) GetByID(ctx context.Context, id uuid.UUID) (*user.User, error) {
	// Try cache first
	cacheKey := fmt.Sprintf("user:id:%s", id.String())
	if cachedData, err := r.cache.Get(ctx, cacheKey); err == nil {
		var u user.User
		if err := json.Unmarshal(cachedData, &u); err == nil {
			return &u, nil
		}
	}

	// Query database
	query := `
		SELECT id, tenant_id, email, name, role, password, status, created_at, updated_at
		FROM users
		WHERE id = ?
	`

	var u user.User
	err := r.session.Query(query, id).
		WithContext(ctx).
		Scan(&u.ID, &u.TenantID, &u.Email, &u.Name, &u.Role, &u.Password, &u.Status, &u.CreatedAt, &u.UpdatedAt)

	if err != nil {
		return nil, err
	}

	// Cache result
	if data, err := json.Marshal(u); err == nil {
		_ = r.cache.Set(ctx, cacheKey, data, 15*time.Minute)
	}

	return &u, nil
}
```

#### 9.3 Use Case Layer (internal/usecase/)

**Purpose:** Focused, single-responsibility business operations

**Example: Create User Entity Use Case**

```go
// internal/usecase/user/create_user_entity.go
package user

import (
	"context"
	"time"

	"github.com/google/uuid"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config/constants"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/domain/user"
)

// CreateUserEntityUseCase creates a user entity from input
type CreateUserEntityUseCase struct {
	logger *zap.Logger
}

// ProvideCreateUserEntityUseCase provides the use case for Wire
func ProvideCreateUserEntityUseCase(logger *zap.Logger) *CreateUserEntityUseCase {
	return &CreateUserEntityUseCase{
		logger: logger.Named("create-user-entity-uc"),
	}
}

// CreateUserEntityInput represents the input
type CreateUserEntityInput struct {
	TenantID       uuid.UUID
	Email          string
	Name           string
	Role           string
	HashedPassword string
}

// Execute creates a user entity
func (uc *CreateUserEntityUseCase) Execute(
	ctx context.Context,
	input *CreateUserEntityInput,
) (*user.User, error) {
	now := time.Now().UTC()

	entity := &user.User{
		ID:        uuid.New(),
		TenantID:  input.TenantID,
		Email:     input.Email,
		Name:      input.Name,
		Role:      input.Role,
		Password:  input.HashedPassword,
		Status:    constants.TenantStatusActive,
		CreatedAt: now,
		UpdatedAt: now,
	}

	uc.logger.Info("User entity created",
		zap.String("user_id", entity.ID.String()),
		zap.String("email", entity.Email))

	return entity, nil
}
```

**Example: Save User to Repo Use Case**

```go
// internal/usecase/user/save_user_to_repo.go
package user

import (
	"context"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/domain/user"
)

// SaveUserToRepoUseCase saves a user to repository
type SaveUserToRepoUseCase struct {
	repo   user.Repository
	logger *zap.Logger
}

// ProvideSaveUserToRepoUseCase provides the use case for Wire
func ProvideSaveUserToRepoUseCase(
	repo user.Repository,
	logger *zap.Logger,
) *SaveUserToRepoUseCase {
	return &SaveUserToRepoUseCase{
		repo:   repo,
		logger: logger.Named("save-user-to-repo-uc"),
	}
}

// Execute saves the user
func (uc *SaveUserToRepoUseCase) Execute(
	ctx context.Context,
	user *user.User,
) error {
	if err := uc.repo.Create(ctx, user); err != nil {
		uc.logger.Error("Failed to save user",
			zap.String("user_id", user.ID.String()),
			zap.Error(err))
		return err
	}

	uc.logger.Info("User saved to repository",
		zap.String("user_id", user.ID.String()))

	return nil
}
```

#### 9.4 Service Layer (internal/service/)

**Purpose:** Orchestration logic, transaction management (SAGA)

**Example: Create User Service**

```go
// internal/service/user/create.go
package user

import (
	"context"
	"fmt"

	"github.com/google/uuid"
	"go.uber.org/zap"

	userusecase "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/usecase/user"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/security/password"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/transaction"
)

// CreateUserService handles user creation orchestration
type CreateUserService interface {
	Create(ctx context.Context, input *CreateUserInput) (*CreateUserResponse, error)
}

type createUserService struct {
	validateEmailUC userusecase.ValidateUserEmailUniqueUseCase
	createEntityUC  *userusecase.CreateUserEntityUseCase
	saveToRepoUC    *userusecase.SaveUserToRepoUseCase
	passwordProvider password.Provider
	logger          *zap.Logger
}

// ProvideCreateUserService provides the service for Wire
func ProvideCreateUserService(
	validateEmailUC *userusecase.ValidateUserEmailUniqueUseCase,
	createEntityUC *userusecase.CreateUserEntityUseCase,
	saveToRepoUC *userusecase.SaveUserToRepoUseCase,
	passwordProvider password.Provider,
	logger *zap.Logger,
) CreateUserService {
	return &createUserService{
		validateEmailUC: validateEmailUC,
		createEntityUC:  createEntityUC,
		saveToRepoUC:    saveToRepoUC,
		passwordProvider: passwordProvider,
		logger:          logger.Named("create-user-service"),
	}
}

type CreateUserInput struct {
	TenantID uuid.UUID
	Email    string
	Name     string
	Role     string
	Password string
}

type CreateUserResponse struct {
	UserID string
	Email  string
	Name   string
	Role   string
}

// Create orchestrates user creation with SAGA pattern
func (s *createUserService) Create(
	ctx context.Context,
	input *CreateUserInput,
) (*CreateUserResponse, error) {
	// Validate email uniqueness
	if err := s.validateEmailUC.Execute(ctx, input.Email); err != nil {
		return nil, fmt.Errorf("email validation failed: %w", err)
	}

	// Hash password
	hashedPassword, err := s.passwordProvider.HashPassword(input.Password)
	if err != nil {
		return nil, fmt.Errorf("password hashing failed: %w", err)
	}

	// Create user entity
	userEntity, err := s.createEntityUC.Execute(ctx, &userusecase.CreateUserEntityInput{
		TenantID:       input.TenantID,
		Email:          input.Email,
		Name:           input.Name,
		Role:           input.Role,
		HashedPassword: hashedPassword,
	})
	if err != nil {
		return nil, fmt.Errorf("entity creation failed: %w", err)
	}

	// Use SAGA pattern for transaction management
	saga := transaction.NewSaga(s.logger)

	// Step 1: Save user to repository
	saga.AddStep(
		func(ctx context.Context) error {
			return s.saveToRepoUC.Execute(ctx, userEntity)
		},
		func(ctx context.Context) error {
			// Compensation: Delete user if subsequent steps fail
			// (implement delete use case)
			s.logger.Warn("Compensating: deleting user", zap.String("user_id", userEntity.ID.String()))
			return nil
		},
	)

	// Execute SAGA
	if err := saga.Execute(ctx); err != nil {
		return nil, fmt.Errorf("user creation failed: %w", err)
	}

	return &CreateUserResponse{
		UserID: userEntity.ID.String(),
		Email:  userEntity.Email,
		Name:   userEntity.Name,
		Role:   userEntity.Role,
	}, nil
}
```

#### 9.5 Interface Layer (internal/interface/http/)

**Purpose:** HTTP handlers and DTOs

**Example: Create User Handler**

```go
// internal/interface/http/handler/user/create_handler.go
package user

import (
	"encoding/json"
	"net/http"

	"github.com/google/uuid"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config/constants"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/dto/user"
	usersvc "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/service/user"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/httperror"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/pkg/httpresponse"
)

// CreateHandler handles user creation
type CreateHandler struct {
	createService usersvc.CreateUserService
	logger        *zap.Logger
}

// ProvideCreateHandler provides the handler for Wire
func ProvideCreateHandler(
	createService usersvc.CreateUserService,
	logger *zap.Logger,
) *CreateHandler {
	return &CreateHandler{
		createService: createService,
		logger:        logger.Named("create-user-handler"),
	}
}

// Handle processes user creation requests
func (h *CreateHandler) Handle(w http.ResponseWriter, r *http.Request) {
	// Get tenant ID from context (populated by JWT middleware)
	tenantIDStr, ok := r.Context().Value(constants.SessionTenantID).(string)
	if !ok {
		httperror.SendError(w, http.StatusUnauthorized, "Tenant ID not found", nil)
		return
	}

	tenantID, err := uuid.Parse(tenantIDStr)
	if err != nil {
		httperror.SendError(w, http.StatusBadRequest, "Invalid tenant ID", err)
		return
	}

	// Parse request
	var req user.CreateUserRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		httperror.SendError(w, http.StatusBadRequest, "Invalid request body", err)
		return
	}

	// Validate input
	if req.Email == "" || req.Password == "" || req.Name == "" {
		httperror.SendError(w, http.StatusBadRequest, "Missing required fields", nil)
		return
	}

	// Create user
	response, err := h.createService.Create(r.Context(), &usersvc.CreateUserInput{
		TenantID: tenantID,
		Email:    req.Email,
		Name:     req.Name,
		Role:     req.Role,
		Password: req.Password,
	})
	if err != nil {
		h.logger.Error("User creation failed", zap.Error(err))
		httperror.SendError(w, http.StatusInternalServerError, "Failed to create user", err)
		return
	}

	// Send response
	httpresponse.SendJSON(w, http.StatusCreated, response)
}
```

---

## 10. Database Setup (Cassandra)

### 10.1 Cassandra Schema Design

**Design Principles:**
1. **Query-driven modeling** - Design tables based on query patterns
2. **Denormalization** - Duplicate data to avoid joins
3. **Partition keys** - Choose keys that distribute data evenly
4. **Clustering keys** - Define sort order within partitions

**Example Migration:**

```cql
-- migrations/000001_create_users.up.cql

-- Users table (by ID)
CREATE TABLE IF NOT EXISTS users (
    id uuid,
    tenant_id uuid,
    email text,
    name text,
    role text,
    password text,
    status text,
    created_at timestamp,
    updated_at timestamp,
    PRIMARY KEY (id)
);

-- Users by email (for login lookups)
CREATE TABLE IF NOT EXISTS users_by_email (
    email text,
    tenant_id uuid,
    user_id uuid,
    PRIMARY KEY (email)
);

-- Users by tenant (for listing users in a tenant)
CREATE TABLE IF NOT EXISTS users_by_tenant (
    tenant_id uuid,
    user_id uuid,
    email text,
    name text,
    role text,
    status text,
    created_at timestamp,
    PRIMARY KEY (tenant_id, created_at, user_id)
) WITH CLUSTERING ORDER BY (created_at DESC, user_id ASC);

-- Create indexes
CREATE INDEX IF NOT EXISTS users_status_idx ON users (status);
CREATE INDEX IF NOT EXISTS users_tenant_idx ON users (tenant_id);
```

```cql
-- migrations/000001_create_users.down.cql

DROP TABLE IF EXISTS users_by_tenant;
DROP TABLE IF EXISTS users_by_email;
DROP INDEX IF EXISTS users_tenant_idx;
DROP INDEX IF EXISTS users_status_idx;
DROP TABLE IF EXISTS users;
```

### 10.2 Migration Management

**pkg/storage/database/migrator.go:**

```go
package database

import (
	"fmt"

	"github.com/golang-migrate/migrate/v4"
	_ "github.com/golang-migrate/migrate/v4/database/cassandra"
	_ "github.com/golang-migrate/migrate/v4/source/file"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
)

// Migrator handles database migrations
type Migrator struct {
	migrate *migrate.Migrate
	logger  *zap.Logger
}

// NewMigrator creates a new migrator
func NewMigrator(cfg *config.Config, logger *zap.Logger) *Migrator {
	// Build Cassandra connection string
	dbURL := fmt.Sprintf("cassandra://%s/%s?consistency=%s",
		cfg.Database.Hosts[0],
		cfg.Database.Keyspace,
		cfg.Database.Consistency,
	)

	// Create migrate instance
	m, err := migrate.New(cfg.Database.MigrationsPath, dbURL)
	if err != nil {
		logger.Fatal("Failed to create migrator", zap.Error(err))
	}

	return &Migrator{
		migrate: m,
		logger:  logger.Named("migrator"),
	}
}

// Up runs all pending migrations
func (m *Migrator) Up() error {
	m.logger.Info("Running migrations...")
	if err := m.migrate.Up(); err != nil && err != migrate.ErrNoChange {
		return fmt.Errorf("migration failed: %w", err)
	}

	version, _, _ := m.migrate.Version()
	m.logger.Info("Migrations completed",
		zap.Uint("version", uint(version)))

	return nil
}

// Down rolls back the last migration
func (m *Migrator) Down() error {
	m.logger.Info("Rolling back last migration...")
	if err := m.migrate.Steps(-1); err != nil {
		return fmt.Errorf("rollback failed: %w", err)
	}

	version, _, _ := m.migrate.Version()
	m.logger.Info("Rollback completed",
		zap.Uint("version", uint(version)))

	return nil
}

// Version returns current migration version
func (m *Migrator) Version() (uint, bool, error) {
	return m.migrate.Version()
}

// ForceVersion forces migration to specific version
func (m *Migrator) ForceVersion(version int) error {
	m.logger.Warn("Forcing migration version",
		zap.Int("version", version))
	return m.migrate.Force(version)
}
```

---

## 11. Middleware Implementation

### 11.1 Security Headers Middleware

**internal/http/middleware/security_headers.go:**

```go
package middleware

import (
	"net/http"
	"strings"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
)

// SecurityHeadersMiddleware adds security headers to responses
type SecurityHeadersMiddleware struct {
	config *config.Config
	logger *zap.Logger
}

// ProvideSecurityHeadersMiddleware provides the middleware for Wire
func ProvideSecurityHeadersMiddleware(
	cfg *config.Config,
	logger *zap.Logger,
) *SecurityHeadersMiddleware {
	return &SecurityHeadersMiddleware{
		config: cfg,
		logger: logger.Named("security-headers-middleware"),
	}
}

// Handler applies security headers
func (m *SecurityHeadersMiddleware) Handler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// CWE-693: Apply security headers

		// CORS headers
		origin := r.Header.Get("Origin")
		if m.isAllowedOrigin(origin) {
			w.Header().Set("Access-Control-Allow-Origin", origin)
			w.Header().Set("Access-Control-Allow-Credentials", "true")
		}

		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Tenant-ID")
		w.Header().Set("Access-Control-Max-Age", "86400") // 24 hours

		// Handle preflight requests
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
			return
		}

		// Security headers (CWE-693: Protection Mechanism Failure)
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("X-Frame-Options", "DENY")
		w.Header().Set("X-XSS-Protection", "1; mode=block")
		w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
		w.Header().Set("Content-Security-Policy", "default-src 'self'")
		w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")

		next.ServeHTTP(w, r)
	})
}

// isAllowedOrigin checks if origin is in allowed list
func (m *SecurityHeadersMiddleware) isAllowedOrigin(origin string) bool {
	if origin == "" {
		return false
	}

	// In development, allow localhost
	if m.config.App.Environment == "development" {
		if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") {
			return true
		}
	}

	// Check against configured allowed origins
	for _, allowed := range m.config.Security.AllowedOrigins {
		if origin == allowed {
			return true
		}
	}

	return false
}
```

### 11.2 Request Size Limit Middleware

**internal/http/middleware/request_size_limit.go:**

```go
package middleware

import (
	"net/http"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
)

// RequestSizeLimitMiddleware limits request body size
type RequestSizeLimitMiddleware struct {
	config *config.Config
	logger *zap.Logger
}

// ProvideRequestSizeLimitMiddleware provides the middleware for Wire
func ProvideRequestSizeLimitMiddleware(
	cfg *config.Config,
	logger *zap.Logger,
) *RequestSizeLimitMiddleware {
	return &RequestSizeLimitMiddleware{
		config: cfg,
		logger: logger.Named("request-size-limit-middleware"),
	}
}

// LimitSmall applies 1MB limit (for auth endpoints)
func (m *RequestSizeLimitMiddleware) LimitSmall() func(http.Handler) http.Handler {
	return m.limitWithSize(1 * 1024 * 1024) // 1 MB
}

// LimitMedium applies 5MB limit (for typical API endpoints)
func (m *RequestSizeLimitMiddleware) LimitMedium() func(http.Handler) http.Handler {
	return m.limitWithSize(5 * 1024 * 1024) // 5 MB
}

// LimitLarge applies 50MB limit (for file uploads)
func (m *RequestSizeLimitMiddleware) LimitLarge() func(http.Handler) http.Handler {
	return m.limitWithSize(50 * 1024 * 1024) // 50 MB
}

// limitWithSize creates a middleware with specific size limit
func (m *RequestSizeLimitMiddleware) limitWithSize(maxBytes int64) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Limit request body size (CWE-770: Resource Exhaustion)
			r.Body = http.MaxBytesReader(w, r.Body, maxBytes)

			next.ServeHTTP(w, r)
		})
	}
}
```

---

## 12. HTTP Server Setup

### internal/interface/http/server.go

```go
package http

import (
	"context"
	"fmt"
	"net/http"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
	httpmw "codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/http/middleware"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/handler/gateway"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/handler/healthcheck"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/internal/interface/http/middleware"
)

// Server represents the HTTP server
type Server struct {
	server                    *http.Server
	logger                    *zap.Logger
	jwtMiddleware             *httpmw.JWTMiddleware
	securityHeadersMiddleware *httpmw.SecurityHeadersMiddleware
	requestSizeLimitMw        *httpmw.RequestSizeLimitMiddleware
	config                    *config.Config
	healthHandler             *healthcheck.Handler
	loginHandler              *gateway.LoginHandler
}

// ProvideServer creates a new HTTP server
func ProvideServer(
	cfg *config.Config,
	logger *zap.Logger,
	jwtMiddleware *httpmw.JWTMiddleware,
	securityHeadersMiddleware *httpmw.SecurityHeadersMiddleware,
	requestSizeLimitMw *httpmw.RequestSizeLimitMiddleware,
	healthHandler *healthcheck.Handler,
	loginHandler *gateway.LoginHandler,
) *Server {
	mux := http.NewServeMux()

	s := &Server{
		logger:                    logger,
		jwtMiddleware:             jwtMiddleware,
		securityHeadersMiddleware: securityHeadersMiddleware,
		requestSizeLimitMw:        requestSizeLimitMw,
		config:                    cfg,
		healthHandler:             healthHandler,
		loginHandler:              loginHandler,
	}

	// Register routes
	s.registerRoutes(mux)

	// Create HTTP server
	s.server = &http.Server{
		Addr:         fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
		Handler:      s.applyMiddleware(mux),
		ReadTimeout:  cfg.HTTP.ReadTimeout,
		WriteTimeout: cfg.HTTP.WriteTimeout,
		IdleTimeout:  cfg.HTTP.IdleTimeout,
	}

	logger.Info("✓ HTTP server configured",
		zap.String("address", s.server.Addr),
		zap.Duration("read_timeout", cfg.HTTP.ReadTimeout),
		zap.Duration("write_timeout", cfg.HTTP.WriteTimeout))

	return s
}

// registerRoutes registers all HTTP routes
func (s *Server) registerRoutes(mux *http.ServeMux) {
	// ===== PUBLIC ROUTES =====
	mux.HandleFunc("GET /health", s.healthHandler.Handle)

	// Authentication routes
	mux.HandleFunc("POST /api/v1/login",
		s.requestSizeLimitMw.LimitSmall()(
			http.HandlerFunc(s.loginHandler.Handle),
		).ServeHTTP)

	// ===== AUTHENTICATED ROUTES =====
	// Add your authenticated routes here with JWT middleware
	// Example:
	// mux.HandleFunc("GET /api/v1/me", s.applyAuthOnly(s.meHandler.Handle))
}

// applyMiddleware applies global middleware to all routes
func (s *Server) applyMiddleware(handler http.Handler) http.Handler {
	// Apply middleware in order
	handler = middleware.LoggerMiddleware(s.logger)(handler)
	handler = s.securityHeadersMiddleware.Handler(handler)
	return handler
}

// applyAuthOnly applies only JWT authentication middleware
func (s *Server) applyAuthOnly(handler http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		s.jwtMiddleware.Handler(
			s.jwtMiddleware.RequireAuth(
				http.HandlerFunc(handler),
			),
		).ServeHTTP(w, r)
	}
}

// Start starts the HTTP server
func (s *Server) Start() error {
	s.logger.Info("")
	s.logger.Info("🚀 Backend is ready!")
	s.logger.Info("",
		zap.String("address", s.server.Addr),
		zap.String("url", fmt.Sprintf("http://localhost:%d", s.config.Server.Port)))
	s.logger.Info("")

	if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		return fmt.Errorf("failed to start server: %w", err)
	}

	return nil
}

// Shutdown gracefully shuts down the HTTP server
func (s *Server) Shutdown(ctx context.Context) error {
	s.logger.Info("shutting down HTTP server")

	if err := s.server.Shutdown(ctx); err != nil {
		return fmt.Errorf("failed to shutdown server: %w", err)
	}

	s.logger.Info("HTTP server shut down successfully")
	return nil
}
```

---

## 13. Docker & Infrastructure

### 13.1 Development Dockerfile

**dev.Dockerfile:**

```dockerfile
FROM golang:1.24-alpine

# Install development tools
RUN apk add --no-cache git curl bash

# Set working directory
WORKDIR /go/src/codeberg.org/mapleopentech/monorepo/cloud/your-backend-name

# Install Wire
RUN go install github.com/google/wire/cmd/wire@latest

# Copy go.mod and go.sum
COPY go.mod go.sum ./

# Download dependencies
RUN go mod download

# Copy source code
COPY . .

# Generate Wire code
RUN cd app && wire

# Build the application
RUN go build -o app-dev .

# Expose port
EXPOSE 8000

# Run the application
CMD ["./app-dev", "daemon"]
```

### 13.2 Production Dockerfile

**Dockerfile:**

```dockerfile
###
### Build Stage
###

FROM golang:1.24-alpine AS build-env

# Create app directory
RUN mkdir /app
WORKDIR /app

# Copy dependency list
COPY go.mod go.sum ./

# Install dependencies
RUN go mod download

# Copy all files
COPY . .

# Install Wire
RUN go install github.com/google/wire/cmd/wire@latest

# Generate Wire code
RUN cd app && wire

# Build for Linux AMD64
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app-backend .

###
### Run Stage
###

FROM alpine:latest

WORKDIR /app

# Copy executable
COPY --from=build-env /app/app-backend .

# Copy migrations
COPY --from=build-env /app/migrations ./migrations

# Copy static files (if any)
COPY --from=build-env /app/static ./static

EXPOSE 8000

# Run the server
CMD ["/app/app-backend", "daemon"]
```

### 13.3 Docker Compose (Development)

**docker-compose.dev.yml:**

```yaml
# Use external network from shared infrastructure
networks:
  mapleopentech-dev:
    external: true

services:
  app:
    container_name: your-backend-dev
    stdin_open: true
    build:
      context: .
      dockerfile: ./dev.Dockerfile
    ports:
      - "${SERVER_PORT:-8000}:${SERVER_PORT:-8000}"
    env_file:
      - .env
    environment:
      # Application
      APP_ENVIRONMENT: ${APP_ENVIRONMENT:-development}
      APP_VERSION: ${APP_VERSION:-0.1.0-dev}
      APP_JWT_SECRET: ${APP_JWT_SECRET:-dev-secret}

      # Server
      SERVER_HOST: ${SERVER_HOST:-0.0.0.0}
      SERVER_PORT: ${SERVER_PORT:-8000}

      # Cassandra (connect to shared infrastructure)
      DATABASE_HOSTS: ${DATABASE_HOSTS:-cassandra-1:9042,cassandra-2:9042,cassandra-3:9042}
      DATABASE_KEYSPACE: ${DATABASE_KEYSPACE:-your_keyspace}
      DATABASE_CONSISTENCY: ${DATABASE_CONSISTENCY:-ONE}
      DATABASE_REPLICATION: ${DATABASE_REPLICATION:-3}
      DATABASE_MIGRATIONS_PATH: ${DATABASE_MIGRATIONS_PATH:-file://migrations}

      # Redis (connect to shared infrastructure)
      CACHE_HOST: ${CACHE_HOST:-redis}
      CACHE_PORT: ${CACHE_PORT:-6379}
      CACHE_PASSWORD: ${CACHE_PASSWORD:-}
      CACHE_DB: ${CACHE_DB:-0}

      # Logger
      LOGGER_LEVEL: ${LOGGER_LEVEL:-debug}
      LOGGER_FORMAT: ${LOGGER_FORMAT:-console}

    volumes:
      - ./:/go/src/codeberg.org/mapleopentech/monorepo/cloud/your-backend-name
    networks:
      - mapleopentech-dev
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:${SERVER_PORT:-8000}/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s
```

### 13.4 Task Runner (Taskfile.yml)

**Taskfile.yml:**

```yaml
version: "3"

env:
  COMPOSE_PROJECT_NAME: your-backend

vars:
  DOCKER_COMPOSE_CMD:
    sh: |
      if command -v docker-compose >/dev/null 2>&1; then
        echo "docker-compose"
      elif docker compose version >/dev/null 2>&1; then
        echo "docker compose"
      else
        echo "docker-compose"
      fi

tasks:
  # Development workflow
  dev:
    desc: Start app in development mode
    cmds:
      - "{{.DOCKER_COMPOSE_CMD}} -f docker-compose.dev.yml up --build"

  dev:down:
    desc: Stop development app
    cmds:
      - "{{.DOCKER_COMPOSE_CMD}} -f docker-compose.dev.yml down"

  dev:restart:
    desc: Quick restart
    cmds:
      - "{{.DOCKER_COMPOSE_CMD}} -f docker-compose.dev.yml restart"

  dev:logs:
    desc: View app logs
    cmds:
      - "{{.DOCKER_COMPOSE_CMD}} -f docker-compose.dev.yml logs -f"

  dev:shell:
    desc: Open shell in running container
    cmds:
      - docker exec -it your-backend-dev sh

  # Database operations
  migrate:up:
    desc: Run all migrations up
    cmds:
      - ./app-backend migrate up

  migrate:down:
    desc: Run all migrations down
    cmds:
      - ./app-backend migrate down

  # Build and test
  build:
    desc: Build the Go binary
    cmds:
      - task: wire
      - go build -o app-backend

  wire:
    desc: Generate Wire dependency injection
    cmds:
      - cd app && wire

  test:
    desc: Run tests
    cmds:
      - go test ./... -v

  lint:
    desc: Run linters
    cmds:
      - go vet ./...

  format:
    desc: Format code
    cmds:
      - go fmt ./...

  tidy:
    desc: Tidy Go modules
    cmds:
      - go mod tidy

  # Production deployment
  deploy:
    desc: Build and push production container
    cmds:
      - docker build -f Dockerfile --rm -t registry.example.com/your-org/your_backend:prod --platform linux/amd64 .
      - docker push registry.example.com/your-org/your_backend:prod
```

---

## 14. CLI Commands (Cobra)

### 14.1 Root Command

**cmd/root.go:**

```go
package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/cmd/daemon"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/cmd/migrate"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/cmd/version"
)

var rootCmd = &cobra.Command{
	Use:   "your-backend",
	Short: "Your Backend Service",
	Long:  `Your Backend - Clean Architecture with Wire DI and Cassandra`,
}

// Execute runs the root command
func Execute() {
	rootCmd.AddCommand(daemon.DaemonCmd())
	rootCmd.AddCommand(migrate.MigrateCmd())
	rootCmd.AddCommand(version.VersionCmd())

	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
```

### 14.2 Daemon Command

**cmd/daemon/daemon.go:**

```go
package daemon

import (
	"log"

	"github.com/spf13/cobra"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/app"
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
)

// DaemonCmd returns the daemon command
func DaemonCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "daemon",
		Short: "Start the HTTP server",
		Run: func(cmd *cobra.Command, args []string) {
			// Load configuration
			cfg, err := config.Load()
			if err != nil {
				log.Fatalf("Failed to load config: %v", err)
			}

			// Initialize application with Wire
			application, err := app.InitializeApplication(cfg)
			if err != nil {
				log.Fatalf("Failed to initialize application: %v", err)
			}

			// Start application
			if err := application.Start(); err != nil {
				log.Fatalf("Application failed: %v", err)
			}
		},
	}
}
```

### 14.3 Main Entry Point

**main.go:**

```go
package main

import (
	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/cmd"
)

func main() {
	cmd.Execute()
}
```

---

## 15. Development Workflow

### Daily Development Flow

```bash
# 1. Start shared infrastructure (first time)
cd cloud/infrastructure/development
task dev:start

# 2. Start your backend
cd cloud/your-backend-name
task dev

# 3. Run migrations (first time)
task migrate:up

# 4. Make code changes...

# 5. Quick restart (after code changes)
task dev:restart

# 6. View logs
task dev:logs

# 7. Run tests
task test

# 8. Format and lint
task format
task lint

# 9. Stop backend
task dev:down
```

### Common Development Tasks

```bash
# Generate Wire dependencies
task wire

# Build binary locally
task build

# Run locally (without Docker)
./app-backend daemon

# Create new migration
./app-backend migrate create create_new_table

# Check migration version
./app-backend migrate version

# Reset database
task db:reset

# Open shell in container
task dev:shell

# Check application version
./app-backend version
```

---

## 16. Testing Strategy

### 16.1 Unit Testing

**Example: Use Case Test**

```go
// internal/usecase/user/create_user_entity_test.go
package user

import (
	"context"
	"testing"

	"github.com/google/uuid"
	"go.uber.org/zap"
)

func TestCreateUserEntityUseCase_Execute(t *testing.T) {
	logger := zap.NewNop()
	uc := ProvideCreateUserEntityUseCase(logger)

	input := &CreateUserEntityInput{
		TenantID:       uuid.New(),
		Email:          "test@example.com",
		Name:           "Test User",
		Role:           "user",
		HashedPassword: "hashed-password",
	}

	entity, err := uc.Execute(context.Background(), input)

	if err != nil {
		t.Fatalf("Execute failed: %v", err)
	}

	if entity.Email != input.Email {
		t.Errorf("Expected email %s, got %s", input.Email, entity.Email)
	}

	if entity.ID == uuid.Nil {
		t.Error("Expected non-nil ID")
	}
}
```

### 16.2 Integration Testing

Use test containers for integration tests:

```go
// internal/repository/user/integration_test.go
package user

import (
	"context"
	"testing"

	"github.com/gocql/gocql"
	"github.com/testcontainers/testcontainers-go"
)

func TestUserRepository_Integration(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test")
	}

	// Start Cassandra container
	ctx := context.Background()
	cassandraContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: testcontainers.ContainerRequest{
			Image:        "cassandra:4.1",
			ExposedPorts: []string{"9042/tcp"},
		},
		Started: true,
	})
	if err != nil {
		t.Fatalf("Failed to start container: %v", err)
	}
	defer cassandraContainer.Terminate(ctx)

	// Run tests...
}
```

---

## 17. Production Deployment

### 17.1 Build Production Container

```bash
# Build for Linux AMD64
task deploy
```

### 17.2 Environment Variables (Production)

```bash
# .env (production)
APP_ENVIRONMENT=production
APP_VERSION=1.0.0
APP_JWT_SECRET=<use-openssl-rand-base64-64>

SERVER_HOST=0.0.0.0
SERVER_PORT=8000

DATABASE_HOSTS=cassandra-prod-1:9042,cassandra-prod-2:9042,cassandra-prod-3:9042
DATABASE_KEYSPACE=your_keyspace_prod
DATABASE_CONSISTENCY=QUORUM
DATABASE_REPLICATION=3

CACHE_HOST=redis-prod
CACHE_PORT=6379
CACHE_PASSWORD=<strong-password>
CACHE_DB=0

SECURITY_IP_ENCRYPTION_KEY=<use-openssl-rand-hex-16>
SECURITY_CORS_ALLOWED_ORIGINS=https://yourdomain.com

LOGGER_LEVEL=info
LOGGER_FORMAT=json
```

### 17.3 Health Checks

**internal/interface/http/handler/healthcheck/healthcheck_handler.go:**

```go
package healthcheck

import (
	"encoding/json"
	"net/http"
	"time"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/your-backend-name/config"
)

// Handler handles health check requests
type Handler struct {
	config *config.Config
	logger *zap.Logger
}

// ProvideHealthCheckHandler provides the handler for Wire
func ProvideHealthCheckHandler(
	cfg *config.Config,
	logger *zap.Logger,
) *Handler {
	return &Handler{
		config: cfg,
		logger: logger.Named("healthcheck-handler"),
	}
}

// Handle responds to health check requests
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) {
	response := map[string]interface{}{
		"status":      "ok",
		"timestamp":   time.Now().UTC(),
		"environment": h.config.App.Environment,
		"version":     h.config.App.Version,
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(response)
}
```

---

## Summary

You now have a complete blueprint for building Golang backends with:

✅ **Clean Architecture** - Proper layer separation and dependency flow
✅ **Wire Dependency Injection** - Compile-time, type-safe DI
✅ **JWT Authentication** - Secure session management with two-tier caching
✅ **Cassandra Database** - Query-driven schema design with migrations
✅ **Reusable pkg/ Components** - Copy-paste infrastructure utilities
✅ **Security-First** - CWE-compliant middleware and validation
✅ **Docker Infrastructure** - Development and production containers
✅ **CLI Commands** - Cobra-based command structure

### Next Steps

1. **Copy this document** to your new project's `docs/` directory
2. **Run the copy-pkg.sh script** to copy reusable components
3. **Update import paths** throughout the codebase
4. **Customize** domain entities, use cases, and services for your specific needs
5. **Add business logic** while maintaining the architectural patterns

### Reference Implementation

Always refer back to `cloud/maplepress-backend` for:
- Complete working examples
- Advanced patterns (SAGA, rate limiting, etc.)
- Production-tested code
- Security best practices

---

**Questions or Issues?**
Review the maplepress-backend codebase or create a new issue in the repository.
