Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 56 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,80 @@ jobs:
fi
echo "SPDX-Header vollständig."

integrations-tests:
django-packages:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [integrations, auth, lti]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install --quiet ./packages/django/basicbar-integrations
- run: cd packages/django/basicbar-integrations && python runtests.py
cache: pip
cache-dependency-path: packages/django/basicbar-${{ matrix.package }}/pyproject.toml
- run: pip install --quiet ./packages/django/basicbar-${{ matrix.package }}
- run: cd packages/django/basicbar-${{ matrix.package }} && python runtests.py

auth-tests:
ui-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/setup-node@v4
with:
python-version: "3.12"
- run: pip install --quiet ./packages/django/basicbar-auth
- run: cd packages/django/basicbar-auth && python runtests.py
node-version: "22"
cache: npm
cache-dependency-path: packages/ui/package-lock.json
- run: cd packages/ui && npm ci --no-fund --no-audit
- run: cd packages/ui && npm run build
- run: cd packages/ui && npx tsc --noEmit

lti-tests:
# Renders the Copier template with defaults (LTI on, so every conditional
# branch is exercised) and runs the generated tool's lint, checks, test suite
# and frontend build — catches Jinja errors, stale package pins and broken
# settings before the next real tool does.
template-probe:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: probe
POSTGRES_USER: probe
POSTGRES_PASSWORD: probe
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U probe"
--health-interval 5s --health-timeout 5s --health-retries 10
env:
POSTGRES_DB: probe
POSTGRES_USER: probe
POSTGRES_PASSWORD: probe
POSTGRES_HOST: localhost
POSTGRES_PORT: "5432"
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install --quiet ./packages/django/basicbar-lti
- run: cd packages/django/basicbar-lti && python runtests.py

ui-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- run: cd packages/ui && npm ci --no-fund --no-audit
- run: cd packages/ui && npm run build
- run: cd packages/ui && npx tsc --noEmit
- name: Render template
run: >-
pipx run copier copy --trust --defaults --vcs-ref HEAD
--data project_slug=probe --data use_lti=true --data ci_host=github
. /tmp/probe
- name: Backend lint, checks, tests
run: |
cd /tmp/probe/backend
pip install --quiet -r requirements.txt ruff
ruff check .
python manage.py check
python manage.py makemigrations --check --dry-run
python manage.py test
- name: Frontend build
run: cd /tmp/probe/frontend && npm install --no-fund --no-audit && npm run build
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,32 @@ Uhren zwischen IdP und Tool ggf. `OIDC_BACKCHANNEL_MAX_AGE` erhöhen.
Zeile in `config/settings.py` übernehmen.
- CLAUDE.md: Der ui-Release entsteht als Draft und muss manuell veröffentlicht
werden, sonst ist der Tarball nicht abrufbar.
- **Template-Refresh (Framework-Review):** Paket-Pins aktuell (integrations
0.2.2, auth 0.1.1, lti 0.1.4, ui 0.6.0 — bisher 0.1.0/0.1.0/0.1.2/0.2.1,
d. h. ohne den `clean_media_url`-Sicherheitsfix); `api.ts` fällt im
Prod-Build nicht mehr auf `localhost` zurück (same-origin) und behandelt
204/FormData korrekt; die 90-Zeilen-`SettingsMenu`-Kopie ist durch
`PreferencesMenu` aus @basicbar/ui ersetzt (Katalog-Key „Preferences“);
Settings verweigern `DEBUG=0` mit dem Dev-`SECRET_KEY`.
- **Prod-Gerüst** (bislang nur in abstimmbar/ausleihbar): Root-`Dockerfile`
(Multi-Stage, SPA gebacken), `docker-compose.prod.yml` (Pflichtvariablen
per `:?`), `.env.prod.example`, Release-Workflow nach GHCR.
- **Neue Copier-Frage `ci_host`** (github/gitlab, Default github): rendert
GitHub-Actions-CI + Release-Workflow oder die GitLab-Pipeline.
- **`_skip_if_exists`**: `copier update` lässt Identitäts-/Inhaltsdateien
(tailwind.config.js, App.tsx, locales, README/CLAUDE.md, Keycloak-Realm,
Caddyfile, .env.prod.example) in Ruhe — erkennbars 11 Hue-Konflikte
entfallen damit. `_message_after_copy` nennt die ersten Schritte.
- Schlankere Images: kein `libpq-dev`/`gcc` mehr (Wheels), `.dockerignore`
für Dev- und Prod-Build-Kontext; `gunicorn` entfernt (ASGI/uvicorn);
ruff-Konfiguration (`backend/pyproject.toml`, Import-Sortierung) und
echte Basis-Tests in `common/tests.py`.
- Repo-CI: `template-probe`-Job rendert das Template (mit LTI) und fährt
Lint, `check`, `makemigrations --check`, Tests gegen PostgreSQL und den
Frontend-Build der generierten Anwendung; Paket-Jobs als Matrix mit Caches.
- Migration Bestandstools (optional, per `copier update --vcs-ref HEAD`):
Konflikte sind in Gerüst-Dateien (compose, Dockerfiles, settings, api.ts)
zu erwarten — Diff lesen; die Identitätsdateien bleiben unberührt.

### @basicbar/ui (→ wird `ui/v0.6.0`)

Expand Down
60 changes: 47 additions & 13 deletions copier.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
# Copier-Template der virtUOS "-bar"-Tools (Basicbar Phase 6).
# Neues Tool erzeugen:
# pipx run copier copy https://github.com/virtUOS/basicbar.git mein-tool
# Später Template-Updates einspielen: `pipx run copier update` im Projekt.
# Neues Tool erzeugen (--vcs-ref HEAD ist Pflicht, sonst gilt der neueste
# Paket-Tag als Template-Version):
# pipx run copier copy --vcs-ref HEAD https://github.com/virtUOS/basicbar.git mein-tool
# Später Template-Updates einspielen: `pipx run copier update --vcs-ref HEAD`.

_subdirectory: template/project
_min_copier_version: "9.0.0"

# Dateien, die nach der Generierung dem Tool gehören — Identität (Farb-Ramps),
# App-Shell, Übersetzungskataloge, Doku, Deployment-Spezifika. `copier update`
# lässt sie in Ruhe; Gerüst-Updates betreffen compose, Dockerfiles, CI,
# settings, api-Client.
_skip_if_exists:
- frontend/tailwind.config.js
- frontend/src/App.tsx
- frontend/src/locales/**
- README.md
- CLAUDE.md
- keycloak/realm-export.json
- Caddyfile
- .env.prod.example

_message_after_copy: |
{{ project_title }} ist generiert. Nächste Schritte:

cd {{ _copier_conf.dst_path }}
git init -b main && git add -A && git commit -m "Gerüst aus basicbar-Template"
docker compose up -d && docker compose exec backend python manage.py migrate
docker compose exec frontend npm install --package-lock-only # Lockfile committen (CI-Cache)

Login: http://localhost:{{ frontend_port }} mit demo/demo (Admin: admin-demo/demo).
Nach dem ersten Push: main schützen (Push "no one", Merge via PR/MR).

project_slug:
type: str
help: "Technischer Name (klein, ohne Sonderzeichen) — Container, DB, Realm, Client-IDs"
Expand All @@ -24,28 +50,28 @@ project_description:

frontend_port:
type: int
help: "Host-Port des Vite-Dev-Servers (ausleihbar 5173, abstimmbar 5174, modulierbar 5175, …)"
default: 5176
help: "Host-Port des Vite-Dev-Servers (ausleihbar 5173, abstimmbar 5174, modulierbar 5175, erkennbar 5176, …)"
default: 5177

backend_port:
type: int
help: "Host-Port des Django-Backends (ausleihbar 8001, abstimmbar 8002, modulierbar 8003, …)"
default: 8004
help: "Host-Port des Django-Backends (ausleihbar 8001, abstimmbar 8002, modulierbar 8003, erkennbar 8004, …)"
default: 8005

keycloak_port:
type: int
help: "Host-Port des Dev-Keycloak (ausleihbar 8080, abstimmbar 8081, modulierbar 8082, …)"
default: 8083
help: "Host-Port des Dev-Keycloak (ausleihbar 8080, abstimmbar 8081, modulierbar 8082, erkennbar 8083, …)"
default: 8084

postgres_port:
type: int
help: "Host-Port von PostgreSQL (ausleihbar 5432, abstimmbar 5433, modulierbar 5434, …)"
default: 5435
help: "Host-Port von PostgreSQL (ausleihbar 5432, abstimmbar 5433, modulierbar 5434, erkennbar 5435, …)"
default: 5436

brand_hue:
type: int
help: "OKLCH-Farbton des Marken-Akzents (ausleihbar Honig ≈ 91, abstimmbar Grün ≈ 150; Startwert, Feintuning in tailwind.config.js)"
default: 260
help: "OKLCH-Farbton des Marken-Akzents (ausleihbar Honig ≈ 91, abstimmbar Grün ≈ 150, erkennbar Violett ≈ 260; Startwert, Feintuning in tailwind.config.js)"
default: 320

neutral_hue:
type: int
Expand All @@ -56,3 +82,11 @@ use_lti:
type: bool
help: "LTI 1.3 vorbereiten (basicbar-lti: Plattform-Registrierung, Middleware — Launch-App folgt nach abstimmbar-Vorbild)?"
default: false

ci_host:
type: str
help: "Wo laufen CI und Release? github = GitHub Actions + Release-Image nach GHCR (ADR-0004), gitlab = Pipeline auf der Uni-GitLab"
choices:
- github
- gitlab
default: github
51 changes: 37 additions & 14 deletions template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,40 @@ cd mein-tool && git init -b main && git add -A && git commit -m "Gerüst aus bas
docker compose up -d && docker compose exec backend python manage.py migrate
```

Danach empfohlen: Frontend-Lockfile erzeugen und committen (der CI-Cache
hängt daran: `docker compose exec frontend npm install --package-lock-only`),
nach dem ersten Push den main-Branch schützen (Push „no one“, Merge via MR)
und Gerüst-Updates später mit `pipx run copier update --vcs-ref HEAD` holen.

Enthalten: Django + DRF auf `basicbar-auth`/`basicbar-integrations`
(LTI 1.3 optional per Frage), React/Vite auf `@basicbar/ui` (App-Shell mit
Login/Theme/Sprache; Farb-Ramps aus den Hue-Fragen als Start-Identität),
Keycloak-Dev-Realm mit Demo-Konten, Compose-Stack mit projektfreien Ports,
Caddyfile, CI (ruff, Tests gegen PostgreSQL, Frontend-Build), README/CLAUDE.md.

Spätere Gerüst-Änderungen holt ein Tool mit `pipx run copier update`
(Basis: die generierte `.copier-answers.yml`). Erster echter Konsument:
**erkennbar** (2026-07-19, inkl. verifiziertem copier-update-Roundtrip).
Die Fragen: Name/Titel/Beschreibung, vier projektfreie Ports, zwei
OKLCH-Farbtöne als Start-Identität, `use_lti` und `ci_host` (`github` =
GitHub Actions + Release-Image nach GHCR, `gitlab` = Pipeline auf der
Uni-GitLab). Copier zeigt nach der Generierung die nächsten Schritte an
(Lockfile committen, main schützen).

Enthalten: Django + DRF auf `basicbar-auth`/`basicbar-integrations` (LTI 1.3
optional), React/Vite auf `@basicbar/ui` (App-Shell mit Login und
`PreferencesMenu`; Farb-Ramps aus den Hue-Fragen), Keycloak-Dev-Realm mit
Demo-Konten, Compose-Stack, ruff-Konfiguration, Basis-Tests, CI — **und das
Prod-Gerüst**: Root-`Dockerfile` (SPA gebacken), `docker-compose.prod.yml`
(Pflichtvariablen per `:?`), `.env.prod.example`, `Caddyfile`, bei GitHub der
Release-Workflow nach GHCR. Die Settings verweigern `DJANGO_DEBUG=0` mit dem
Entwicklungs-`SECRET_KEY`.

## Updates in bestehende Tools

`pipx run copier update --vcs-ref HEAD` im Tool spielt Gerüst-Änderungen als
Diff ein (Basis: `.copier-answers.yml`). Per `_skip_if_exists` bleiben die
Dateien unberührt, die dem Tool gehören: `tailwind.config.js` (Identität),
`App.tsx`, `locales/`, `README.md`, `CLAUDE.md`, `keycloak/realm-export.json`,
`Caddyfile`, `.env.prod.example`. Updates betreffen also compose, Dockerfiles,
CI, `settings.py`, `api.ts` — dort den Diff lesen.

## Qualitätssicherung

Die Repo-CI (`template-probe`) rendert das Template bei jedem Push mit
Defaults (LTI an, `ci_host=github`) und fährt Lint, `manage.py check`,
`makemigrations --check`, die Testsuite gegen PostgreSQL und den
Frontend-Build der generierten Anwendung. Lokal:

```bash
pipx run copier copy --trust --defaults --vcs-ref HEAD --data project_slug=probe . /tmp/probe
```

Erster echter Konsument: **erkennbar** (2026-07-19, inkl. verifiziertem
copier-update-Roundtrip).
28 changes: 28 additions & 0 deletions template/project/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.git/

# Python
**/__pycache__/
**/*.py[cod]
.venv/
venv/
**/*.egg-info/

# Node
**/node_modules/
frontend/dist/
**/*.tsbuildinfo

# Environment / secrets
.env
.env.*
!.env.example
!.env.prod.example

# Editors & OS
.idea/
.vscode/
.DS_Store

# Local data
media/
**/*.sqlite3
18 changes: 13 additions & 5 deletions template/project/CLAUDE.md.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@
{{ project_description }} Django-Backend (`backend/`, Apps `config`/`accounts`/
`common`) + React/Vite-SPA (`frontend/`). Gemeinsame Basis der virtUOS
"-bar"-Tools aus dem basicbar-Repo: `basicbar-auth` (OIDC), `basicbar-integrations`
(LibreTranslate/LiteLLM/Capabilities){% if use_lti %}, `basicbar-lti`{% endif %} und `@basicbar/ui`
(Tailwind-Preset, base.css, Theme, i18n, TranslatableField). Paketcode nie
lokal patchen — Änderungen gehören ins basicbar-Repo, Upgrade per Versions-Bump
(Changelog dort = Migrationsanleitung).
(LibreTranslate/LiteLLM){% if use_lti %}, `basicbar-lti`{% endif %} und `@basicbar/ui`
(Tailwind-Preset, base.css, Theme, i18n, TranslatableField, Preferences). Paketcode
nie lokal patchen — Änderungen gehören ins basicbar-Repo, Upgrade per
Versions-Bump (Changelog dort = Migrationsanleitung).

## Befehle

```bash
docker compose exec backend python manage.py test # Backend-Tests
docker compose exec frontend npx tsc -b # Frontend-Typecheck
docker compose exec backend sh -c "pip install -q ruff && ruff check ." # Lint (wie CI)
docker compose exec backend sh -c "pip install -q ruff && ruff check ." # Lint (wie CI, Config in backend/pyproject.toml)
```

## Workflow

- Branch + PR/MR, nie direkt auf `main`; der Mensch merged.
- Release = Git-Tag `vX.Y.Z`{% if ci_host == 'github' %} → GitHub Actions baut das Image nach GHCR{% endif %};
Deployment über `docker-compose.prod.yml` (siehe README).
- Gerüst-Updates: `pipx run copier update --vcs-ref HEAD` (Identitäts- und
Inhaltsdateien sind davon ausgenommen, siehe README).

## Konventionen

- Apache-2.0, SPDX-Header in jeder Quelldatei.
Expand Down
36 changes: 36 additions & 0 deletions template/project/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Production image: builds the SPA and bakes it into the Django image, so one
# versioned artifact per release. On start (see docker-compose.prod.yml) the
# app copies /app/frontend_dist into a volume that Caddy serves directly.

FROM node:22-slim AS frontend-build
WORKDIR /frontend
COPY frontend/package.json frontend/package-lock.json* ./
RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
COPY frontend/ .
# Same-origin API in production: VITE_API_BASE_URL stays unset (api.ts → "").
RUN npm run build

FROM python:3.12-slim

ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

# gettext for compilemessages (add `RUN python manage.py compilemessages` once
# the tool ships a locale/ directory). No compiler needed — wheels only.
RUN apt-get update \
&& apt-get install -y --no-install-recommends gettext \
&& rm -rf /var/lib/apt/lists/*

COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY backend/ .
COPY --from=frontend-build /frontend/dist /app/frontend_dist

EXPOSE 8000

# --proxy-headers: trust Caddy's X-Forwarded-* so https is detected.
CMD ["uvicorn", "config.asgi:application", "--host", "0.0.0.0", "--port", "8000", \
"--proxy-headers", "--forwarded-allow-ips", "*"]
Loading
Loading