From 9219a586b1b7951cf83a2eac5de9b0596537796e Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Tue, 6 Jan 2026 05:22:54 +0100 Subject: [PATCH] feat: Add `.env.example` for configuration and update README with new features, setup, and API endpoints. --- .env.example | 83 +++++++++++++++++++ README.md | 220 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 225 insertions(+), 78 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c7e1668 --- /dev/null +++ b/.env.example @@ -0,0 +1,83 @@ +# ============================================================================ +# K-Template Configuration +# ============================================================================ +# Copy this file to .env and adjust values for your environment. +# All values shown are defaults or examples. + +# ============================================================================ +# Server Configuration +# ============================================================================ +HOST=127.0.0.1 +PORT=3000 + +# ============================================================================ +# Database Configuration +# ============================================================================ +# SQLite (default) +DATABASE_URL=sqlite:data.db?mode=rwc + +# PostgreSQL (alternative - requires postgres feature) +# DATABASE_URL=postgres://user:password@localhost:5432/mydb + +# Connection pool settings +DB_MAX_CONNECTIONS=5 +DB_MIN_CONNECTIONS=1 + +# ============================================================================ +# Authentication Mode +# ============================================================================ +# Options: session, jwt, both +# - session: Cookie-based sessions (requires auth-axum-login feature) +# - jwt: Bearer token authentication (requires auth-jwt feature) +# - both: Support both methods (try JWT first, fall back to session) +AUTH_MODE=jwt + +# ============================================================================ +# Session Configuration (for session/both modes) +# ============================================================================ +# Must be at least 64 characters in production +SESSION_SECRET=your-super-secret-key-must-be-at-least-64-characters-long-for-security + +# Set to true in production for HTTPS-only cookies +SECURE_COOKIE=false + +# ============================================================================ +# JWT Configuration (for jwt/both modes) +# ============================================================================ +# Must be at least 32 characters in production +JWT_SECRET=your-jwt-secret-key-at-least-32-chars + +# Optional: JWT issuer and audience for token validation +JWT_ISSUER=your-app-name +JWT_AUDIENCE=your-app-audience + +# Token expiry in hours (default: 24) +JWT_EXPIRY_HOURS=24 + +# ============================================================================ +# OIDC Configuration (optional - requires auth-oidc feature) +# ============================================================================ +# Your OIDC provider's issuer URL (e.g., Keycloak, Auth0, Zitadel) +OIDC_ISSUER=https://your-oidc-provider.com + +# Client credentials from your OIDC provider +OIDC_CLIENT_ID=your-client-id +OIDC_CLIENT_SECRET=your-client-secret + +# Callback URL (must match what's configured in your OIDC provider) +OIDC_REDIRECT_URL=http://localhost:3000/api/v1/auth/callback + +# Optional: Resource ID for audience verification +# OIDC_RESOURCE_ID=your-resource-id + +# ============================================================================ +# CORS Configuration +# ============================================================================ +# Comma-separated list of allowed origins +CORS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000 + +# ============================================================================ +# Production Mode +# ============================================================================ +# Set to true/production/1 to enable production checks (secret length, etc.) +PRODUCTION=false diff --git a/README.md b/README.md index 437036b..622828b 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,164 @@ # k-template -A production-ready, modular Rust template for K-Suite applications, following Hexagonal Architecture principles. +A production-ready, modular Rust API template for K-Suite applications, following Hexagonal Architecture principles. ## Features -- **Hexagonal Architecture**: Clear separation of concerns between Domain, Infrastructure, and API layers. -- **Modular & Swappable**: Vendor implementations (databases, message brokers) are behind feature flags and trait objects. -- **Feature-Gated Dependencies**: Compile only what you need. Unused dependencies are not included in the build. -- **Cargo Generate Ready**: Pre-configured for `cargo-generate` to easily scaffold new services. -- **Testable**: Domain logic is pure and easily testable; Infrastructure is tested with integration tests. +- **Hexagonal Architecture**: Clear separation between Domain, Infrastructure, and API layers +- **Multiple Auth Modes**: Session-based, JWT, or both - fully configurable +- **OIDC Integration**: Connect to any OpenID Connect provider (Keycloak, Auth0, Zitadel, etc.) +- **Database Flexibility**: SQLite (default) or PostgreSQL via feature flags +- **Type-Safe Configuration**: Newtypes with built-in validation for all security-sensitive values +- **Cargo Generate Ready**: Pre-configured for scaffolding new services + +## Quick Start + +### 1. Clone and Configure + +```bash +git clone https://github.com/GKaszewski/k-template.git my-api +cd my-api +cp .env.example .env +# Edit .env with your configuration +``` + +### 2. Run + +```bash +# Development (with hot reload via cargo-watch) +cargo watch -x run + +# Or simply +cargo run +``` + +The API will be available at `http://localhost:3000/api/v1/`. + +## Configuration + +All configuration is done via environment variables. See [.env.example](.env.example) for all options. + +### Authentication Modes + +Set `AUTH_MODE` to one of: + +| Mode | Description | Required Features | +|------|-------------|-------------------| +| `session` | Cookie-based sessions | `auth-axum-login` | +| `jwt` | Bearer token authentication | `auth-jwt` | +| `both` | Try JWT first, fall back to session | `auth-axum-login`, `auth-jwt` | + +### OIDC Integration + +To enable OIDC login (e.g., "Login with Google"): + +1. Enable the `auth-oidc` feature (enabled by default) +2. Configure your OIDC provider in `.env`: + ```env + OIDC_ISSUER=https://your-provider.com + OIDC_CLIENT_ID=your-client-id + OIDC_CLIENT_SECRET=your-secret + OIDC_REDIRECT_URL=http://localhost:3000/api/v1/auth/callback + ``` +3. Users can login via `GET /api/v1/auth/login/oidc` + +## Feature Flags + +Features are configured in `api/Cargo.toml`: + +```toml +[features] +default = ["sqlite", "auth-axum-login", "auth-oidc", "auth-jwt"] +``` + +| Feature | Description | +|---------|-------------| +| `sqlite` | SQLite database support (default) | +| `postgres` | PostgreSQL database support | +| `auth-axum-login` | Session-based authentication | +| `auth-oidc` | OpenID Connect integration | +| `auth-jwt` | JWT token authentication | +| `auth-full` | All auth features combined | + +### Common Configurations + +**JWT-only API (stateless)**: +```toml +default = ["sqlite", "auth-jwt"] +``` + +**OIDC + JWT (typical SPA backend)**: +```toml +default = ["sqlite", "auth-oidc", "auth-jwt"] +``` + +**Full-featured (all auth methods)**: +```toml +default = ["sqlite", "auth-full"] +``` + +## API Endpoints + +### Authentication + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `POST` | `/api/v1/auth/login` | Login with email/password | +| `POST` | `/api/v1/auth/register` | Register new user | +| `POST` | `/api/v1/auth/logout` | Logout (session mode) | +| `GET` | `/api/v1/auth/me` | Get current user | +| `POST` | `/api/v1/auth/token` | Get JWT for session user | +| `GET` | `/api/v1/auth/login/oidc` | Start OIDC login flow | +| `GET` | `/api/v1/auth/callback` | OIDC callback | ## Project Structure -The workspace consists of three main crates: - -- **`template-domain`**: The core business logic. - - Contains Entities, Value Objects, Repository Interfaces (Ports), and Services. - - **Dependencies**: Pure Rust only (no I/O, no heavy frameworks). - -- **`template-infra`**: The adapters layer. - - Implements the Repository interfaces defined in `template-domain`. - - Content is heavily feature-gated (e.g., `sqlite`, `postgres`, `broker-nats`). - -- **`template-api`**: The application entry point (Driving Adapter). - - Wires everything together using dependency injection. - - Handles HTTP/REST/gRPC interfaces. - -## Getting Started - -### Prerequisites - -- Rust (latest stable) -- `cargo-generate` (`cargo install cargo-generate`) - -### Creating a New Project - -Use `cargo-generate` to scaffold a new project from this template: - -```bash -cargo generate --git https://github.com/your-org/k-template.git +``` +k-template/ +├── domain/ # Core business logic (no I/O dependencies) +│ └── src/ +│ ├── entities.rs # User entity +│ ├── value_objects.rs # Email, Password, OIDC newtypes +│ ├── repositories.rs # Repository interfaces (ports) +│ └── services.rs # Domain services +│ +├── infra/ # Infrastructure adapters +│ └── src/ +│ ├── auth/ # Auth backends (OIDC, JWT) +│ └── user_repository.rs +│ +├── api/ # HTTP API layer +│ └── src/ +│ ├── routes/ # API endpoints +│ ├── config.rs # Configuration +│ └── state.rs # Application state +│ +├── .env.example # Configuration template +└── compose.yml # Docker Compose for local dev ``` -You will be prompted for: -1. **Project Name**: The name of your new service. -2. **Database**: Choose between `sqlite` (default) or `postgres`. - -The template will automatically clean up unused repository implementations based on your choice. +## Development ### Running Tests ```bash -# Run all tests -cargo test +# All tests +cargo test --all-features -# Run tests for a specific feature (e.g., postgres) -cargo test -p template-infra --no-default-features --features postgres +# Domain tests only +cargo test -p domain ``` -## Configuration & Feature Flags +### Database Migrations -This template uses Cargo features to control compilation of infrastructure adapters. +```bash +# SQLite +sqlx migrate run --source migrations_sqlite -| Feature | Description | Crate | -|---------|-------------|-------| -| `sqlite` | Enables SQLite repository implementations and dependencies | `template-infra`, `template-api` | -| `postgres` | Enables PostgreSQL repository implementations and dependencies | `template-infra`, `template-api` | -| `broker-nats`| Enables NATS messaging support | `template-infra` | - - -### Switching Databases - -To switch from the default SQLite to PostgreSQL in an existing project, update `Cargo.toml`: - -**`template-api/Cargo.toml`**: -```toml -[features] -default = ["postgres"] -# ... +# PostgreSQL +sqlx migrate run --source migrations_postgres ``` -**`template-infra/Cargo.toml`**: -```toml -[features] -default = ["postgres"] -# ... -``` +## License -## Architecture Guide - -### Adding a New Feature - -1. **Domain**: Define the Entity, Value Objects, and Repository Interface in `template-domain`. -2. **Infra**: Implement the Repository Interface in `template-infra`. - - **Important**: Wrap your implementation in a feature flag (e.g., `#[cfg(feature = "my-feature")]`). -3. **API**: Wire the new service in `template-api/src/main.rs` or a dedicated module. - -### Vendor Isolation - -All external dependencies (SQLx, NATS, etc.) should stay within `template-infra` or `template-api`. The `template-domain` crate should remain agnostic to specific technologies. +MIT