Files
appointment-booking-software/docs/infrastructure.md
T

8.2 KiB

Infrastructure Setup

This document describes the complete setup for the appointment booking application infrastructure.

Architecture Overview

The application consists of three Docker containers:

  1. PostgreSQL Database - Data persistence
  2. SvelteKit Application - Web application (production only)
  3. Caddy Reverse Proxy - HTTPS termination and routing (production only)

Development Setup

Development runs only the PostgreSQL database with a public port for development tools.

Prerequisites

  • Docker and Docker Compose
  • Node.js 24+
  • Git

Setup Steps

  1. Clone the repository

    git clone <repository-url>
    cd appointment-booking-software
    
  2. Configure environment

    cp .env.example .env
    

    Edit .env and set secure values:

    POSTGRES_DB=appointment_booking
    POSTGRES_USER=postgres
    POSTGRES_PASSWORD=your_secure_development_password
    POSTGRES_PORT=5432
    
  3. Start development database

    npm run docker:dev:up
    
  4. Verify database connection

    # Check container status
    docker ps
    
    # Test connection
    psql -h localhost -U postgres -d appointment_booking
    
  5. Install SvelteKit dependencies (when SvelteKit code is added)

    npm install
    
  6. Start SvelteKit development server (when SvelteKit code is added)

    npm run dev
    

Development Commands

# Database management
npm run docker:dev:up        # Start PostgreSQL
npm run docker:dev:down      # Stop PostgreSQL
npm run docker:dev:logs      # View database logs
npm run docker:dev:clean     # Remove containers and volumes

# Application (when SvelteKit is implemented)
npm run dev                  # Start development server
npm run build               # Build for production

Production Setup

Production runs all three containers with security hardening and HTTPS.

Prerequisites

  • Docker and Docker Compose
  • Domain name with DNS pointing to server
  • Server with public IP

Setup Steps

  1. Configure production secrets

    Edit the secret files in the secrets/ directory:

    # Database configuration
    echo "appointment_booking" > secrets/postgres_db.txt
    echo "postgres" > secrets/postgres_user.txt
    echo "$(openssl rand -base64 32)" > secrets/postgres_password.txt
    
    # Set proper permissions
    chmod 600 secrets/*.txt
    
  2. Configure domain

    Edit Caddyfile and replace your-domain.com with your actual domain:

    yourdomain.com {
        # ... rest of configuration
    }
    
  3. Build and start production stack

    # Build application image
    npm run docker:prod:build
    
    # Start all services
    npm run docker:prod:up
    
  4. Verify deployment

    # Check all containers are running
    docker ps
    
    # Check application health
    npm run docker:health
    
    # View logs
    npm run docker:prod:logs
    

Production Commands

# Stack management
npm run docker:prod:build    # Build application image
npm run docker:prod:up       # Start all services
npm run docker:prod:down     # Stop all services
npm run docker:prod:logs     # View all logs
npm run docker:prod:clean    # Remove containers and volumes
npm run docker:health        # Check container status
npm run docker:tag-and-push  # Build, tag and push the app image to GHCR (Remember to change username accordingly first) 

SvelteKit Application Setup

When implementing the SvelteKit application, follow these steps:

Database Connection

Create src/lib/database.js:

import { readFileSync } from 'fs';
import pg from 'pg';

function getDatabaseConfig() {
    if (process.env.NODE_ENV === 'production') {
        // Read from Docker secrets
        const user = readFileSync('/run/secrets/postgres_user', 'utf8').trim();
        const password = readFileSync('/run/secrets/postgres_password', 'utf8').trim();
        const database = readFileSync('/run/secrets/postgres_db', 'utf8').trim();
        
        return {
            host: 'postgres',
            port: 5432,
            user,
            password,
            database
        };
    } else {
        // Development configuration
        return {
            host: 'localhost',
            port: process.env.POSTGRES_PORT || 5432,
            user: process.env.POSTGRES_USER || 'postgres',
            password: process.env.POSTGRES_PASSWORD,
            database: process.env.POSTGRES_DB || 'appointment_booking'
        };
    }
}

export const pool = new pg.Pool(getDatabaseConfig());

Health Check Endpoint

Create src/routes/health/+server.js:

import { json } from '@sveltejs/kit';
import { pool } from '$lib/database.js';

export async function GET() {
    try {
        await pool.query('SELECT 1');
        return json({ status: 'healthy', timestamp: new Date().toISOString() });
    } catch (error) {
        return json(
            { status: 'unhealthy', error: error.message },
            { status: 500 }
        );
    }
}

SvelteKit Configuration

Update vite.config.js:

import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
    plugins: [sveltekit()],
    server: {
        host: '0.0.0.0',
        port: 5173
    }
});

Security Features

Container Security

  • Rootless containers: All containers (sans caddy, which needs to access privileged ports) run as non-root users
  • Read-only filesystems: Containers have read-only root filesystems where possible
  • No new privileges: Containers cannot escalate privileges
  • Minimal capabilities: Only necessary Linux capabilities are granted

Network Security

  • Internal networks: Database and app communicate via internal Docker network
  • No exposed ports: Only Caddy exposes ports to the host
  • HTTPS only: Caddy handles automatic HTTPS with Let's Encrypt

Data Security

  • Docker secrets: Sensitive data stored as Docker secrets
  • Encrypted connections: Database connections use SSL/TLS
  • Security headers: Comprehensive security headers via Caddy

Monitoring and Logs

Log Locations

  • Caddy logs: Stored in /data/access.log inside Caddy container
  • Application logs: Available via docker logs
  • Database logs: Available via docker logs

Health Checks

  • Application: GET /health endpoint
  • Database: Built-in PostgreSQL health check
  • Caddy: HTTP response check

Monitoring Commands

# View real-time logs
npm run docker:prod:logs

# Check container health
docker ps
npm run docker:health

# Individual container logs
docker logs appointment-booking-app
docker logs appointment-booking-postgres
docker logs appointment-booking-caddy

Troubleshooting

Common Issues

  1. Container won't start

    # Check container logs
    docker logs <container-name>
    
    # Check resource usage
    docker stats
    
  2. Database connection issues

    # Test database connectivity
    docker exec -it appointment-booking-postgres psql -U postgres -d appointment_booking
    
    # Check database logs
    docker logs appointment-booking-postgres
    
  3. HTTPS certificate issues

    # Check Caddy logs
    docker logs appointment-booking-caddy
    
    # Verify domain DNS
    nslookup yourdomain.com
    
  4. Application not accessible

    # Check if all containers are running
    docker ps
    
    # Test internal connectivity
    docker exec -it appointment-booking-caddy wget -q --spider http://app:3000/health
    

Reset Commands

# Complete reset (destroys all data)
npm run docker:prod:clean
npm run docker:dev:clean

# Rebuild and restart
npm run docker:prod:build
npm run docker:prod:up

Backup and Restore

Database Backup

# Create backup
docker exec appointment-booking-postgres pg_dump -U postgres appointment_booking > backup.sql

# Restore backup
docker exec -i appointment-booking-postgres psql -U postgres appointment_booking < backup.sql

Volume Backup

# Backup PostgreSQL data volume
docker run --rm -v appointment-booking-software_postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres-backup.tar.gz /data