@@ -4,6 +4,12 @@ APP_VERSION="1.0.0"
|
||||
DEBUG=True
|
||||
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_V1_PREFIX=/api/v1
|
||||
SECRET_KEY=your-secret-key-change-this-in-production
|
||||
|
||||
@@ -49,6 +49,7 @@ Thumbs.db
|
||||
|
||||
# Docker
|
||||
docker-compose.override.yml
|
||||
docker/certs/
|
||||
|
||||
# Uploads
|
||||
uploads/
|
||||
|
||||
+28
-32
@@ -4,23 +4,28 @@
|
||||
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
|
||||
# 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.
|
||||
|
||||
**Access the API**:
|
||||
- API: http://localhost:8000
|
||||
- Docs: http://localhost:8000/docs
|
||||
- API: http://localhost:8050/api/v1
|
||||
- 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
|
||||
|
||||
### 1. Register a new user
|
||||
```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" \
|
||||
-d '{
|
||||
"email": "test@example.com",
|
||||
@@ -32,7 +37,7 @@ curl -X POST "http://localhost:8000/api/v1/auth/register" \
|
||||
|
||||
### 2. Login
|
||||
```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" \
|
||||
-d '{
|
||||
"email": "test@example.com",
|
||||
@@ -44,45 +49,41 @@ Save the `access_token` from the response.
|
||||
|
||||
### 3. Get your profile
|
||||
```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"
|
||||
```
|
||||
|
||||
### 4. List membership tiers
|
||||
```bash
|
||||
curl -X GET "http://localhost:8000/api/v1/tiers/"
|
||||
curl -X GET "http://localhost:8050/api/v1/tiers/"
|
||||
```
|
||||
|
||||
## Docker Compose Commands
|
||||
|
||||
```bash
|
||||
# Start services
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
docker compose down
|
||||
|
||||
# View logs (all services)
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
|
||||
# View logs (specific service)
|
||||
docker-compose logs -f backend
|
||||
docker-compose logs -f mysql
|
||||
docker compose logs -f backend
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
docker compose restart
|
||||
|
||||
# Rebuild after code changes
|
||||
docker-compose up -d --build
|
||||
docker compose up -d --build
|
||||
|
||||
# Check status
|
||||
docker-compose ps
|
||||
docker compose ps
|
||||
|
||||
# Access MySQL CLI (using environment variables)
|
||||
docker exec -it membership_mysql mysql -u "${DATABASE_USER}" -p"${DATABASE_PASSWORD}" "${DATABASE_NAME}"
|
||||
|
||||
# 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
|
||||
# Tail gateway logs
|
||||
docker compose logs -f gateway
|
||||
```
|
||||
|
||||
## Default Admin Access
|
||||
@@ -111,33 +112,28 @@ docker exec membership_mysql mysqldump -u "${DATABASE_USER}" -p"${DATABASE_PASSW
|
||||
|
||||
### Check service status
|
||||
```bash
|
||||
docker-compose ps
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### View all logs
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
### View backend logs only
|
||||
```bash
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
### View MySQL logs only
|
||||
```bash
|
||||
docker-compose logs -f mysql
|
||||
docker compose logs -f backend
|
||||
```
|
||||
|
||||
### Restart everything
|
||||
```bash
|
||||
docker-compose restart
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
### Clean start (removes all data)
|
||||
```bash
|
||||
docker-compose down -v
|
||||
docker-compose up -d
|
||||
docker compose down -v
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
@@ -73,41 +73,42 @@ membership/
|
||||
- SMTP2GO API key (for email notifications)
|
||||
- Database password (if desired)
|
||||
|
||||
3. **Start the services in your preferred mode**:
|
||||
3. **Start the services**:
|
||||
```bash
|
||||
# For development (with hot reloading)
|
||||
docker-compose --profile dev up -d
|
||||
# Development mode (gateway + Vite hot reload)
|
||||
docker compose up -d
|
||||
|
||||
# For production (optimized static files)
|
||||
docker-compose --profile prod up -d
|
||||
# Production static frontend mode
|
||||
docker compose --profile prod up -d frontend-prod backend
|
||||
```
|
||||
|
||||
4. **Wait for services to be ready** (about 30 seconds for MySQL initialization):
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
```
|
||||
Press Ctrl+C when you see "Application startup complete"
|
||||
|
||||
5. **Access the application**:
|
||||
- Frontend: http://localhost:3500 (development) or http://localhost:8080 (production)
|
||||
- API: http://localhost:8000
|
||||
- API Documentation: http://localhost:8000/docs
|
||||
- Frontend (HTTP): http://localhost:8050
|
||||
- Frontend (HTTPS for Square): https://localhost:8443
|
||||
- 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
|
||||
|
||||
Choose your deployment mode by using the appropriate docker-compose file:
|
||||
|
||||
### Development Mode (Vite)
|
||||
```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
|
||||
- Access at: http://localhost:3500
|
||||
- Access at: http://localhost:8050
|
||||
|
||||
### Production Mode (Nginx)
|
||||
```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
|
||||
- Optimized static files, production-ready
|
||||
@@ -120,15 +121,30 @@ Set your preferred defaults in `.env`:
|
||||
# Deployment mode (for reference only)
|
||||
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)
|
||||
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
|
||||
```bash
|
||||
# Stop all services
|
||||
docker compose -f docker-compose.yml -f docker-compose.dev.yml down
|
||||
docker compose -f docker-compose.yml -f docker-compose.prod.yml down
|
||||
docker compose down
|
||||
|
||||
# Stop production profile services
|
||||
docker compose --profile prod down
|
||||
```
|
||||
|
||||
## Default Credentials
|
||||
@@ -182,29 +198,29 @@ docker compose -f docker-compose.yml -f docker-compose.prod.yml down
|
||||
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
|
||||
# View logs (all services)
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
|
||||
# View logs (specific service)
|
||||
docker-compose logs -f backend
|
||||
docker-compose logs -f mysql
|
||||
docker compose logs -f backend
|
||||
docker compose logs -f gateway
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
docker compose down
|
||||
|
||||
# Stop and remove volumes (clean slate)
|
||||
docker-compose down -v
|
||||
docker compose down -v
|
||||
|
||||
# Restart services
|
||||
docker-compose restart
|
||||
docker compose restart
|
||||
|
||||
# Rebuild after code changes
|
||||
docker-compose up -d --build
|
||||
docker compose up -d --build
|
||||
|
||||
# Check service status
|
||||
docker-compose ps
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
@@ -242,7 +258,7 @@ sudo docker compose exec backend alembic history
|
||||
|
||||
## 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
|
||||
2. Login to get access token
|
||||
@@ -253,7 +269,7 @@ Or use curl:
|
||||
|
||||
```bash
|
||||
# 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" \
|
||||
-d '{
|
||||
"email": "user@example.com",
|
||||
@@ -263,7 +279,7 @@ curl -X POST "http://localhost:8000/api/v1/auth/register" \
|
||||
}'
|
||||
|
||||
# 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" \
|
||||
-d '{
|
||||
"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)
|
||||
curl -X GET "http://localhost:8000/api/v1/users/me" \
|
||||
curl -X GET "http://localhost:8050/api/v1/users/me" \
|
||||
-H "Authorization: Bearer TOKEN"
|
||||
```
|
||||
|
||||
@@ -308,45 +324,42 @@ The system comes with three pre-configured tiers:
|
||||
### Services not starting
|
||||
```bash
|
||||
# Check status of all services
|
||||
docker-compose ps
|
||||
docker compose ps
|
||||
|
||||
# View all logs
|
||||
docker-compose logs
|
||||
docker compose logs
|
||||
|
||||
# View specific service logs
|
||||
docker-compose logs mysql
|
||||
docker-compose logs backend
|
||||
docker compose logs gateway
|
||||
docker compose logs backend
|
||||
|
||||
# Restart all services
|
||||
docker-compose restart
|
||||
docker compose restart
|
||||
|
||||
# Full restart with rebuild
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
docker compose down
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
### Database connection issues
|
||||
```bash
|
||||
# Check if MySQL is healthy
|
||||
docker-compose ps
|
||||
# Check backend connectivity and status
|
||||
docker compose ps
|
||||
|
||||
# View MySQL logs for errors
|
||||
docker-compose logs mysql
|
||||
|
||||
# Wait for MySQL to be fully ready (may take 30 seconds on first start)
|
||||
docker-compose logs -f mysql
|
||||
# View backend logs for DB errors
|
||||
docker compose logs backend
|
||||
```
|
||||
|
||||
### Clean slate restart
|
||||
```bash
|
||||
# Stop everything and remove volumes
|
||||
docker-compose down -v
|
||||
docker compose down -v
|
||||
|
||||
# Start fresh
|
||||
docker-compose up -d
|
||||
docker compose up -d
|
||||
|
||||
# Wait for initialization
|
||||
docker-compose logs -f
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
+45
-20
@@ -42,8 +42,8 @@ services:
|
||||
- ACCESS_TOKEN_EXPIRE_MINUTES=${ACCESS_TOKEN_EXPIRE_MINUTES}
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
ports:
|
||||
- "6000:8000" # Only expose backend API to host
|
||||
expose:
|
||||
- "8000"
|
||||
volumes:
|
||||
- ./backend/app:/app/app
|
||||
- ./backend/alembic:/app/alembic
|
||||
@@ -55,23 +55,45 @@ services:
|
||||
# mysql:
|
||||
# condition: service_healthy
|
||||
|
||||
# frontend:
|
||||
# build:
|
||||
# context: ./frontend
|
||||
# dockerfile: Dockerfile
|
||||
# target: development
|
||||
# restart: unless-stopped
|
||||
# environment:
|
||||
# - VITE_HOST_CHECK=false
|
||||
# - VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS}
|
||||
# ports:
|
||||
# - "8050:3000" # Expose frontend to host
|
||||
# volumes:
|
||||
# - ./frontend/src:/app/src
|
||||
# - ./frontend/public:/app/public
|
||||
# - ./frontend/vite.config.ts:/app/vite.config.ts
|
||||
# depends_on:
|
||||
# - backend
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
target: development
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- VITE_ALLOWED_HOSTS=${VITE_ALLOWED_HOSTS}
|
||||
expose:
|
||||
- "3000"
|
||||
volumes:
|
||||
- ./frontend/src:/app/src
|
||||
- ./frontend/public:/app/public
|
||||
- ./frontend/vite.config.ts:/app/vite.config.ts
|
||||
- ./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:
|
||||
build:
|
||||
@@ -80,10 +102,13 @@ services:
|
||||
target: production
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8050:80" # Nginx default port
|
||||
- "${APP_PORT:-8050}:80" # Nginx default port
|
||||
depends_on:
|
||||
- backend
|
||||
profiles:
|
||||
- prod
|
||||
|
||||
volumes:
|
||||
# mysql_data:
|
||||
uploads_data:
|
||||
gateway_certs:
|
||||
|
||||
@@ -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"]
|
||||
@@ -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;'
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ export default defineConfig({
|
||||
host: true,
|
||||
port: 3000,
|
||||
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: {
|
||||
usePolling: true
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user