Container refactoring

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
James Pattinson
2026-04-26 09:43:02 +00:00
parent 0c0b5fbefe
commit 74a4e3ede8
9 changed files with 259 additions and 109 deletions
+6
View File
@@ -4,6 +4,12 @@ APP_VERSION="1.0.0"
DEBUG=True DEBUG=True
ENVIRONMENT=development ENVIRONMENT=development
# Gateway host port
APP_PORT=8050
APP_TLS_PORT=8443
DEV_CERT_CN=localhost
DEV_CERT_SANS=DNS:localhost,IP:127.0.0.1,IP:::1
# API Settings # API Settings
API_V1_PREFIX=/api/v1 API_V1_PREFIX=/api/v1
SECRET_KEY=your-secret-key-change-this-in-production SECRET_KEY=your-secret-key-change-this-in-production
+1
View File
@@ -49,6 +49,7 @@ Thumbs.db
# Docker # Docker
docker-compose.override.yml docker-compose.override.yml
docker/certs/
# Uploads # Uploads
uploads/ uploads/
+28 -32
View File
@@ -4,23 +4,28 @@
```bash ```bash
# Start all services # Start all services
docker-compose up -d docker compose up -d
# Watch the logs until services are ready # Watch the logs until services are ready
docker-compose logs -f docker compose logs -f
``` ```
Wait until you see "Application startup complete", then press Ctrl+C. Wait until you see "Application startup complete", then press Ctrl+C.
**Access the API**: **Access the API**:
- API: http://localhost:8000 - API: http://localhost:8050/api/v1
- Docs: http://localhost:8000/docs - Docs: http://localhost:8050/docs
Set `APP_PORT` in `.env` / `.env.example` to change `8050`.
For Square payment form testing, use HTTPS at `https://localhost:8443`.
Set `APP_TLS_PORT` in `.env` / `.env.example` to change `8443`.
TLS certs are auto-generated by the gateway container on first start.
## Testing the API ## Testing the API
### 1. Register a new user ### 1. Register a new user
```bash ```bash
curl -X POST "http://localhost:8000/api/v1/auth/register" \ curl -X POST "http://localhost:8050/api/v1/auth/register" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"email": "test@example.com", "email": "test@example.com",
@@ -32,7 +37,7 @@ curl -X POST "http://localhost:8000/api/v1/auth/register" \
### 2. Login ### 2. Login
```bash ```bash
curl -X POST "http://localhost:8000/api/v1/auth/login-json" \ curl -X POST "http://localhost:8050/api/v1/auth/login-json" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"email": "test@example.com", "email": "test@example.com",
@@ -44,45 +49,41 @@ Save the `access_token` from the response.
### 3. Get your profile ### 3. Get your profile
```bash ```bash
curl -X GET "http://localhost:8000/api/v1/users/me" \ curl -X GET "http://localhost:8050/api/v1/users/me" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Authorization: Bearer YOUR_TOKEN_HERE"
``` ```
### 4. List membership tiers ### 4. List membership tiers
```bash ```bash
curl -X GET "http://localhost:8000/api/v1/tiers/" curl -X GET "http://localhost:8050/api/v1/tiers/"
``` ```
## Docker Compose Commands ## Docker Compose Commands
```bash ```bash
# Start services # Start services
docker-compose up -d docker compose up -d
# Stop services # Stop services
docker-compose down docker compose down
# View logs (all services) # View logs (all services)
docker-compose logs -f docker compose logs -f
# View logs (specific service) # View logs (specific service)
docker-compose logs -f backend docker compose logs -f backend
docker-compose logs -f mysql
# Restart services # Restart services
docker-compose restart docker compose restart
# Rebuild after code changes # Rebuild after code changes
docker-compose up -d --build docker compose up -d --build
# Check status # Check status
docker-compose ps docker compose ps
# Access MySQL CLI (using environment variables) # Tail gateway logs
docker exec -it membership_mysql mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" "${DATABASE_NAME}" docker compose logs -f gateway
# Create database backup
docker exec membership_mysql mysqldump -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" "${DATABASE_NAME}" > backup_$(date +%Y%m%d_%H%M%S).sql
``` ```
## Default Admin Access ## Default Admin Access
@@ -111,33 +112,28 @@ docker exec membership_mysql mysqldump -u "${DATABASE_USER}" -p"${DATABASE_PASSW
### Check service status ### Check service status
```bash ```bash
docker-compose ps docker compose ps
``` ```
### View all logs ### View all logs
```bash ```bash
docker-compose logs -f docker compose logs -f
``` ```
### View backend logs only ### View backend logs only
```bash ```bash
docker-compose logs -f backend docker compose logs -f backend
```
### View MySQL logs only
```bash
docker-compose logs -f mysql
``` ```
### Restart everything ### Restart everything
```bash ```bash
docker-compose restart docker compose restart
``` ```
### Clean start (removes all data) ### Clean start (removes all data)
```bash ```bash
docker-compose down -v docker compose down -v
docker-compose up -d docker compose up -d
``` ```
## Next Steps ## Next Steps
+60 -47
View File
@@ -73,41 +73,42 @@ membership/
- SMTP2GO API key (for email notifications) - SMTP2GO API key (for email notifications)
- Database password (if desired) - Database password (if desired)
3. **Start the services in your preferred mode**: 3. **Start the services**:
```bash ```bash
# For development (with hot reloading) # Development mode (gateway + Vite hot reload)
docker-compose --profile dev up -d docker compose up -d
# For production (optimized static files) # Production static frontend mode
docker-compose --profile prod up -d docker compose --profile prod up -d frontend-prod backend
``` ```
4. **Wait for services to be ready** (about 30 seconds for MySQL initialization): 4. **Wait for services to be ready** (about 30 seconds for MySQL initialization):
```bash ```bash
docker-compose logs -f docker compose logs -f
``` ```
Press Ctrl+C when you see "Application startup complete" Press Ctrl+C when you see "Application startup complete"
5. **Access the application**: 5. **Access the application**:
- Frontend: http://localhost:3500 (development) or http://localhost:8080 (production) - Frontend (HTTP): http://localhost:8050
- API: http://localhost:8000 - Frontend (HTTPS for Square): https://localhost:8443
- API Documentation: http://localhost:8000/docs - API: http://localhost:8050/api/v1
- API Documentation: http://localhost:8050/docs
- TLS certs are generated automatically by the gateway container on first start
## Frontend Development vs Production ## Frontend Development vs Production
Choose your deployment mode by using the appropriate docker-compose file:
### Development Mode (Vite) ### Development Mode (Vite)
```bash ```bash
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d docker compose up -d
``` ```
- Frontend served by Vite dev server on port 3500 - Single entry point on port 8050
- Nginx gateway routes `/api/*` to backend and all other traffic to Vite
- Hot reloading and development features - Hot reloading and development features
- Access at: http://localhost:3500 - Access at: http://localhost:8050
### Production Mode (Nginx) ### Production Mode (Nginx)
```bash ```bash
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d docker compose --profile prod up -d frontend-prod backend
``` ```
- Frontend served by Nginx on port 8050 - Frontend served by Nginx on port 8050
- Optimized static files, production-ready - Optimized static files, production-ready
@@ -120,15 +121,30 @@ Set your preferred defaults in `.env`:
# Deployment mode (for reference only) # Deployment mode (for reference only)
MODE=dev MODE=dev
# Single host entrypoint port
APP_PORT=8050
# HTTPS entrypoint port for self-signed TLS in dev
APP_TLS_PORT=8443
DEV_CERT_CN=localhost
DEV_CERT_SANS=DNS:localhost,IP:127.0.0.1,IP:::1
# Frontend allowed hosts (comma-separated) # Frontend allowed hosts (comma-separated)
VITE_ALLOWED_HOSTS=sasaprod,localhost,members.sasalliance.org VITE_ALLOWED_HOSTS=sasaprod,localhost,members.sasalliance.org
``` ```
If you access via a LAN hostname or IP, add it to `VITE_ALLOWED_HOSTS`.
If you change `APP_PORT`, use that port instead of `8050` in URLs.
If you change `APP_TLS_PORT`, use that port for HTTPS URLs.
If you change hostnames, update `DEV_CERT_CN` and `DEV_CERT_SANS` accordingly.
### Stopping Services ### Stopping Services
```bash ```bash
# Stop all services # Stop all services
docker compose -f docker-compose.yml -f docker-compose.dev.yml down docker compose down
docker compose -f docker-compose.yml -f docker-compose.prod.yml down
# Stop production profile services
docker compose --profile prod down
``` ```
## Default Credentials ## Default Credentials
@@ -182,29 +198,29 @@ docker compose -f docker-compose.yml -f docker-compose.prod.yml down
```bash ```bash
# Start all services # Start all services
docker-compose up -d docker compose up -d
# View logs (all services) # View logs (all services)
docker-compose logs -f docker compose logs -f
# View logs (specific service) # View logs (specific service)
docker-compose logs -f backend docker compose logs -f backend
docker-compose logs -f mysql docker compose logs -f gateway
# Stop services # Stop services
docker-compose down docker compose down
# Stop and remove volumes (clean slate) # Stop and remove volumes (clean slate)
docker-compose down -v docker compose down -v
# Restart services # Restart services
docker-compose restart docker compose restart
# Rebuild after code changes # Rebuild after code changes
docker-compose up -d --build docker compose up -d --build
# Check service status # Check service status
docker-compose ps docker compose ps
``` ```
### Database Operations ### Database Operations
@@ -242,7 +258,7 @@ sudo docker compose exec backend alembic history
## API Testing ## API Testing
You can use the interactive API documentation at http://localhost:8000/docs to test endpoints: You can use the interactive API documentation at http://localhost:8050/docs to test endpoints:
1. Register a new user 1. Register a new user
2. Login to get access token 2. Login to get access token
@@ -253,7 +269,7 @@ Or use curl:
```bash ```bash
# Register # Register
curl -X POST "http://localhost:8000/api/v1/auth/register" \ curl -X POST "http://localhost:8050/api/v1/auth/register" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"email": "user@example.com", "email": "user@example.com",
@@ -263,7 +279,7 @@ curl -X POST "http://localhost:8000/api/v1/auth/register" \
}' }'
# Login # Login
curl -X POST "http://localhost:8000/api/v1/auth/login-json" \ curl -X POST "http://localhost:8050/api/v1/auth/login-json" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{ -d '{
"email": "user@example.com", "email": "user@example.com",
@@ -271,7 +287,7 @@ curl -X POST "http://localhost:8000/api/v1/auth/login-json" \
}' }'
# Get profile (replace TOKEN with actual token) # Get profile (replace TOKEN with actual token)
curl -X GET "http://localhost:8000/api/v1/users/me" \ curl -X GET "http://localhost:8050/api/v1/users/me" \
-H "Authorization: Bearer TOKEN" -H "Authorization: Bearer TOKEN"
``` ```
@@ -308,45 +324,42 @@ The system comes with three pre-configured tiers:
### Services not starting ### Services not starting
```bash ```bash
# Check status of all services # Check status of all services
docker-compose ps docker compose ps
# View all logs # View all logs
docker-compose logs docker compose logs
# View specific service logs # View specific service logs
docker-compose logs mysql docker compose logs gateway
docker-compose logs backend docker compose logs backend
# Restart all services # Restart all services
docker-compose restart docker compose restart
# Full restart with rebuild # Full restart with rebuild
docker-compose down docker compose down
docker-compose up -d --build docker compose up -d --build
``` ```
### Database connection issues ### Database connection issues
```bash ```bash
# Check if MySQL is healthy # Check backend connectivity and status
docker-compose ps docker compose ps
# View MySQL logs for errors # View backend logs for DB errors
docker-compose logs mysql docker compose logs backend
# Wait for MySQL to be fully ready (may take 30 seconds on first start)
docker-compose logs -f mysql
``` ```
### Clean slate restart ### Clean slate restart
```bash ```bash
# Stop everything and remove volumes # Stop everything and remove volumes
docker-compose down -v docker compose down -v
# Start fresh # Start fresh
docker-compose up -d docker compose up -d
# Wait for initialization # Wait for initialization
docker-compose logs -f docker compose logs -f
``` ```
## Next Steps ## Next Steps
+53 -28
View File
@@ -42,8 +42,8 @@ services:
- ACCESS_TOKEN_EXPIRE_MINUTES=${ACCESS_TOKEN_EXPIRE_MINUTES} - ACCESS_TOKEN_EXPIRE_MINUTES=${ACCESS_TOKEN_EXPIRE_MINUTES}
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
ports: expose:
- "6000:8000" # Only expose backend API to host - "8000"
volumes: volumes:
- ./backend/app:/app/app - ./backend/app:/app/app
- ./backend/alembic:/app/alembic - ./backend/alembic:/app/alembic
@@ -55,35 +55,60 @@ services:
# mysql: # mysql:
# condition: service_healthy # condition: service_healthy
# frontend: frontend:
# build: build:
# context: ./frontend context: ./frontend
# dockerfile: Dockerfile dockerfile: Dockerfile
# target: development target: development
# restart: unless-stopped restart: unless-stopped
# environment: env_file:
# - VITE_HOST_CHECK=false - .env
# - VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS} environment:
# ports: - VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS}
# - "8050:3000" # Expose frontend to host expose:
# volumes: - "3000"
# - ./frontend/src:/app/src volumes:
# - ./frontend/public:/app/public - ./frontend/src:/app/src
# - ./frontend/vite.config.ts:/app/vite.config.ts - ./frontend/public:/app/public
# depends_on: - ./frontend/vite.config.ts:/app/vite.config.ts
# - backend - ./frontend/index.html:/app/index.html
depends_on:
- backend
gateway:
build:
context: ./docker/gateway
dockerfile: Dockerfile
restart: unless-stopped
env_file:
- .env
environment:
- DEV_CERT_CN=${DEV_CERT_CN:-localhost}
- DEV_CERT_SANS=${DEV_CERT_SANS:-DNS:localhost,IP:127.0.0.1,IP:::1}
ports:
- "${APP_PORT:-8050}:80"
- "${APP_TLS_PORT:-8443}:443"
volumes:
- ./docker/gateway/nginx.dev.conf:/etc/nginx/conf.d/default.conf:ro
- gateway_certs:/etc/nginx/certs
depends_on:
- backend
- frontend
frontend-prod: frontend-prod:
build: build:
context: ./frontend context: ./frontend
dockerfile: Dockerfile dockerfile: Dockerfile
target: production target: production
restart: unless-stopped restart: unless-stopped
ports: ports:
- "8050:80" # Nginx default port - "${APP_PORT:-8050}:80" # Nginx default port
depends_on: depends_on:
- backend - backend
profiles:
- prod
volumes: volumes:
# mysql_data: # mysql_data:
uploads_data: uploads_data:
gateway_certs:
+8
View File
@@ -0,0 +1,8 @@
FROM nginx:alpine
RUN apk add --no-cache openssl
COPY docker-entrypoint-dev.sh /usr/local/bin/docker-entrypoint-dev.sh
RUN chmod +x /usr/local/bin/docker-entrypoint-dev.sh
CMD ["/usr/local/bin/docker-entrypoint-dev.sh"]
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env sh
set -eu
CERT_DIR="/etc/nginx/certs"
CERT_FILE="$CERT_DIR/dev.crt"
KEY_FILE="$CERT_DIR/dev.key"
CERT_CN="${DEV_CERT_CN:-localhost}"
CERT_SANS="${DEV_CERT_SANS:-DNS:localhost,IP:127.0.0.1,IP:::1}"
mkdir -p "$CERT_DIR"
if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then
echo "Generating self-signed TLS certificate for CN=$CERT_CN"
openssl req -x509 -nodes -newkey rsa:2048 \
-keyout "$KEY_FILE" \
-out "$CERT_FILE" \
-days 365 \
-subj "/C=GB/ST=Dev/L=Dev/O=SASA/OU=Membership/CN=$CERT_CN" \
-addext "subjectAltName=$CERT_SANS"
fi
exec nginx -g 'daemon off;'
+79
View File
@@ -0,0 +1,79 @@
server {
listen 80;
server_name _;
# Keep HTTP available in dev, but use HTTPS for Square Web Payments.
location /api/ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~ ^/(docs|redoc|openapi.json)$ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://frontend:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 443 ssl;
server_name _;
ssl_certificate /etc/nginx/certs/dev.crt;
ssl_certificate_key /etc/nginx/certs/dev.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_prefer_server_ciphers off;
# API routes to backend service
location /api/ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# FastAPI docs and schema for local development
location ~ ^/(docs|redoc|openapi.json)$ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# All other requests route to Vite dev server
location / {
proxy_pass http://frontend:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ export default defineConfig({
host: true, host: true,
port: 3000, port: 3000,
strictPort: true, strictPort: true,
allowedHosts: process.env.VITE_ALLOWED_HOSTS ? process.env.VITE_ALLOWED_HOSTS.split(',') : ['sasaprod', 'localhost'], allowedHosts: process.env.VITE_ALLOWED_HOSTS ? process.env.VITE_ALLOWED_HOSTS.split(',') : true,
watch: { watch: {
usePolling: true usePolling: true
}, },