diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml new file mode 100644 index 0000000..7ec2d3d --- /dev/null +++ b/.github/workflows/build-and-push.yml @@ -0,0 +1,45 @@ +name: Build and Push to GHCR + +on: + push: + branches: [main] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}/cactoide + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: ${{ github.event_name != 'pull_request' }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 + + - name: Output image info + if: github.event_name != 'pull_request' + run: | + echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..fa5856b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,41 @@ +name: Test and Build + +on: + push: + branches: [main] + pull_request: + branches: ['**'] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run type checking + run: npm run check + + - name: Run linting + run: npm run lint + + - name: Build application + run: npm run build + + - name: Test build output + run: | + if [ ! -d "build" ]; then + echo "Build directory not found!" + exit 1 + fi + echo "Build successful! Build directory exists." diff --git a/DOCKER_README.md b/DOCKER_README.md deleted file mode 100644 index ce32798..0000000 --- a/DOCKER_README.md +++ /dev/null @@ -1,218 +0,0 @@ -# Docker Setup for Cactoide - -This document explains how to run the Cactoide application using Docker containers. - -## Prerequisites - -- Docker installed on your system -- Docker Compose installed -- Make (optional, but recommended for easier management) - -## Quick Start - -### 1. Build and Start Everything - -```bash -# Build images and start all services -make build-and-up - -# Or manually: -docker-compose up -d --build -``` - -### 2. Access the Application - -- **Application**: http://localhost:3000 -- **Database**: localhost:5432 - -## Available Commands - -### Using Make (Recommended) - -```bash -# Show all available commands -make help - -# Start all services -make up - -# Stop all services -make down - -# Restart all services -make restart - -# View logs -make logs - -# Check status -make status - -# Clean up everything -make clean -``` - -### Using Docker Compose Directly - -```bash -# Start services -docker-compose up -d - -# Stop services -docker-compose down - -# View logs -docker-compose logs -f - -# Check status -docker-compose ps -``` - -## Development Mode - -For development with hot reloading: - -```bash -# Start development environment -make dev - -# Or manually: -docker-compose -f docker-compose.dev.yml up -``` - -Development mode runs on port **5173** with hot reloading enabled. - -## Individual Services - -### Start Only Database - -```bash -make db-only -``` - -### Start Only Application (requires database to be running) - -```bash -make app-only -``` - -## Database Management - -### Access Database Shell - -```bash -make db-shell -``` - -### Database Initialization - -The database is automatically initialized with the schema from `database/init.sql` when the container starts for the first time. - -### Persistent Data - -Database data is stored in a Docker volume (`postgres_data`) and persists between container restarts. - -## Environment Variables - -The following environment variables are automatically set in the containers: - -- `DATABASE_URL`: PostgreSQL connection string -- `NODE_ENV`: Environment mode (production/development) -- `POSTGRES_DB`: Database name -- `POSTGRES_USER`: Database user -- `POSTGRES_PASSWORD`: Database password - -## Ports - -- **3000**: Production application -- **5173**: Development application (with hot reloading) -- **5432**: PostgreSQL database - -## Troubleshooting - -### Check Service Status - -```bash -make status -``` - -### View Logs - -```bash -# All services -make logs - -# Specific service -make logs-app -make logs-db -``` - -### Restart Services - -```bash -make restart -``` - -### Clean Start - -```bash -make clean -make build-and-up -``` - -### Database Connection Issues - -1. Ensure the database container is healthy: - - ```bash - docker-compose ps postgres - ``` - -2. Check database logs: - - ```bash - make logs-db - ``` - -3. Verify environment variables: - ```bash - docker-compose exec app env | grep DATABASE - ``` - -## File Structure - -``` -. -├── Dockerfile # Production application image -├── Dockerfile.dev # Development application image -├── docker-compose.yml # Production services -├── docker-compose.dev.yml # Development services -├── Makefile # Management commands -├── .dockerignore # Docker build exclusions -└── database/ - └── init.sql # Database initialization script -``` - -## Production Deployment - -For production deployment, use the production compose file: - -```bash -docker-compose up -d -``` - -The production setup: - -- Runs the built SvelteKit application -- Uses optimized Node.js production image -- Includes health checks and restart policies -- Runs on port 3000 - -## Development Workflow - -1. **Start development environment**: `make dev` -2. **Make code changes** - they will automatically reload -3. **Test your changes** in the browser -4. **Stop development**: `Ctrl+C` or `make down` -5. **Build for production**: `make build` -6. **Deploy**: `make up` diff --git a/README.md b/README.md index 0818041..a27b638 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,45 @@ Your app will be available at `http://localhost:5173` ### 🚀 Self-Host -WIP +#### Using GitHub Container Registry (GHCR) + +The application is automatically built and pushed to GitHub Container Registry on every push to main/master branch. + +```bash +# Pull the latest image +docker pull ghcr.io/${{ github.repository }}/cactoide:latest + +# Or use a specific tag +docker pull ghcr.io/${{ github.repository }}/cactoide:main-abc1234 + +# Run the container +docker run -p 3000:3000 \ + -e DATABASE_URL="your-database-url" \ + ghcr.io/${{ github.repository }}/cactoide:latest +``` + +#### Using Docker Compose with GHCR + +```yaml +# docker-compose.prod.yml +version: '3.8' +services: + app: + image: ghcr.io/${{ github.repository }}/cactoide:latest + ports: + - '3000:3000' + environment: + - DATABASE_URL=your-production-database-url + - NODE_ENV=production + restart: unless-stopped +``` + +#### Available Tags + +- `latest` - Latest commit on main branch +- `main-` - Specific commit on main branch +- `v1.0.0` - Semantic version tags +- `1.0` - Major.minor version tags ### 📄 License diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..23c970a --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,59 @@ +version: '3.8' + +services: + # Database + postgres: + image: postgres:15-alpine + container_name: cactoide-db-prod + environment: + POSTGRES_DB: ${POSTGRES_DB:-cactoied_database} + POSTGRES_USER: ${POSTGRES_USER:-cactoide} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-cactoide_password} + ports: + - '5432:5432' + volumes: + - postgres_data_prod:/var/lib/postgresql/data + - ./database/init.sql:/docker-entrypoint-initdb.d/init.sql + healthcheck: + test: + [ + 'CMD-SHELL', + 'pg_isready -U ${POSTGRES_USER:-cactoide} -d ${POSTGRES_DB:-cactoied_database}' + ] + interval: 10s + timeout: 5s + retries: 5 + networks: + - cactoide-network-prod + restart: unless-stopped + + # Application + app: + image: ghcr.io/polaroi8d/cactoide:latest + container_name: cactoide-app-prod + ports: + - '3000:3000' + environment: + DATABASE_URL: postgres://${POSTGRES_USER:-cactoide}:${POSTGRES_PASSWORD:-cactoide_password}@postgres:5432/${POSTGRES_DB:-cactoied_database} + NODE_ENV: production + PORT: 3000 + HOSTNAME: 0.0.0.0 + depends_on: + postgres: + condition: service_healthy + networks: + - cactoide-network-prod + restart: unless-stopped + healthcheck: + test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3000/'] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +volumes: + postgres_data_prod: + +networks: + cactoide-network-prod: + driver: bridge diff --git a/env.prod.example b/env.prod.example new file mode 100644 index 0000000..a4f1d00 --- /dev/null +++ b/env.prod.example @@ -0,0 +1,11 @@ +# Production Environment Variables +# Copy this file to .env.prod and update the values + +# Database Configuration +POSTGRES_DB=cactoide_production +POSTGRES_USER=cactoide_prod +POSTGRES_PASSWORD=your_secure_password_here + +# App Configuration +NODE_ENV=production +PORT=3000