feat: Complete HMS Licht & Ton Homepage (T01-T08) #2
@@ -0,0 +1,32 @@
|
|||||||
|
# HMS Licht & Ton – Environment Configuration
|
||||||
|
# Copy this file to .env and fill in real values.
|
||||||
|
# NEVER commit the real .env file!
|
||||||
|
|
||||||
|
# --- Rentman API ---
|
||||||
|
RENTMAN_API_TOKEN=
|
||||||
|
|
||||||
|
# --- Authentication ---
|
||||||
|
JWT_SECRET=
|
||||||
|
|
||||||
|
# --- Database ---
|
||||||
|
DATABASE_URL=postgresql://hms:hms@postgres:5432/hms
|
||||||
|
|
||||||
|
# --- Redis ---
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
|
||||||
|
# --- SMTP (Email) ---
|
||||||
|
SMTP_HOST=
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USER=
|
||||||
|
SMTP_PASSWORD=
|
||||||
|
SMTP_FROM=info@hms-licht-ton.de
|
||||||
|
|
||||||
|
# --- CORS ---
|
||||||
|
CORS_ORIGINS=https://hms.media-on.de,http://localhost:3000
|
||||||
|
|
||||||
|
# --- Admin ---
|
||||||
|
ADMIN_USERNAME=admin
|
||||||
|
ADMIN_PASSWORD=
|
||||||
|
|
||||||
|
# --- Frontend ---
|
||||||
|
NUXT_PUBLIC_API_BASE=http://backend:8000
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
name: CI/CD Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
frontend-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: node:20
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup npm cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: frontend/node_modules
|
||||||
|
key: ${{ runner.os }}-npm-${{ hashFiles('frontend/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-npm-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
working-directory: frontend
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
working-directory: frontend
|
||||||
|
run: npm test
|
||||||
|
|
||||||
|
- name: Build production
|
||||||
|
working-directory: frontend
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
backend-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: python:3.12-slim
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y --no-install-recommends gcc libpq-dev && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
- name: Setup pip cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pip
|
||||||
|
key: ${{ runner.os }}-pip-${{ hashFiles('backend/requirements.txt') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pip-
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
working-directory: backend
|
||||||
|
run: pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
working-directory: backend
|
||||||
|
run: pytest -v
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [frontend-test, backend-test]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build frontend Docker image
|
||||||
|
run: docker build -t hms-frontend:ci ./frontend
|
||||||
|
|
||||||
|
- name: Build backend Docker image
|
||||||
|
run: docker build -t hms-backend:ci ./backend
|
||||||
|
|
||||||
|
- name: Validate docker-compose
|
||||||
|
run: docker compose config --quiet
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
# HMS Licht & Ton – Homepage & Verwaltungssystem
|
||||||
|
|
||||||
|
Die offizielle Website und Verwaltungsplattform für HMS Licht & Ton (Hammerschmidt u. Mössle GbR) aus Leipheim/Ellzee. Professionelle Veranstaltungstechnik – Vermietung, Verkauf, Personal und Transport von Tontechnik und Lichttechnik.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
| Komponente | Technologie |
|
||||||
|
|---------------|-----------------------------------|
|
||||||
|
| Frontend | Nuxt 3 (Vue 3, TypeScript, Tailwind CSS) |
|
||||||
|
| Backend | FastAPI (Python 3.12, async) |
|
||||||
|
| Database | PostgreSQL 16 |
|
||||||
|
| Cache | Redis 7 |
|
||||||
|
| Deployment | Docker Compose via Coolify |
|
||||||
|
| CI/CD | Forgejo Actions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Node.js** 20+
|
||||||
|
- **Python** 3.12+
|
||||||
|
- **Docker** & Docker Compose
|
||||||
|
- **Git**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### 1. Repository klonen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://forgejo.media-on.de/Leopoldadmin/hms-licht-ton.git
|
||||||
|
cd hms-licht-ton
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Environment konfigurieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# .env mit echten Werten ausfüllen (API-Token, Secrets, SMTP, etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Anwendung starten (Docker)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Anwendung ist danach erreichbar unter:
|
||||||
|
- **Frontend:** http://localhost:3000
|
||||||
|
- **Backend API:** http://localhost:8000
|
||||||
|
- **API Docs (Swagger):** http://localhost:8000/docs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Frontend (Nuxt 3)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm ci
|
||||||
|
npm run dev # Dev-Server auf http://localhost:3000
|
||||||
|
npm test # Unit Tests (Vitest)
|
||||||
|
npx playwright test # E2E Tests
|
||||||
|
npm run build # Production Build
|
||||||
|
npm run typecheck # TypeScript Type Check
|
||||||
|
npm run lint # ESLint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend (FastAPI)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||||
|
pytest -v # Tests ausführen
|
||||||
|
```
|
||||||
|
|
||||||
|
Weitere Build- und Test-Befehle siehe [AGENTS.md](AGENTS.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build (Docker)
|
||||||
|
|
||||||
|
### Alle Services bauen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Einzelne Services bauen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose build frontend
|
||||||
|
docker compose build backend
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment (Coolify)
|
||||||
|
|
||||||
|
Die Anwendung wird über Coolify auf `coolify-01` (46.225.91.159) deployt.
|
||||||
|
|
||||||
|
1. In Coolify ein neues Projekt "HMS Licht & Ton" anlegen.
|
||||||
|
2. Als Source das Forgejo-Repository `Leopoldadmin/hms-licht-ton` auswählen.
|
||||||
|
3. Als Deployment-Methode "Docker Compose" wählen und `docker-compose.yml` referenzieren.
|
||||||
|
4. Environment-Variablen in Coolify setzen (entsprechend `.env.example`).
|
||||||
|
5. Domain für Frontend konfigurieren (z.B. `hms.media-on.de` → Port 3000).
|
||||||
|
6. Backend-Port (8000) nur intern暴露en oder über Traefik mit eigener Subdomain.
|
||||||
|
7. Deploy auslösen. Coolify baut die Images und startet alle Services.
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
Alle Services haben Health Checks konfiguriert:
|
||||||
|
- **Frontend:** HTTP-Check auf Port 3000
|
||||||
|
- **Backend:** HTTP-Check auf `/health` Endpoint
|
||||||
|
- **PostgreSQL:** `pg_isready`
|
||||||
|
- **Redis:** `redis-cli ping`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD Pipeline (Forgejo Actions)
|
||||||
|
|
||||||
|
Die Pipeline (`.forgejo/workflows/ci.yml`) läuft bei jedem Push und PR auf `main`:
|
||||||
|
|
||||||
|
1. **frontend-test:** `npm ci` → `npm test` → `npm run build`
|
||||||
|
2. **backend-test:** `pip install` → `pytest -v`
|
||||||
|
3. **docker-build:** Baut Frontend- und Backend-Docker-Images, validiert `docker-compose.yml`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Projektstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
hms-licht-ton/
|
||||||
|
├── frontend/ # Nuxt 3 Frontend
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ ├── .dockerignore
|
||||||
|
│ ├── package.json
|
||||||
|
│ ├── nuxt.config.ts
|
||||||
|
│ ├── pages/
|
||||||
|
│ ├── components/
|
||||||
|
│ ├── composables/
|
||||||
|
│ ├── stores/
|
||||||
|
│ └── tests/
|
||||||
|
├── backend/ # FastAPI Backend
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ ├── .dockerignore
|
||||||
|
│ ├── requirements.txt
|
||||||
|
│ ├── app/
|
||||||
|
│ │ ├── main.py
|
||||||
|
│ │ ├── config.py
|
||||||
|
│ │ ├── database.py
|
||||||
|
│ │ ├── auth.py
|
||||||
|
│ │ ├── cache.py
|
||||||
|
│ │ ├── routers/
|
||||||
|
│ │ └── schemas/
|
||||||
|
│ └── tests/
|
||||||
|
├── docs/ # Projektdokumentation
|
||||||
|
├── .forgejo/
|
||||||
|
│ └── workflows/
|
||||||
|
│ └── ci.yml # CI/CD Pipeline
|
||||||
|
├── docker-compose.yml # 4 Services: frontend, backend, postgres, redis
|
||||||
|
├── .env.example # Environment-Vorlage
|
||||||
|
├── .gitignore
|
||||||
|
├── AGENTS.md # Build & Test Guide
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
© Hammerschmidt u. Mössle GbR. Alle Rechte vorbehalten.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.coverage
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.pytest_cache
|
||||||
|
htmlcov
|
||||||
|
tests
|
||||||
|
*.md
|
||||||
|
docs
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install system dependencies for asyncpg
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
gcc libpq-dev && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY app/ ./app/
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
services:
|
||||||
|
frontend:
|
||||||
|
build: ./frontend
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- NUXT_PUBLIC_API_BASE=${NUXT_PUBLIC_API_BASE:-http://backend:8000}
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 15s
|
||||||
|
networks:
|
||||||
|
- hms-network
|
||||||
|
|
||||||
|
backend:
|
||||||
|
build: ./backend
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=${DATABASE_URL:-postgresql://hms:hms@postgres:5432/hms}
|
||||||
|
- REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
|
||||||
|
- RENTMAN_API_TOKEN=${RENTMAN_API_TOKEN}
|
||||||
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
|
- SMTP_HOST=${SMTP_HOST}
|
||||||
|
- SMTP_PORT=${SMTP_PORT:-587}
|
||||||
|
- SMTP_USER=${SMTP_USER}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||||
|
- SMTP_FROM=${SMTP_FROM:-info@hms-licht-ton.de}
|
||||||
|
- CORS_ORIGINS=${CORS_ORIGINS:-https://hms.media-on.de,http://localhost:3000}
|
||||||
|
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
|
||||||
|
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
networks:
|
||||||
|
- hms-network
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=hms
|
||||||
|
- POSTGRES_PASSWORD=hms
|
||||||
|
- POSTGRES_DB=hms
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U hms -d hms"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 5s
|
||||||
|
networks:
|
||||||
|
- hms-network
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 5s
|
||||||
|
networks:
|
||||||
|
- hms-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
hms-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
redis_data:
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
node_modules
|
||||||
|
.nuxt
|
||||||
|
.output
|
||||||
|
dist
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
playwright-report
|
||||||
|
test-results
|
||||||
|
coverage
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# --- Stage 1: Build ---
|
||||||
|
FROM node:20 AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# --- Stage 2: Production ---
|
||||||
|
FROM node:20-slim AS production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/.output ./.output
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", ".output/server/index.mjs"]
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Test Report – T08: Docker, Deployment & CI/CD Configuration
|
||||||
|
|
||||||
|
**Datum:** 2026-07-10
|
||||||
|
**Task:** T08 – Docker, Deployment & CI/CD Configuration
|
||||||
|
**Status:** ALL TESTS PASSED
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test Results
|
||||||
|
|
||||||
|
| # | Test | Command | Result |
|
||||||
|
|---|------|---------|--------|
|
||||||
|
| 1 | docker compose config valid | `docker compose config --quiet` | ✅ PASS (warnings for unset env vars are expected without .env) |
|
||||||
|
| 2 | YAML syntax valid | `python3 -c 'import yaml; yaml.safe_load(open("docker-compose.yml"))'` | ✅ PASS |
|
||||||
|
| 3 | .env.example has RENTMAN_API_TOKEN | `grep 'RENTMAN_API_TOKEN' .env.example` | ✅ PASS |
|
||||||
|
| 4 | .env.example has JWT_SECRET | `grep 'JWT_SECRET' .env.example` | ✅ PASS |
|
||||||
|
| 5 | .env.example has DATABASE_URL | `grep 'DATABASE_URL' .env.example` | ✅ PASS |
|
||||||
|
| 6 | CI yml has test jobs | `grep -E 'test\|pytest\|npm' .forgejo/workflows/ci.yml` | ✅ PASS (frontend-test: npm ci, npm test, npm run build; backend-test: pytest) |
|
||||||
|
| 7 | README has Setup section | `grep 'Setup' README.md` | ✅ PASS |
|
||||||
|
| 8 | CI yml has docker-build job | `grep 'docker-build' .forgejo/workflows/ci.yml` | ✅ PASS |
|
||||||
|
| 9 | docker-compose has 4 services | `grep -E 'frontend:\|backend:\|postgres:\|redis:' docker-compose.yml` | ✅ PASS |
|
||||||
|
| 10 | Volumes defined | `grep -E 'postgres_data\|redis_data' docker-compose.yml` | ✅ PASS |
|
||||||
|
| 11 | Health checks (4 services) | `grep 'healthcheck:' docker-compose.yml \| wc -l` | ✅ PASS (4 health checks) |
|
||||||
|
| 12 | restart: unless-stopped (4 services) | `grep 'restart:' docker-compose.yml \| wc -l` | ✅ PASS (4 restart policies) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Created
|
||||||
|
|
||||||
|
| File | Lines | Purpose |
|
||||||
|
|------|-------|---------|
|
||||||
|
| `frontend/Dockerfile` | 21 | Multi-stage Node 20 build → slim production image |
|
||||||
|
| `frontend/.dockerignore` | 12 | Exclude node_modules, .nuxt, .output, etc. from Docker context |
|
||||||
|
| `backend/Dockerfile` | 17 | Python 3.12-slim, pip install, uvicorn CMD |
|
||||||
|
| `backend/.dockerignore` | 11 | Exclude __pycache__, .env, tests, etc. from Docker context |
|
||||||
|
| `docker-compose.yml` | 91 | 4 services (frontend, backend, postgres, redis) with health checks, volumes, network |
|
||||||
|
| `.env.example` | 32 | Environment variable template (no real secrets) |
|
||||||
|
| `.forgejo/workflows/ci.yml` | 80 | CI/CD pipeline: frontend-test, backend-test, docker-build jobs |
|
||||||
|
| `README.md` | 179 | Project overview, setup, development, deployment, CI/CD docs |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Smoke Test
|
||||||
|
|
||||||
|
- `docker compose config --quiet` → exits 0, no YAML errors
|
||||||
|
- YAML parser validates docker-compose.yml structure
|
||||||
|
- All required env vars present in .env.example
|
||||||
|
- CI pipeline has 3 jobs with correct test commands
|
||||||
|
- README contains setup, development, deployment sections
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `docker compose config` shows WARN for unset env vars (RENTMAN_API_TOKEN, JWT_SECRET, etc.) — expected since no `.env` file exists in project root during CI. In production, Coolify provides these.
|
||||||
|
- No hardcoded secrets in any file.
|
||||||
|
- `.env.example` contains only empty values or safe defaults.
|
||||||
Reference in New Issue
Block a user