Getting Started

This guide will help you set up the development environment for the CoffeeBreak project.

Quick Start with Development Stack

The easiest way to get started is using our pre-configured development stack:

# Clone the development stack with all submodules
git clone --recurse-submodules https://github.com/PI-coffeeBreak/coffeebreak-devstack.git
cd coffeebreak-devstack

# Copy environment configuration
cp .env.example .env

# Start all services
docker compose up

After the services start:

  1. Access Keycloak admin console at http://localhost/auth
  2. Login with admin credentials (from your .env file)
  3. Navigate to: Realms → coffeebreak → Clients → fastapi-client → Credentials
  4. Copy the “Client Secret” value to your .env file: KEYCLOAK_CLIENT_SECRET=your-secret
  5. Restart services: docker compose restart

Access Applications

Updating to Latest Code

The development stack uses git submodules tracking the dev branch:

git submodule update --remote

Manual Setup (Advanced)

If you prefer to set up each component individually:

1. Clone the repositories

# Clone the core repository
git clone https://github.com/PI-coffeeBreak/core.git

# Clone the event-app repository
git clone https://github.com/PI-coffeeBreak/event-app.git

# Clone the frontend repository
git clone https://github.com/PI-coffeeBreak/frontend.git

# (Optional) Clone the webpush-sender service
# Only required if you want to use the webpush-notifications plugin
git clone https://github.com/PI-coffeeBreak/webpush-sender.git

Note: The webpush-sender service is only required if you want to use the webpush-notifications plugin. If you do not plan to use push notifications, you can skip this step.

2. Docker Compose Configuration

Below is a development example. For production, use the downloadable file above.

services:
  core:
    # image: ghcr.io/pi-coffeebreak/core:latest
    build:
      context: ./core
      dockerfile: Dockerfile
    environment:
      - KEYCLOAK_URL=${KEYCLOAK_URL}
      - KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET}
      - DATABASE_URI=${DATABASE_URI}
      - MONGODB_URI=${MONGODB_URI}
      - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER}
      - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS}
      - RABBITMQ_HOST=${RABBITMQ_HOST}
      - RABBITMQ_PORT=${RABBITMQ_PORT}
      - CORS_ORIGINS=${CORS_ORIGINS}
      - ANON_JWT_SECRET=${ANON_JWT_SECRET}
    ports:
      - "8080:8080"
    depends_on:
      - db
      - mongo
      - keycloak
      - mq
    volumes:
      - ./core:/app

  event-app:
    # image: ghcr.io/pi-coffeebreak/event-app:latest
    build:
      context: ./event-app
      dockerfile: Dockerfile
    environment:
      - API_BASE_URL=${API_BASE_URL}
      - WS_URL=${WS_URL}
      - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}
    ports:
      - "3000:80"
    depends_on:
      - core

  frontend-admin:
    # image: ghcr.io/pi-coffeebreak/frontend:latest
    build:
      context: ./frontend
      dockerfile: Dockerfile
    environment:
      - API_BASE_URL=${API_BASE_URL}
      - WS_URL=${WS_URL}
    ports:
      - "3001:80"
    depends_on:
      - core

  db:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    ports:
      - 5432:5432
    volumes:
      - postgres_data:/var/lib/postgresql/data

  keycloak-db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: ${KC_DB_USERNAME}
      POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
    volumes:
      - keycloak_data:/var/lib/postgresql/data

  mongo:
    image: mongodb/mongodb-community-server:latest
    environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
      - MONGO_INITDB_DATABASE=${MONGO_INITDB_DATABASE}
    ports:
      - 27017:27017
    volumes:
      - mongo_data:/data/db

  keycloak:
    image: quay.io/keycloak/keycloak:latest
    restart: unless-stopped
    environment:
      - KC_DB=postgres
      - KC_DB_URL=jdbc:postgresql://keycloak-db:5432/keycloak
      - KC_DB_USERNAME=${KC_DB_USERNAME}
      - KC_DB_PASSWORD=${KC_DB_PASSWORD}
      - KEYCLOAK_ADMIN=${KEYCLOAK_ADMIN}
      - KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
      - KC_PROXY_HEADERS=xforwarded
      - KC_HTTP_RELATIVE_PATH=/auth
      - KC_HOSTNAME=${KC_HOSTNAME}
      - PROXY_ADDRESS_FORWARDING=true
    ports:
      - 8081:8080
    depends_on:
      - keycloak-db
    command:
      - start-dev

  mq:
    image: rabbitmq:3-management-alpine
    environment:
      - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER}
      - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS}
    ports:
      - 5672:5672
      - 15672:15672
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - core
      - keycloak
      - event-app
      - frontend-admin

  # (Optional) Webpush service - only required for webpush-notifications plugin
  webpush-sender:
    build:
      context: ./webpush-sender
      dockerfile: Dockerfile
    environment:
      - RABBITMQ_URL=${RABBITMQ_URL}
      - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY}
      - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY}
    depends_on:
      - mq

volumes:
  postgres_data:
  mongo_data:
  keycloak_data:
  rabbitmq_data:

3. Environment Configuration

Create a .env file with the following variables:

Download .env.example
# PostgreSQL
POSTGRES_USER=username
POSTGRES_PASSWORD=password          # CHANGE ME
POSTGRES_HOST=db
POSTGRES_PORT=5432
POSTGRES_DB=coffeebreak

# PgAdmin
PGADMIN_DEFAULT_EMAIL=admin@example.com
PGADMIN_DEFAULT_PASSWORD=admin      # CHANGE ME

# PostgreSQL client
DATABASE_URI=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}

# MongoDB
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=admin    # CHANGE ME
MONGO_INITDB_DATABASE=coffeebreak

# MongoDB client
MONGODB_URI=mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongo/${MONGO_INITDB_DATABASE}?authSource=admin

# Keycloak
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin       # CHANGE ME
KC_HOSTNAME=http://localhost:8081   # Change for production
PROXY_ADDRESS_FORWARDING=true       # Set true if using a reverse proxy

# Keycloak db
KC_DB_USERNAME=keycloak
KC_DB_PASSWORD=keycloak             # CHANGE ME

# Keycloak fastapi client  
KEYCLOAK_URL=http://nginx/auth
# get on Keycloak Console > coffeebreak > Clients > fastapi-client > Credentials > Client Secret
KEYCLOAK_CLIENT_SECRET=             # CHANGE ME
ANON_JWT_SECRET=your-anonymous-jwt-secret-change-me-in-production

RABBITMQ_DEFAULT_USER=username
RABBITMQ_DEFAULT_PASS=password      # CHANGE ME
RABBITMQ_HOST=mq
RABBITMQ_PORT=5672
RABBITMQ_URL=amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@mq:5672

# Web Push VAPID Keys (generate with: npx web-push generate-vapid-keys)
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=

# Frontend
API_BASE_URL=http://localhost/api/v1
WS_URL=ws://localhost/ws

# CORS
CORS_ORIGINS=http://localhost,http://localhost:3001

4. Generate VAPID Keys

Generate VAPID keys for push notifications:

npx web-push generate-vapid-keys

Copy the generated keys to your .env file:

  • VAPID_PUBLIC_KEY
  • VAPID_PRIVATE_KEY

5. Get Keycloak Client Secret

  1. Start your Docker containers: docker compose up -d
  2. Go to Keycloak Admin Console: http://localhost:8081/auth/admin
  3. Login with admin credentials:
    • Username: admin (or value from KEYCLOAK_ADMIN)
    • Password: value from KEYCLOAK_ADMIN_PASSWORD
  4. Navigate to: Realms > coffeebreak > Clients > fastapi-client > Credentials
  5. Copy the “Client Secret” value
  6. Add it to your .env file: KEYCLOAK_CLIENT_SECRET=your-secret-here
  7. Restart your containers: docker compose restart

6. Nginx Configuration (Production)

For production deployment with a reverse proxy:

Download nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream core_backend {
        server core:8080;
    }

    upstream keycloak_backend {
        server keycloak:8080;
    }

    upstream event_app {
        server event-app:80;
    }

    upstream frontend_admin {
        server frontend-admin:80;
    }

    server {
        listen 80;
        server_name localhost;  # Change to your domain in production

        # Event app (main site)
        location / {
            proxy_pass http://event_app;
            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;
        }

        # Admin frontend
        location /admin {
            proxy_pass http://frontend_admin;
            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;
        }

        # API
        location /api {
            proxy_pass http://core_backend;
            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;
        }

        # WebSocket
        location /ws {
            proxy_pass http://core_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            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;
        }

        # Keycloak
        location /auth {
            proxy_pass http://keycloak_backend;
            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;
        }
    }
}

Note: Remember to change server_name localhost; to your actual domain name in production.

Next Steps