diff --git a/.gitignore b/.gitignore index a360305..c0bb8fa 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,9 @@ deployments/.env **/node_modules/ # OS files -**/.DS_Store \ No newline at end of file +**/.DS_Store + +**/.claude/** +**/.claude-logs/** +**/.claude-sessions/** +**/.kilo/** \ No newline at end of file diff --git a/deployments/README.md b/deployments/README.md new file mode 100644 index 0000000..5725cca --- /dev/null +++ b/deployments/README.md @@ -0,0 +1,358 @@ +# Hiling Production Deployment Guide + +This directory contains all necessary files for deploying the Hiling application stack to production using Docker Compose. + +## Architecture + +The application consists of 5 services: + +1. **PostgreSQL** - Main database +2. **Meilisearch** - Search engine +3. **Backend** - Go API server (hiling_go) +4. **OpenGraph** - Deno-based OpenGraph service +5. **Frontend** - Preact/React frontend served by Nginx + +## Prerequisites + +- Docker Engine 20.10+ +- Docker Compose v2.0+ +- At least 2GB RAM +- 10GB free disk space + +## Quick Start + +### 1. Configuration + +Copy the environment template and configure it: + +```bash +cd deployments +cp .env.example .env +``` + +Edit `.env` and set the following required variables: + +```bash +# REQUIRED: Set a strong password for PostgreSQL +DB_PASSWORD=your_secure_password_here + +# REQUIRED: Set a 32-character secret key for JWT tokens +TOKEN_SYMMETRIC_KEY=your_32_character_secret_key_here + +# REQUIRED: Set a master key for Meilisearch +MEILI_MASTER_KEY=your_secure_meilisearch_master_key +``` + +### 2. Build and Start Services + +```bash +docker-compose up -d --build +``` + +This will: +- Build all custom Docker images +- Start all services in the correct order +- Wait for health checks to pass +- Run in detached mode + +### 3. Verify Deployment + +Check service status: + +```bash +docker-compose ps +``` + +All services should show as "Up" or "healthy". + +View logs: + +```bash +# All services +docker-compose logs -f + +# Specific service +docker-compose logs -f backend +docker-compose logs -f frontend +``` + +### 4. Database Initialization + +If this is a fresh deployment, you may need to run database migrations: + +```bash +docker-compose exec backend ./main migrate +``` + +(Adjust the command based on your migration setup) + +## Service Endpoints + +Once deployed, services are accessible at: + +- **Frontend**: http://localhost:80 +- **Backend API**: http://localhost:8888 +- **OpenGraph Service**: http://localhost:1234 +- **Meilisearch**: http://localhost:7700 +- **PostgreSQL**: localhost:5432 + +## Configuration Reference + +### Environment Variables + +#### Database +- `DB_USERNAME` - PostgreSQL username (default: postgres) +- `DB_PASSWORD` - PostgreSQL password (required) +- `DB_NAME` - Database name (default: hiling) +- `DB_PORT` - External PostgreSQL port (default: 5432) + +#### Backend +- `BACKEND_PORT` - Backend API external port (default: 8888) +- `TOKEN_SYMMETRIC_KEY` - JWT signing key (required, 32 chars) +- `TOKEN_DURATION` - Token validity period (default: 720h) +- `COOKIE_DURATION` - Cookie duration in seconds (default: 86400) +- `REFRESH_TOKEN_DURATION` - Refresh token duration (default: 720h) + +#### Meilisearch +- `MEILI_MASTER_KEY` - Meilisearch master key (required) +- `MEILI_PORT` - External Meilisearch port (default: 7700) + +#### OpenGraph +- `OPENGRAPH_PORT` - OpenGraph service port (default: 1234) + +#### Frontend +- `FRONTEND_PORT` - Frontend external port (default: 80) + +## Production Hardening + +### Security Checklist + +- [ ] Change all default passwords +- [ ] Use strong, randomly generated keys +- [ ] Configure firewall rules to restrict access +- [ ] Enable HTTPS with reverse proxy (Nginx/Caddy) +- [ ] Set up database backups +- [ ] Configure log rotation +- [ ] Review and restrict exposed ports +- [ ] Enable Docker security scanning +- [ ] Set resource limits for containers + +### Recommended: Add Reverse Proxy + +For production, add a reverse proxy like Nginx or Caddy in front of the services: + +```yaml +# Add to docker-compose.yml + nginx-proxy: + image: nginx:alpine + ports: + - "443:443" + volumes: + - ./nginx-proxy.conf:/etc/nginx/nginx.conf + - ./ssl:/etc/nginx/ssl + depends_on: + - frontend + - backend +``` + +### Resource Limits + +Add resource limits to prevent containers from consuming too much: + +```yaml +services: + backend: + # ... existing config + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M +``` + +## Management Commands + +### Stop all services +```bash +docker-compose down +``` + +### Stop and remove volumes (WARNING: Deletes data) +```bash +docker-compose down -v +``` + +### Restart a specific service +```bash +docker-compose restart backend +``` + +### View resource usage +```bash +docker stats +``` + +### Rebuild a specific service +```bash +docker-compose up -d --build backend +``` + +### Access service shell +```bash +docker-compose exec backend sh +docker-compose exec postgres psql -U postgres -d hiling +``` + +## Backup and Restore + +### Database Backup + +```bash +# Backup +docker-compose exec -T postgres pg_dump -U postgres hiling > backup_$(date +%Y%m%d_%H%M%S).sql + +# Restore +docker-compose exec -T postgres psql -U postgres hiling < backup_20260321_120000.sql +``` + +### Meilisearch Backup + +Meilisearch data is stored in the `meilisearch_data` volume. + +```bash +# Create backup of volume +docker run --rm -v deployments_meilisearch_data:/data -v $(pwd):/backup alpine tar czf /backup/meilisearch_backup.tar.gz -C /data . + +# Restore +docker run --rm -v deployments_meilisearch_data:/data -v $(pwd):/backup alpine tar xzf /backup/meilisearch_backup.tar.gz -C /data +``` + +## Troubleshooting + +### Service won't start + +Check logs: +```bash +docker-compose logs +``` + +### Database connection issues + +Ensure PostgreSQL is healthy: +```bash +docker-compose ps postgres +docker-compose logs postgres +``` + +Test connection: +```bash +docker-compose exec postgres psql -U postgres -d hiling -c "SELECT 1" +``` + +### Port conflicts + +If you get port binding errors, check what's using the port: +```bash +lsof -i :8888 # or any conflicting port +``` + +Change ports in `.env` file. + +### Out of disk space + +Check Docker disk usage: +```bash +docker system df +``` + +Clean up: +```bash +docker system prune -a +``` + +### Reset everything + +```bash +docker-compose down -v +docker system prune -a +docker-compose up -d --build +``` + +## Monitoring + +### Health Checks + +All services have health checks configured. Check status: + +```bash +docker-compose ps +``` + +### Logs + +Centralized logging with Docker: + +```bash +# Follow all logs +docker-compose logs -f + +# Last 100 lines +docker-compose logs --tail=100 + +# Specific time range +docker-compose logs --since 30m +``` + +### Metrics + +For production monitoring, consider adding: +- Prometheus for metrics +- Grafana for visualization +- Loki for log aggregation + +## Scaling + +To run multiple instances of a service: + +```bash +docker-compose up -d --scale backend=3 +``` + +Note: You'll need a load balancer (like Nginx) to distribute traffic. + +## Updates and Maintenance + +### Updating Services + +1. Pull latest code +2. Rebuild images: `docker-compose build` +3. Restart services: `docker-compose up -d` + +### Rolling Updates + +For zero-downtime updates: + +1. Scale up new version +2. Wait for health check +3. Remove old version + +```bash +docker-compose up -d --scale backend=2 --no-recreate +# Wait for new instance to be healthy +docker-compose up -d --scale backend=1 +``` + +## Support + +For issues and questions: +- Check logs: `docker-compose logs` +- Review configuration in `.env` +- Ensure all required environment variables are set +- Verify Docker and Docker Compose versions + +## License + +[Your License Here] diff --git a/deployments/docker-compose.dev.yml b/deployments/docker-compose.dev.yml index 9dfc5fd..f26dad9 100644 --- a/deployments/docker-compose.dev.yml +++ b/deployments/docker-compose.dev.yml @@ -35,6 +35,16 @@ services: - hiling_network_dev restart: unless-stopped + # Redis + redis: + image: redis:7-alpine + container_name: hiling_redis_dev + ports: + - "${REDIS_PORT:-6379}:6379" + networks: + - hiling_network_dev + restart: unless-stopped + volumes: postgres_data_dev: driver: local diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml index ca208a4..51e36f2 100644 --- a/deployments/docker-compose.yml +++ b/deployments/docker-compose.yml @@ -44,6 +44,23 @@ services: timeout: 5s retries: 5 + # Redis + redis: + image: redis:7-alpine + container_name: hiling_redis + ports: + - "${REDIS_PORT:-6379}:6379" + volumes: + - redis_data:/data + networks: + - hiling_network + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + # Backend API (Go) backend: build: @@ -63,6 +80,7 @@ services: TOKEN_DURATION: ${TOKEN_DURATION:-1024h} COOKIE_DURATION: ${COOKIE_DURATION:-86400} REFRESH_TOKEN_DURATION: ${REFRESH_TOKEN_DURATION:-1024h} + REDIS_ADDRESS: redis:6379 ports: - "${BACKEND_PORT:-8888}:8888" depends_on: @@ -70,6 +88,8 @@ services: condition: service_healthy meilisearch: condition: service_healthy + redis: + condition: service_healthy networks: - hiling_network restart: unless-stopped @@ -128,6 +148,8 @@ volumes: driver: local meilisearch_data: driver: local + redis_data: + driver: local networks: hiling_network: diff --git a/hiling_go b/hiling_go index 67eb0a5..67ea7cb 160000 --- a/hiling_go +++ b/hiling_go @@ -1 +1 @@ -Subproject commit 67eb0a5a66d412fe5e11a84b54a9be3280f74d5a +Subproject commit 67ea7cb20fbb14416febd4bc869245c5bbe40e28 diff --git a/hilingriviw b/hilingriviw index 38e44d7..b5a316a 160000 --- a/hilingriviw +++ b/hilingriviw @@ -1 +1 @@ -Subproject commit 38e44d7056ab82118d726e289ae9c16a56ebb34e +Subproject commit b5a316af982de400aca6f3320e9c1823f4c20cfa diff --git a/run-dev-concurrent.sh b/run-dev-concurrent.sh new file mode 100755 index 0000000..312fded --- /dev/null +++ b/run-dev-concurrent.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +DOCKER=${DOCKER:-docker} + +# Advanced concurrent development server runner using concurrently (if available) +# Falls back to basic parallel execution if concurrently is not installed + +# Check if concurrently is installed +if command -v npx &> /dev/null && npx concurrently --version &> /dev/null 2>&1; then + echo "Using concurrently for better process management..." + + npx concurrently --kill-others \ + --names "Redis,Backend,Meilisearch,Frontend,OpenGraph" \ + --prefix "[{name}]" \ + --prefix-colors "red,green,yellow,blue,magenta" \ + "$DOCKER compose -f deployments/docker-compose.dev.yml up redis" \ + "sleep 2 && cd hiling_go && air" \ + "cd hiling_go && ./dev-meilisearch.sh" \ + "cd hilingriviw && pnpm dev" \ + "cd hiling-opengraph && deno task dev" +else + echo "concurrently not found. Install it for better process management:" + echo " npm install -g concurrently" + echo "" + echo "Falling back to run-dev.sh..." + exec ./run-dev.sh +fi \ No newline at end of file diff --git a/run-dev.sh b/run-dev.sh index 076b257..4a507f9 100755 --- a/run-dev.sh +++ b/run-dev.sh @@ -1,5 +1,9 @@ #!/bin/bash +DOCKER="podman" + +echo ${DOCKER} + RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -46,10 +50,19 @@ if ! command -v deno &> /dev/null; then exit 1 fi +if ! command -v "$DOCKER" &> /dev/null; then + echo -e "${RED}Error: '$DOCKER' is not installed${NC}" + exit 1 +fi + echo -e "${GREEN}All requirements satisfied${NC}\n" echo -e "${CYAN}Starting all development servers...${NC}\n" +run_service "Redis" "$RED" "." "$DOCKER" compose -f deployments/docker-compose.dev.yml up redis + +sleep 2 + run_service "Backend" "$GREEN" "hiling_go" air run_service "Meilisearch" "$YELLOW" "hiling_go" ./dev-meilisearch.sh