mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Merge pull request #134 from aaronpo97/133-update-env-handling
refactor/update docker compose env configuration
This commit is contained in:
38
.env.example
Normal file
38
.env.example
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# ==============================================
|
||||||
|
# Biergarten App - Environment Variables Template
|
||||||
|
# ==============================================
|
||||||
|
#
|
||||||
|
# This file contains backend/Docker environment variables.
|
||||||
|
# Copy this to create environment-specific files:
|
||||||
|
# - .env.dev (development)
|
||||||
|
# - .env.test (testing)
|
||||||
|
# - .env.prod (production)
|
||||||
|
#
|
||||||
|
# For frontend variables, create a separate .env.local file
|
||||||
|
# in the Website/ directory. See README.md for complete docs.
|
||||||
|
#
|
||||||
|
# ==============================================
|
||||||
|
|
||||||
|
# ======================
|
||||||
|
# Database Configuration
|
||||||
|
# ======================
|
||||||
|
|
||||||
|
# SQL Server Connection Components (Recommended for Docker)
|
||||||
|
# These are used to build connection strings dynamically
|
||||||
|
DB_SERVER=sqlserver,1433
|
||||||
|
DB_NAME=Biergarten
|
||||||
|
DB_USER=sa
|
||||||
|
DB_PASSWORD=YourStrong!Passw0rd
|
||||||
|
|
||||||
|
# Alternative: Full Connection String (Local Development)
|
||||||
|
# If set, this overrides the component-based configuration above
|
||||||
|
# DB_CONNECTION_STRING=Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;
|
||||||
|
|
||||||
|
# ======================
|
||||||
|
# JWT Configuration
|
||||||
|
# ======================
|
||||||
|
|
||||||
|
# JWT Secret for signing tokens
|
||||||
|
# IMPORTANT: Generate a secure secret (minimum 32 characters)
|
||||||
|
# Command: openssl rand -base64 32
|
||||||
|
JWT_SECRET=128490218jfklsdajfdsa90f8sd0fid0safasr31jl2k1j4AFSDR
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -486,4 +486,7 @@ FodyWeavers.xsd
|
|||||||
|
|
||||||
database
|
database
|
||||||
|
|
||||||
.env.*
|
.env
|
||||||
|
.env.dev
|
||||||
|
.env.test
|
||||||
|
.env.prod
|
||||||
|
|||||||
367
README.md
367
README.md
@@ -12,6 +12,15 @@ A social platform for craft beer enthusiasts to discover breweries, share review
|
|||||||
- [Prerequisites](#prerequisites)
|
- [Prerequisites](#prerequisites)
|
||||||
- [Quick Start (Development Environment)](#quick-start-development-environment)
|
- [Quick Start (Development Environment)](#quick-start-development-environment)
|
||||||
- [Manual Setup (Without Docker)](#manual-setup-without-docker)
|
- [Manual Setup (Without Docker)](#manual-setup-without-docker)
|
||||||
|
- [Environment Variables](#environment-variables)
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Backend Variables (.NET API)](#backend-variables-net-api)
|
||||||
|
- [Frontend Variables (Next.js)](#frontend-variables-nextjs)
|
||||||
|
- [Docker Variables](#docker-variables)
|
||||||
|
- [External Services](#external-services)
|
||||||
|
- [Generating Secrets](#generating-secrets)
|
||||||
|
- [Environment File Structure](#environment-file-structure)
|
||||||
|
- [Variable Reference Table](#variable-reference-table)
|
||||||
- [Testing](#testing)
|
- [Testing](#testing)
|
||||||
- [Database Schema](#database-schema)
|
- [Database Schema](#database-schema)
|
||||||
- [Authentication & Security](#authentication--security)
|
- [Authentication & Security](#authentication--security)
|
||||||
@@ -154,17 +163,25 @@ Website/ # Next.js frontend application
|
|||||||
|
|
||||||
2. **Configure environment variables**
|
2. **Configure environment variables**
|
||||||
|
|
||||||
Create a `.env` file in the project root:
|
Copy the example file and customize:
|
||||||
```bash
|
```bash
|
||||||
# Database
|
cp .env.example .env.dev
|
||||||
SA_PASSWORD=YourStrong!Passw0rd
|
```
|
||||||
DB_CONNECTION_STRING=Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;
|
|
||||||
MASTER_DB_CONNECTION_STRING=Server=localhost,1433;Database=master;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;
|
Required variables in `.env.dev`:
|
||||||
|
```bash
|
||||||
|
# Database (component-based for Docker)
|
||||||
|
DB_SERVER=sqlserver,1433
|
||||||
|
DB_NAME=Biergarten
|
||||||
|
DB_USER=sa
|
||||||
|
DB_PASSWORD=YourStrong!Passw0rd
|
||||||
|
|
||||||
# JWT Authentication
|
# JWT Authentication
|
||||||
JWT_SECRET=your-secret-key-here-min-32-chars
|
JWT_SECRET=your-secret-key-minimum-32-characters-required
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For a complete list of all backend and frontend environment variables, see the [Environment Variables](#environment-variables) section.
|
||||||
|
|
||||||
3. **Start the development environment**
|
3. **Start the development environment**
|
||||||
```bash
|
```bash
|
||||||
docker compose -f docker-compose.dev.yaml up -d
|
docker compose -f docker-compose.dev.yaml up -d
|
||||||
@@ -181,27 +198,39 @@ Website/ # Next.js frontend application
|
|||||||
Navigate to http://localhost:8080/swagger to explore and test API endpoints.
|
Navigate to http://localhost:8080/swagger to explore and test API endpoints.
|
||||||
|
|
||||||
5. **Run the frontend** (optional)
|
5. **Run the frontend** (optional)
|
||||||
|
|
||||||
|
The frontend requires additional environment variables. See [Frontend Variables](#frontend-variables-nextjs) section.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd Website
|
cd Website
|
||||||
|
|
||||||
|
# Create .env.local with frontend variables
|
||||||
|
# (see Environment Variables section)
|
||||||
|
|
||||||
npm install
|
npm install
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
For Website environment variables, see `Website/README.old.md`.
|
For complete environment variable documentation, see the [Environment Variables](#environment-variables) section below.
|
||||||
|
|
||||||
### Manual Setup (Without Docker)
|
### Manual Setup (Without Docker)
|
||||||
|
|
||||||
|
#### Backend Setup
|
||||||
|
|
||||||
1. **Start SQL Server locally** or use a hosted instance
|
1. **Start SQL Server locally** or use a hosted instance
|
||||||
|
|
||||||
2. **Set environment variable**
|
2. **Set environment variables**
|
||||||
|
|
||||||
|
See [Backend Variables](#backend-variables-net-api) for details.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# macOS/Linux
|
# macOS/Linux
|
||||||
export DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
|
export DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
|
||||||
export JWT_SECRET="your-secret-key-here-min-32-chars"
|
export JWT_SECRET="your-secret-key-minimum-32-characters-required"
|
||||||
|
|
||||||
# Windows PowerShell
|
# Windows PowerShell
|
||||||
$env:DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
|
$env:DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
|
||||||
$env:JWT_SECRET="your-secret-key-here-min-32-chars"
|
$env:JWT_SECRET="your-secret-key-minimum-32-characters-required"
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Run migrations**
|
3. **Run migrations**
|
||||||
@@ -220,6 +249,324 @@ Website/ # Next.js frontend application
|
|||||||
dotnet run --project API/API.Core/API.Core.csproj
|
dotnet run --project API/API.Core/API.Core.csproj
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Frontend Setup
|
||||||
|
|
||||||
|
1. **Navigate to Website directory**
|
||||||
|
```bash
|
||||||
|
cd Website
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create environment file**
|
||||||
|
|
||||||
|
Create `.env.local` with required frontend variables. See [Frontend Variables](#frontend-variables-nextjs) for the complete list.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Example minimal setup
|
||||||
|
BASE_URL=http://localhost:3000
|
||||||
|
NODE_ENV=development
|
||||||
|
|
||||||
|
# Generate secrets
|
||||||
|
CONFIRMATION_TOKEN_SECRET=$(openssl rand -base64 127)
|
||||||
|
RESET_PASSWORD_TOKEN_SECRET=$(openssl rand -base64 127)
|
||||||
|
SESSION_SECRET=$(openssl rand -base64 127)
|
||||||
|
|
||||||
|
# Add external service credentials
|
||||||
|
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your-cloud-name
|
||||||
|
CLOUDINARY_KEY=your-api-key
|
||||||
|
CLOUDINARY_SECRET=your-api-secret
|
||||||
|
# ... (see Environment Variables section for complete list)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Install dependencies**
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Run Prisma migrations** (current frontend database)
|
||||||
|
```bash
|
||||||
|
npx prisma generate
|
||||||
|
npx prisma migrate dev
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Start the development server**
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
The frontend will be available at http://localhost:3000
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
The Biergarten App uses environment variables for configuration across both backend (.NET API) and frontend (Next.js) services. This section provides complete documentation for all required and optional variables.
|
||||||
|
|
||||||
|
**Configuration Patterns:**
|
||||||
|
- **Backend**: Direct environment variable access via `Environment.GetEnvironmentVariable()`
|
||||||
|
- **Frontend**: Centralized configuration module at [src/Website/src/config/env/index.ts](src/Website/src/config/env/index.ts) with Zod validation
|
||||||
|
- **Docker**: Environment-specific `.env` files (`.env.dev`, `.env.test`, `.env.prod`)
|
||||||
|
|
||||||
|
### Backend Variables (.NET API)
|
||||||
|
|
||||||
|
The .NET API requires environment variables for database connectivity and JWT authentication. These can be set directly in your shell or via `.env` files when using Docker.
|
||||||
|
|
||||||
|
#### Database Connection
|
||||||
|
|
||||||
|
**Option 1: Component-Based (Recommended for Docker)**
|
||||||
|
|
||||||
|
Use individual components to build the connection string:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_SERVER=sqlserver,1433 # SQL Server address and port
|
||||||
|
DB_NAME=Biergarten # Database name
|
||||||
|
DB_USER=sa # SQL Server username
|
||||||
|
DB_PASSWORD=YourStrong!Passw0rd # SQL Server password
|
||||||
|
DB_TRUST_SERVER_CERTIFICATE=True # Optional, defaults to True
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: Full Connection String (Local Development)**
|
||||||
|
|
||||||
|
Provide a complete SQL Server connection string:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DB_CONNECTION_STRING="Server=localhost,1433;Database=Biergarten;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
|
||||||
|
```
|
||||||
|
|
||||||
|
The connection factory checks for `DB_CONNECTION_STRING` first, then falls back to building from components. See [DefaultSqlConnectionFactory.cs](src/Core/Repository/Repository.Core/Sql/DefaultSqlConnectionFactory.cs).
|
||||||
|
|
||||||
|
#### JWT Authentication
|
||||||
|
|
||||||
|
```bash
|
||||||
|
JWT_SECRET=your-secret-key-minimum-32-characters-required
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Required**: Yes
|
||||||
|
- **Minimum Length**: 32 characters
|
||||||
|
- **Used For**: Signing JWT tokens for user authentication
|
||||||
|
- **Location**: [JwtService.cs](src/Core/Service/Service.Core/Services/JwtService.cs)
|
||||||
|
|
||||||
|
**Additional JWT Configuration** (in `appsettings.json`):
|
||||||
|
- `Jwt:ExpirationMinutes` - Token lifetime (default: 60)
|
||||||
|
- `Jwt:Issuer` - Token issuer (default: "biergarten-api")
|
||||||
|
- `Jwt:Audience` - Token audience (default: "biergarten-users")
|
||||||
|
|
||||||
|
#### Migration Control
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CLEAR_DATABASE=true # Development/Testing only
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Required**: No
|
||||||
|
- **Effect**: If set to "true", drops and recreates the database during migrations
|
||||||
|
- **Usage**: Development and testing environments only
|
||||||
|
- **Warning**: Never use in production
|
||||||
|
|
||||||
|
### Frontend Variables (Next.js)
|
||||||
|
|
||||||
|
The Next.js frontend requires environment variables for external services, authentication, and database connectivity. Create a `.env` or `.env.local` file in the `Website/` directory.
|
||||||
|
|
||||||
|
All variables are validated at runtime using Zod schemas. See [src/Website/src/config/env/index.ts](src/Website/src/config/env/index.ts).
|
||||||
|
|
||||||
|
#### Base Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
BASE_URL=http://localhost:3000 # Application base URL
|
||||||
|
NODE_ENV=development # Environment: development, production, test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Authentication & Sessions
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Token signing secrets (generate with: openssl rand -base64 127)
|
||||||
|
CONFIRMATION_TOKEN_SECRET=<generated-secret> # Email confirmation tokens
|
||||||
|
RESET_PASSWORD_TOKEN_SECRET=<generated-secret> # Password reset tokens
|
||||||
|
SESSION_SECRET=<generated-secret> # Session cookie signing
|
||||||
|
|
||||||
|
# Session configuration
|
||||||
|
SESSION_TOKEN_NAME=biergarten # Cookie name
|
||||||
|
SESSION_MAX_AGE=604800 # Cookie max age in seconds (604800 = 1 week)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Database (Prisma/Postgres)
|
||||||
|
|
||||||
|
**Current State**: The frontend currently uses Neon Postgres with Prisma. This will migrate to the SQL Server backend once feature parity is achieved.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
POSTGRES_PRISMA_URL=postgresql://user:pass@host/db?pgbouncer=true # Pooled connection
|
||||||
|
POSTGRES_URL_NON_POOLING=postgresql://user:pass@host/db # Direct connection (migrations)
|
||||||
|
SHADOW_DATABASE_URL=postgresql://user:pass@host/shadow_db # Prisma shadow DB
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Admin Account
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ADMIN_PASSWORD=SecureAdminPassword123! # Initial admin account password for seeding
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Variables
|
||||||
|
|
||||||
|
When running services in Docker, additional environment variables control container behavior:
|
||||||
|
|
||||||
|
#### ASP.NET Core
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ASPNETCORE_ENVIRONMENT=Development # Development, Production
|
||||||
|
ASPNETCORE_URLS=http://0.0.0.0:8080 # Binding address
|
||||||
|
DOTNET_RUNNING_IN_CONTAINER=true # Container execution flag
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SQL Server (Docker Container)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SA_PASSWORD=YourStrong!Passw0rd # SQL Server SA password (maps to DB_PASSWORD)
|
||||||
|
ACCEPT_EULA=Y # Accept SQL Server EULA
|
||||||
|
MSSQL_PID=Express # SQL Server edition (Express, Developer, etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: `SA_PASSWORD` in the SQL Server container maps to `DB_PASSWORD` for the API application.
|
||||||
|
|
||||||
|
### External Services
|
||||||
|
|
||||||
|
The frontend integrates with several third-party services. Sign up for accounts and retrieve API credentials:
|
||||||
|
|
||||||
|
#### Cloudinary (Image Hosting)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your-cloud-name # Public, client-accessible
|
||||||
|
CLOUDINARY_KEY=your-api-key # Server-side API key
|
||||||
|
CLOUDINARY_SECRET=your-api-secret # Server-side secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**Setup**:
|
||||||
|
1. Sign up at [cloudinary.com](https://cloudinary.com)
|
||||||
|
2. Navigate to Dashboard
|
||||||
|
3. Copy Cloud Name, API Key, and API Secret
|
||||||
|
|
||||||
|
**Note**: The `NEXT_PUBLIC_` prefix makes the cloud name accessible in client-side code.
|
||||||
|
|
||||||
|
#### Mapbox (Maps & Geocoding)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
MAPBOX_ACCESS_TOKEN=pk.your-public-token
|
||||||
|
```
|
||||||
|
|
||||||
|
**Setup**:
|
||||||
|
1. Create account at [mapbox.com](https://mapbox.com)
|
||||||
|
2. Navigate to Account → Tokens
|
||||||
|
3. Create a new token with public scopes
|
||||||
|
4. Copy the access token
|
||||||
|
|
||||||
|
#### SparkPost (Email Service)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SPARKPOST_API_KEY=your-api-key
|
||||||
|
SPARKPOST_SENDER_ADDRESS=noreply@yourdomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**Setup**:
|
||||||
|
1. Sign up at [sparkpost.com](https://sparkpost.com)
|
||||||
|
2. Verify your sending domain or use sandbox
|
||||||
|
3. Create an API key with "Send via SMTP" permission
|
||||||
|
4. Configure sender address (must match verified domain)
|
||||||
|
|
||||||
|
### Generating Secrets
|
||||||
|
|
||||||
|
For authentication secrets (`JWT_SECRET`, `CONFIRMATION_TOKEN_SECRET`, etc.), generate cryptographically secure random values:
|
||||||
|
|
||||||
|
**macOS/Linux:**
|
||||||
|
```bash
|
||||||
|
openssl rand -base64 127
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows PowerShell:**
|
||||||
|
```powershell
|
||||||
|
[Convert]::ToBase64String((1..127 | ForEach-Object { Get-Random -Maximum 256 }))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Requirements**:
|
||||||
|
- `JWT_SECRET`: Minimum 32 characters
|
||||||
|
- Session/token secrets: Recommend 127+ characters for maximum security
|
||||||
|
|
||||||
|
### Environment File Structure
|
||||||
|
|
||||||
|
The project uses multiple environment files depending on the context:
|
||||||
|
|
||||||
|
#### Backend/Docker (Root Directory)
|
||||||
|
|
||||||
|
- **`.env.example`** - Template file (tracked in Git)
|
||||||
|
- **`.env.dev`** - Development environment (gitignored)
|
||||||
|
- **`.env.test`** - Testing environment (gitignored)
|
||||||
|
- **`.env.prod`** - Production environment (gitignored)
|
||||||
|
|
||||||
|
**Setup**:
|
||||||
|
```bash
|
||||||
|
# Copy template and customize
|
||||||
|
cp .env.example .env.dev
|
||||||
|
# Edit .env.dev with your values
|
||||||
|
```
|
||||||
|
|
||||||
|
Docker Compose files reference these:
|
||||||
|
- `docker-compose.dev.yaml` → `.env.dev`
|
||||||
|
- `docker-compose.test.yaml` → `.env.test`
|
||||||
|
- `docker-compose.prod.yaml` → `.env.prod`
|
||||||
|
|
||||||
|
#### Frontend (Website Directory)
|
||||||
|
|
||||||
|
- **`.env`** or **`.env.local`** - Local development (gitignored)
|
||||||
|
|
||||||
|
**Setup**:
|
||||||
|
```bash
|
||||||
|
cd Website
|
||||||
|
# Create .env file with frontend variables
|
||||||
|
touch .env.local
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable Reference Table
|
||||||
|
|
||||||
|
| Variable | Backend | Frontend | Docker | Required | Notes |
|
||||||
|
|----------|---------|----------|--------|----------|-------|
|
||||||
|
| **Database** |
|
||||||
|
| `DB_SERVER` | ✓ | | ✓ | Yes* | SQL Server address |
|
||||||
|
| `DB_NAME` | ✓ | | ✓ | Yes* | Database name |
|
||||||
|
| `DB_USER` | ✓ | | ✓ | Yes* | SQL username |
|
||||||
|
| `DB_PASSWORD` | ✓ | | ✓ | Yes* | SQL password |
|
||||||
|
| `DB_CONNECTION_STRING` | ✓ | | | Yes* | Alternative to components |
|
||||||
|
| `DB_TRUST_SERVER_CERTIFICATE` | ✓ | | ✓ | No | Defaults to True |
|
||||||
|
| `SA_PASSWORD` | | | ✓ | Yes | SQL Server container only |
|
||||||
|
| **Authentication (Backend)** |
|
||||||
|
| `JWT_SECRET` | ✓ | | ✓ | Yes | Min 32 chars |
|
||||||
|
| **Authentication (Frontend)** |
|
||||||
|
| `CONFIRMATION_TOKEN_SECRET` | | ✓ | | Yes | Email confirmation |
|
||||||
|
| `RESET_PASSWORD_TOKEN_SECRET` | | ✓ | | Yes | Password reset |
|
||||||
|
| `SESSION_SECRET` | | ✓ | | Yes | Session signing |
|
||||||
|
| `SESSION_TOKEN_NAME` | | ✓ | | No | Default: "biergarten" |
|
||||||
|
| `SESSION_MAX_AGE` | | ✓ | | No | Default: 604800 |
|
||||||
|
| **Base Configuration** |
|
||||||
|
| `BASE_URL` | | ✓ | | Yes | App base URL |
|
||||||
|
| `NODE_ENV` | | ✓ | | Yes | development/production |
|
||||||
|
| `ASPNETCORE_ENVIRONMENT` | ✓ | | ✓ | Yes | Development/Production |
|
||||||
|
| `ASPNETCORE_URLS` | ✓ | | ✓ | Yes | Binding address |
|
||||||
|
| **Database (Frontend - Current)** |
|
||||||
|
| `POSTGRES_PRISMA_URL` | | ✓ | | Yes | Pooled connection |
|
||||||
|
| `POSTGRES_URL_NON_POOLING` | | ✓ | | Yes | Direct connection |
|
||||||
|
| `SHADOW_DATABASE_URL` | | ✓ | | No | Prisma shadow DB |
|
||||||
|
| **External Services** |
|
||||||
|
| `NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME` | | ✓ | | Yes | Public, client-side |
|
||||||
|
| `CLOUDINARY_KEY` | | ✓ | | Yes | Server-side |
|
||||||
|
| `CLOUDINARY_SECRET` | | ✓ | | Yes | Server-side |
|
||||||
|
| `MAPBOX_ACCESS_TOKEN` | | ✓ | | Yes | Maps/geocoding |
|
||||||
|
| `SPARKPOST_API_KEY` | | ✓ | | Yes | Email service |
|
||||||
|
| `SPARKPOST_SENDER_ADDRESS` | | ✓ | | Yes | From address |
|
||||||
|
| **Other** |
|
||||||
|
| `ADMIN_PASSWORD` | | ✓ | | No | Seeding only |
|
||||||
|
| `CLEAR_DATABASE` | ✓ | | ✓ | No | Dev/test only |
|
||||||
|
| `ACCEPT_EULA` | | | ✓ | Yes | SQL Server EULA |
|
||||||
|
| `MSSQL_PID` | | | ✓ | No | SQL Server edition |
|
||||||
|
|
||||||
|
\* Either `DB_CONNECTION_STRING` OR the four component variables (`DB_SERVER`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`) are required.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
services:
|
services:
|
||||||
sqlserver:
|
sqlserver:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
container_name: dev-env-sqlserver
|
container_name: dev-env-sqlserver
|
||||||
environment:
|
environment:
|
||||||
ACCEPT_EULA: "Y"
|
ACCEPT_EULA: "Y"
|
||||||
SA_PASSWORD: "${SA_PASSWORD}"
|
SA_PASSWORD: "${DB_PASSWORD}"
|
||||||
MSSQL_PID: "Express"
|
MSSQL_PID: "Express"
|
||||||
ports:
|
ports:
|
||||||
- "1433:1433"
|
- "1433:1433"
|
||||||
volumes:
|
volumes:
|
||||||
- sqlserverdata-dev:/var/opt/mssql
|
- sqlserverdata-dev:/var/opt/mssql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
@@ -20,6 +21,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
database.migrations:
|
database.migrations:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: database.migrations
|
image: database.migrations
|
||||||
container_name: dev-env-database-migrations
|
container_name: dev-env-database-migrations
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -33,14 +35,17 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}"
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
CLEAR_DATABASE: "true"
|
CLEAR_DATABASE: "true"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
|
|
||||||
database.seed:
|
database.seed:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: database.seed
|
image: database.seed
|
||||||
container_name: dev-env-database-seed
|
container_name: dev-env-database-seed
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -54,11 +59,13 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
sqlserverdata-dev:
|
sqlserverdata-dev:
|
||||||
driver: local
|
driver: local
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
services:
|
services:
|
||||||
sqlserver:
|
sqlserver:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
container_name: dev-env-sqlserver
|
container_name: dev-env-sqlserver
|
||||||
environment:
|
environment:
|
||||||
ACCEPT_EULA: "Y"
|
ACCEPT_EULA: "Y"
|
||||||
SA_PASSWORD: "${SA_PASSWORD}"
|
SA_PASSWORD: "${DB_PASSWORD}"
|
||||||
MSSQL_PID: "Express"
|
MSSQL_PID: "Express"
|
||||||
ports:
|
ports:
|
||||||
- "1433:1433"
|
- "1433:1433"
|
||||||
volumes:
|
volumes:
|
||||||
- sqlserverdata-dev:/var/opt/mssql
|
- sqlserverdata-dev:/var/opt/mssql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
@@ -20,6 +21,7 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
database.migrations:
|
database.migrations:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: database.migrations
|
image: database.migrations
|
||||||
container_name: dev-env-database-migrations
|
container_name: dev-env-database-migrations
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -33,14 +35,17 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}"
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
CLEAR_DATABASE: "true"
|
CLEAR_DATABASE: "true"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
|
|
||||||
database.seed:
|
database.seed:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: database.seed
|
image: database.seed
|
||||||
container_name: dev-env-database-seed
|
container_name: dev-env-database-seed
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -54,12 +59,16 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- devnet
|
- devnet
|
||||||
|
|
||||||
api.core:
|
api.core:
|
||||||
|
env_file: ".env.dev"
|
||||||
image: api.core
|
image: api.core
|
||||||
container_name: dev-env-api-core
|
container_name: dev-env-api-core
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -78,7 +87,10 @@ services:
|
|||||||
ASPNETCORE_ENVIRONMENT: "Development"
|
ASPNETCORE_ENVIRONMENT: "Development"
|
||||||
ASPNETCORE_URLS: "http://0.0.0.0:8080"
|
ASPNETCORE_URLS: "http://0.0.0.0:8080"
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
JWT_SECRET: "${JWT_SECRET}"
|
JWT_SECRET: "${JWT_SECRET}"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
services:
|
services:
|
||||||
sqlserver:
|
sqlserver:
|
||||||
|
env_file: ".env.prod"
|
||||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
container_name: prod-env-sqlserver
|
container_name: prod-env-sqlserver
|
||||||
environment:
|
environment:
|
||||||
ACCEPT_EULA: "Y"
|
ACCEPT_EULA: "Y"
|
||||||
SA_PASSWORD: "${SA_PASSWORD}"
|
SA_PASSWORD: "${DB_PASSWORD}"
|
||||||
MSSQL_PID: "Express"
|
MSSQL_PID: "Express"
|
||||||
volumes:
|
volumes:
|
||||||
- sqlserverdata-prod:/var/opt/mssql
|
- sqlserverdata-prod:/var/opt/mssql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
@@ -19,6 +20,7 @@ services:
|
|||||||
- prodnet
|
- prodnet
|
||||||
|
|
||||||
database.migrations:
|
database.migrations:
|
||||||
|
env_file: ".env.prod"
|
||||||
image: database.migrations
|
image: database.migrations
|
||||||
container_name: prod-env-database-migrations
|
container_name: prod-env-database-migrations
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -32,13 +34,16 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}"
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- prodnet
|
- prodnet
|
||||||
|
|
||||||
api.core:
|
api.core:
|
||||||
|
env_file: ".env.prod"
|
||||||
image: api.core
|
image: api.core
|
||||||
container_name: prod-env-api-core
|
container_name: prod-env-api-core
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -57,8 +62,10 @@ services:
|
|||||||
ASPNETCORE_ENVIRONMENT: "Production"
|
ASPNETCORE_ENVIRONMENT: "Production"
|
||||||
ASPNETCORE_URLS: "http://0.0.0.0:8080"
|
ASPNETCORE_URLS: "http://0.0.0.0:8080"
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
MASTER_DB_CONNECTION_STRING: "${MASTER_DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
DB_CONNECTION_STRING: "${DB_CONNECTION_STRING}"
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
JWT_SECRET: "${JWT_SECRET}"
|
JWT_SECRET: "${JWT_SECRET}"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
services:
|
services:
|
||||||
sqlserver:
|
sqlserver:
|
||||||
|
env_file: ".env.test"
|
||||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
container_name: test-env-sqlserver
|
container_name: test-env-sqlserver
|
||||||
environment:
|
environment:
|
||||||
ACCEPT_EULA: "Y"
|
ACCEPT_EULA: "Y"
|
||||||
SA_PASSWORD: "${SA_PASSWORD}"
|
SA_PASSWORD: "${DB_PASSWORD}"
|
||||||
MSSQL_PID: "Express"
|
MSSQL_PID: "Express"
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
volumes:
|
volumes:
|
||||||
- sqlserverdata-test:/var/opt/mssql
|
- sqlserverdata-test:/var/opt/mssql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${SA_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P '${DB_PASSWORD}' -C -Q 'SELECT 1' || exit 1"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
@@ -20,6 +21,7 @@ services:
|
|||||||
- testnet
|
- testnet
|
||||||
|
|
||||||
database.migrations:
|
database.migrations:
|
||||||
|
env_file: ".env.test"
|
||||||
image: database.migrations
|
image: database.migrations
|
||||||
container_name: test-env-database-migrations
|
container_name: test-env-database-migrations
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -33,14 +35,17 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${TEST_DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
MASTER_DB_CONNECTION_STRING: "${TEST_MASTER_DB_CONNECTION_STRING}"
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
CLEAR_DATABASE: "true"
|
CLEAR_DATABASE: "true"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- testnet
|
- testnet
|
||||||
|
|
||||||
database.seed:
|
database.seed:
|
||||||
|
env_file: ".env.test"
|
||||||
image: database.seed
|
image: database.seed
|
||||||
container_name: test-env-database-seed
|
container_name: test-env-database-seed
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -54,12 +59,16 @@ services:
|
|||||||
APP_UID: 1000
|
APP_UID: 1000
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${TEST_DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
restart: "no"
|
restart: "no"
|
||||||
networks:
|
networks:
|
||||||
- testnet
|
- testnet
|
||||||
|
|
||||||
api.specs:
|
api.specs:
|
||||||
|
env_file: ".env.test"
|
||||||
image: api.specs
|
image: api.specs
|
||||||
container_name: test-env-api-specs
|
container_name: test-env-api-specs
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -72,7 +81,10 @@ services:
|
|||||||
BUILD_CONFIGURATION: Release
|
BUILD_CONFIGURATION: Release
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${TEST_DB_CONNECTION_STRING}"
|
DB_SERVER: "${DB_SERVER}"
|
||||||
|
DB_NAME: "${DB_NAME}"
|
||||||
|
DB_USER: "${DB_USER}"
|
||||||
|
DB_PASSWORD: "${DB_PASSWORD}"
|
||||||
JWT_SECRET: "${JWT_SECRET}"
|
JWT_SECRET: "${JWT_SECRET}"
|
||||||
volumes:
|
volumes:
|
||||||
- ./test-results:/app/test-results
|
- ./test-results:/app/test-results
|
||||||
@@ -81,6 +93,7 @@ services:
|
|||||||
- testnet
|
- testnet
|
||||||
|
|
||||||
repository.tests:
|
repository.tests:
|
||||||
|
env_file: ".env.test"
|
||||||
image: repository.tests
|
image: repository.tests
|
||||||
container_name: test-env-repository-tests
|
container_name: test-env-repository-tests
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -93,8 +106,6 @@ services:
|
|||||||
BUILD_CONFIGURATION: Release
|
BUILD_CONFIGURATION: Release
|
||||||
environment:
|
environment:
|
||||||
DOTNET_RUNNING_IN_CONTAINER: "true"
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
DB_CONNECTION_STRING: "${TEST_DB_CONNECTION_STRING}"
|
|
||||||
JWT_SECRET: "${JWT_SECRET}"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./test-results:/app/test-results
|
- ./test-results:/app/test-results
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ WORKDIR /src
|
|||||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||||
RUN mkdir -p /app/test-results
|
RUN mkdir -p /app/test-results
|
||||||
WORKDIR /src/API/API.Specs
|
WORKDIR /src/API/API.Specs
|
||||||
ENTRYPOINT ["dotnet", "test", "API.Specs.csproj", "-c", "Release", "--no-build", "--no-restore", "--logger", "trx;LogFileName=/app/test-results/test-results.trx"]
|
ENTRYPOINT ["dotnet", "test", "API.Specs.csproj", "-c", "Release", "--logger", "trx;LogFileName=/app/test-results/test-results.trx"]
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ namespace API.Specs
|
|||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
builder.UseEnvironment("Testing");
|
builder.UseEnvironment("Testing");
|
||||||
|
|
||||||
builder.ConfigureAppConfiguration((context, configBuilder) =>
|
|
||||||
{
|
|
||||||
var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,39 @@ namespace Database.Migrations;
|
|||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
private static readonly string? connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");
|
private static string BuildConnectionString(string? databaseName = null)
|
||||||
private static readonly string? masterConnectionString = Environment.GetEnvironmentVariable("MASTER_DB_CONNECTION_STRING");
|
{
|
||||||
|
var server = Environment.GetEnvironmentVariable("DB_SERVER")
|
||||||
|
?? throw new InvalidOperationException("DB_SERVER environment variable is not set");
|
||||||
|
|
||||||
|
var dbName = databaseName
|
||||||
|
?? Environment.GetEnvironmentVariable("DB_NAME")
|
||||||
|
?? throw new InvalidOperationException("DB_NAME environment variable is not set");
|
||||||
|
|
||||||
|
var user = Environment.GetEnvironmentVariable("DB_USER")
|
||||||
|
?? throw new InvalidOperationException("DB_USER environment variable is not set");
|
||||||
|
|
||||||
|
var password = Environment.GetEnvironmentVariable("DB_PASSWORD")
|
||||||
|
?? throw new InvalidOperationException("DB_PASSWORD environment variable is not set");
|
||||||
|
|
||||||
|
var trustServerCertificate = Environment.GetEnvironmentVariable("DB_TRUST_SERVER_CERTIFICATE")
|
||||||
|
?? "True";
|
||||||
|
|
||||||
|
var builder = new SqlConnectionStringBuilder
|
||||||
|
{
|
||||||
|
DataSource = server,
|
||||||
|
InitialCatalog = dbName,
|
||||||
|
UserID = user,
|
||||||
|
Password = password,
|
||||||
|
TrustServerCertificate = bool.Parse(trustServerCertificate),
|
||||||
|
Encrypt = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return builder.ConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string connectionString = BuildConnectionString();
|
||||||
|
private static readonly string masterConnectionString = BuildConnectionString("master");
|
||||||
|
|
||||||
private static bool DeployMigrations()
|
private static bool DeployMigrations()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,9 +3,39 @@ using Microsoft.Data.SqlClient;
|
|||||||
using DbUp;
|
using DbUp;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
string BuildConnectionString()
|
||||||
|
{
|
||||||
|
var server = Environment.GetEnvironmentVariable("DB_SERVER")
|
||||||
|
?? throw new InvalidOperationException("DB_SERVER environment variable is not set");
|
||||||
|
|
||||||
|
var dbName = Environment.GetEnvironmentVariable("DB_NAME")
|
||||||
|
?? throw new InvalidOperationException("DB_NAME environment variable is not set");
|
||||||
|
|
||||||
|
var user = Environment.GetEnvironmentVariable("DB_USER")
|
||||||
|
?? throw new InvalidOperationException("DB_USER environment variable is not set");
|
||||||
|
|
||||||
|
var password = Environment.GetEnvironmentVariable("DB_PASSWORD")
|
||||||
|
?? throw new InvalidOperationException("DB_PASSWORD environment variable is not set");
|
||||||
|
|
||||||
|
var trustServerCertificate = Environment.GetEnvironmentVariable("DB_TRUST_SERVER_CERTIFICATE")
|
||||||
|
?? "True";
|
||||||
|
|
||||||
|
var builder = new SqlConnectionStringBuilder
|
||||||
|
{
|
||||||
|
DataSource = server,
|
||||||
|
InitialCatalog = dbName,
|
||||||
|
UserID = user,
|
||||||
|
Password = password,
|
||||||
|
TrustServerCertificate = bool.Parse(trustServerCertificate),
|
||||||
|
Encrypt = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return builder.ConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");
|
var connectionString = BuildConnectionString();
|
||||||
|
|
||||||
Console.WriteLine("Attempting to connect to database...");
|
Console.WriteLine("Attempting to connect to database...");
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,36 @@ namespace DataAccessLayer.Sql
|
|||||||
{
|
{
|
||||||
public class DefaultSqlConnectionFactory(IConfiguration configuration) : ISqlConnectionFactory
|
public class DefaultSqlConnectionFactory(IConfiguration configuration) : ISqlConnectionFactory
|
||||||
{
|
{
|
||||||
private readonly string _connectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING")
|
private readonly string _connectionString = GetConnectionString(configuration);
|
||||||
?? configuration.GetConnectionString("Default")
|
|
||||||
?? throw new InvalidOperationException(
|
private static string GetConnectionString(IConfiguration configuration)
|
||||||
"Database connection string not configured. Set DB_CONNECTION_STRING env var or ConnectionStrings:Default."
|
{
|
||||||
|
// Check for full connection string first
|
||||||
|
var fullConnectionString = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING");
|
||||||
|
if (!string.IsNullOrEmpty(fullConnectionString))
|
||||||
|
{
|
||||||
|
return fullConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to build from individual environment variables (preferred method for Docker)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return SqlConnectionStringHelper.BuildConnectionString();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
// Fall back to configuration-based connection string if env vars are not set
|
||||||
|
var connString = configuration.GetConnectionString("Default");
|
||||||
|
if (!string.IsNullOrEmpty(connString))
|
||||||
|
{
|
||||||
|
return connString;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Database connection string not configured. Set DB_CONNECTION_STRING or DB_SERVER, DB_NAME, DB_USER, DB_PASSWORD env vars or ConnectionStrings:Default."
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DbConnection CreateConnection()
|
public DbConnection CreateConnection()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace DataAccessLayer.Sql
|
||||||
|
{
|
||||||
|
public static class SqlConnectionStringHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a SQL Server connection string from environment variables.
|
||||||
|
/// Expects DB_SERVER, DB_NAME, DB_USER, DB_PASSWORD, and DB_TRUST_SERVER_CERTIFICATE.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="databaseName">Optional override for the database name. If null, uses DB_NAME env var.</param>
|
||||||
|
/// <returns>A properly formatted SQL Server connection string.</returns>
|
||||||
|
public static string BuildConnectionString(string? databaseName = null)
|
||||||
|
{
|
||||||
|
var server = Environment.GetEnvironmentVariable("DB_SERVER")
|
||||||
|
?? throw new InvalidOperationException("DB_SERVER environment variable is not set");
|
||||||
|
|
||||||
|
var dbName = databaseName
|
||||||
|
?? Environment.GetEnvironmentVariable("DB_NAME")
|
||||||
|
?? throw new InvalidOperationException("DB_NAME environment variable is not set");
|
||||||
|
|
||||||
|
var user = Environment.GetEnvironmentVariable("DB_USER")
|
||||||
|
?? throw new InvalidOperationException("DB_USER environment variable is not set");
|
||||||
|
|
||||||
|
var password = Environment.GetEnvironmentVariable("DB_PASSWORD")
|
||||||
|
?? throw new InvalidOperationException("DB_PASSWORD environment variable is not set");
|
||||||
|
|
||||||
|
var builder = new SqlConnectionStringBuilder
|
||||||
|
{
|
||||||
|
DataSource = server,
|
||||||
|
InitialCatalog = dbName,
|
||||||
|
UserID = user,
|
||||||
|
Password = password,
|
||||||
|
TrustServerCertificate = true,
|
||||||
|
Encrypt = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return builder.ConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a connection string to the master database using environment variables.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A connection string for the master database.</returns>
|
||||||
|
public static string BuildMasterConnectionString()
|
||||||
|
{
|
||||||
|
return BuildConnectionString("master");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,4 +11,4 @@ RUN dotnet build "./Repository.Tests.csproj" -c $BUILD_CONFIGURATION -o /app/bui
|
|||||||
FROM build AS final
|
FROM build AS final
|
||||||
RUN mkdir -p /app/test-results
|
RUN mkdir -p /app/test-results
|
||||||
WORKDIR /src/Repository/Repository.Tests
|
WORKDIR /src/Repository/Repository.Tests
|
||||||
ENTRYPOINT ["dotnet", "test", "./Repository.Tests.csproj", "-c", "Release", "--no-build", "--logger", "trx;LogFileName=/app/test-results/repository-tests.trx"]
|
ENTRYPOINT ["dotnet", "test", "./Repository.Tests.csproj", "-c", "Release", "--logger", "trx;LogFileName=/app/test-results/repository-tests.trx"]
|
||||||
|
|||||||
Reference in New Issue
Block a user