12 KiB
id, title, status, phase, created
| id | title | status | phase | created |
|---|---|---|---|---|
| WP-0001 | Projektgerüst — Django-Setup, Tailwind, Dev-Stack | done | 1-of-12 | 2026-05-08 |
WP-0001 — Projektgerüst
Legt das vollständige Django-Projektgerüst an: uv, Projektstruktur, Settings, alle App-Hüllen, Tailwind CSS v4 via Vite, HTMX + Alpine.js, Docker Compose für PostgreSQL, pytest-django, Makefile.
Referenzdokumente: wiki/ArchitectureBlueprint.md Abschnitte 2 und 3.
Arbeitsverzeichnis: /home/worsch/vergabe-teilnahme/
id: WP-0001-T01
title: pyproject.toml und uv-Projektstruktur anlegen
status: done
Erstelle `pyproject.toml` mit uv als Package-Manager.
Abhängigkeiten (production):
django>=5.2, psycopg[binary]>=3.2, django-storages>=1.14,
whitenoise>=6.7, python-decouple>=3.8
Abhängigkeiten (dev):
pytest-django>=4.8, pytest-cov>=5.0, factory-boy>=3.3,
ruff>=0.4, mypy>=1.10, django-stubs>=5.0
Python: >=3.12
Erstelle außerdem `.python-version` mit `3.12`.
Führe `uv sync` aus und bestätige, dass die virtuelle Umgebung erstellt wird.
id: WP-0001-T02
title: Django-Projekt initialisieren und Settings-Struktur anlegen
status: done
Führe `uv run django-admin startproject vergabe_teilnahme .` aus
(Punkt am Ende — kein verschachteltes Projektverzeichnis).
Erstelle `vergabe_teilnahme/settings/` mit:
- `__init__.py` (leer)
- `base.py` — gemeinsame Settings (INSTALLED_APPS, TEMPLATES, STATIC, MEDIA,
AUTH_USER_MODEL = 'accounts.Mitarbeiter', DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField',
LANGUAGE_CODE = 'de-de', TIME_ZONE = 'Europe/Berlin', USE_I18N = True, USE_TZ = True)
- `dev.py` — importiert base, setzt DEBUG=True, ALLOWED_HOSTS=['*'],
DATABASE aus python-decouple .env
- `prod.py` — importiert base, DEBUG=False, ALLOWED_HOSTS aus Env,
WhiteNoise-Middleware, SECURE_* Flags
Passe `manage.py` und `vergabe_teilnahme/wsgi.py` auf
`DJANGO_SETTINGS_MODULE = 'vergabe_teilnahme.settings.dev'` an.
id: WP-0001-T03
title: .env.example und PostgreSQL-Konfiguration
status: done
Erstelle `.env.example`:
DATABASE_URL=postgres://vergabe:vergabe@localhost:5432/vergabe_db SECRET_KEY=change-me-in-production DEBUG=True ALLOWED_HOSTS=localhost,127.0.0.1 MEDIA_ROOT=media/ MAX_UPLOAD_SIZE=52428800
In `settings/base.py` lese DATABASE_URL via `python-decouple` und parse mit
`dj-database-url` (füge `dj-database-url>=2.1` zu pyproject.toml hinzu).
Erstelle `.env` (nur lokal, in .gitignore) mit Entwicklungswerten.
Prüfe dass `.env` und `*.sqlite3` in `.gitignore` enthalten sind.
id: WP-0001-T04
title: Alle Django-Apps anlegen
status: done
Erstelle folgende Apps mit `uv run manage.py startapp <name>`:
core, accounts, ausschreibungen, lose, aufgaben,
dokumente, preise, partner, bibliothek, marktbegleiter,
nachbetrachtung, feedback
Verschiebe jede App in ein eigenes Unterverzeichnis:
`vergabe_teilnahme/apps/<app_name>/`
Passe in jeder App `apps.py` den `name` auf `vergabe_teilnahme.apps.<app_name>` an.
Füge alle Apps zu `INSTALLED_APPS` in `settings/base.py` hinzu.
Stelle sicher, dass `django.contrib.contenttypes` ebenfalls in INSTALLED_APPS ist
(wird für GenericForeignKey im core-Modell benötigt).
id: WP-0001-T05
title: Tailwind CSS v4 via Vite integrieren
status: done
Erstelle `package.json` im Projektwurzelverzeichnis:
```json
{
"scripts": {
"dev": "vite build --watch",
"build": "vite build"
},
"devDependencies": {
"vite": "^5.0",
"@tailwindcss/vite": "^4.0",
"tailwindcss": "^4.0"
}
}
Erstelle vite.config.js:
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
build: { outDir: 'static/dist', emptyOutDir: true,
rollupOptions: { input: 'static/src/main.css' } }
})
Erstelle static/src/main.css:
@import "tailwindcss";
@layer base { /* German-app base resets */ }
@layer components {
.card { @apply bg-white rounded-xl border border-slate-200 shadow-sm p-6; }
.btn-primary { @apply bg-brand-500 text-white px-4 py-2 rounded-lg hover:bg-brand-600 transition-colors; }
.btn-secondary { @apply bg-white text-slate-700 border border-slate-300 px-4 py-2 rounded-lg hover:bg-slate-50; }
.btn-danger { @apply bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700; }
.btn-ghost { @apply text-slate-600 px-3 py-2 rounded-lg hover:bg-slate-100; }
.field-row { @apply grid grid-cols-3 gap-4 py-3 border-b border-slate-100 last:border-0; }
.field-label { @apply text-sm font-medium text-slate-500 col-span-1; }
.field-value { @apply text-sm text-slate-900 col-span-2; }
.phase-badge { @apply inline-flex items-center justify-center w-7 h-7 rounded-full text-sm font-bold; }
.phase-todo { @apply phase-badge bg-slate-200 text-slate-500; }
.phase-active { @apply phase-badge bg-brand-500 text-white; }
.phase-done { @apply phase-badge bg-green-500 text-white; }
.phase-warn { @apply phase-badge bg-amber-400 text-amber-900; }
.section-title { @apply text-base font-semibold text-slate-900 mb-4; }
.page-title { @apply text-2xl font-bold text-slate-900; }
.form-input { @apply w-full rounded-lg border border-slate-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:border-transparent; }
.form-label { @apply block text-sm font-medium text-slate-700 mb-1; }
.table-base { @apply w-full text-sm text-left; }
.table-header { @apply bg-slate-50 text-slate-500 font-medium text-xs uppercase tracking-wide; }
.table-row { @apply border-t border-slate-100 hover:bg-slate-50 transition-colors; }
}
Füge CSS-Theme-Token für brand in main.css hinzu:
@theme {
--color-brand-50: #f0f4ff;
--color-brand-100: #dce7ff;
--color-brand-500: #3b5bdb;
--color-brand-600: #2f4ac7;
--color-brand-700: #2541b2;
--color-brand-900: #152d99;
}
Konfiguriere Django STATICFILES_DIRS und STATIC_ROOT in settings/base.py.
Füge STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
in settings/prod.py ein.
Führe npm install aus.
```task
id: WP-0001-T06
title: HTMX und Alpine.js einbinden
status: done
Lade HTMX und Alpine.js als lokale Vendor-Dateien (keine CDN-Abhängigkeit):
- `static/vendor/htmx/htmx.min.js` — HTMX 2.x (von unpkg herunterladen)
- `static/vendor/alpinejs/alpine.min.js` — Alpine.js 3.x
Füge in `settings/base.py` hinzu:
```python
STATICFILES_DIRS = [BASE_DIR / 'static']
Die Einbindung im base.html-Template erfolgt in WP-0003.
Erstelle hier nur die Verzeichnisstruktur und die Dateien.
Prüfe: ls static/vendor/htmx/ und ls static/vendor/alpinejs/ sollten die Dateien zeigen.
```task
id: WP-0001-T07
title: Docker Compose für Entwicklungs-PostgreSQL
status: done
Erstelle `docker-compose.dev.yml`:
```yaml
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: vergabe_db
POSTGRES_USER: vergabe
POSTGRES_PASSWORD: vergabe
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Erstelle außerdem docker-compose.test.yml für CI (gleiche Konfiguration,
anderer DB-Name: vergabe_test).
Starte die DB: docker compose -f docker-compose.dev.yml up -d
Prüfe Verbindung: uv run manage.py check --database default
```task
id: WP-0001-T08
title: pytest-django konfigurieren
status: done
Füge in `pyproject.toml` hinzu:
```toml
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "vergabe_teilnahme.settings.dev"
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = "--tb=short -q"
[tool.ruff]
line-length = 100
target-version = "py312"
select = ["E", "F", "I", "N", "UP"]
Erstelle conftest.py im Projektwurzel:
import pytest
@pytest.fixture
def mitarbeiter(db):
from vergabe_teilnahme.apps.accounts.models import Mitarbeiter
return Mitarbeiter.objects.create_user(
username='testuser', password='testpass', first_name='Test', last_name='User'
)
Prüfe: uv run pytest --co -q (keine Tests vorhanden, aber Konfiguration valide).
```task
id: WP-0001-T09
title: Makefile für häufige Dev-Commands
status: done
Erstelle `Makefile` im Projektwurzel:
```makefile
.PHONY: dev db migrate shell test lint css
db:
docker compose -f docker-compose.dev.yml up -d
dev: db
uv run manage.py runserver 0.0.0.0:8000
css:
npm run dev
migrate:
uv run manage.py makemigrations
uv run manage.py migrate
shell:
uv run manage.py shell_plus 2>/dev/null || uv run manage.py shell
test:
uv run pytest
lint:
uv run ruff check .
uv run mypy vergabe_teilnahme/
createsuperuser:
uv run manage.py createsuperuser
collectstatic:
uv run manage.py collectstatic --noinput
Prüfe: make db startet PostgreSQL, make migrate läuft fehlerfrei durch
(zu diesem Zeitpunkt noch ohne Fachmodelle — nur Django-Default-Migrationen).
```task
id: WP-0001-T10
title: Django URL-Grundkonfiguration und Health-Check
status: done
Editiere `vergabe_teilnahme/urls.py`:
```python
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.http import JsonResponse
def health(request):
return JsonResponse({'status': 'ok'})
urlpatterns = [
path('admin/', admin.site.urls),
path('health/', health),
# Module-URLs werden in späteren Workplans ergänzt
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Füge in settings/base.py hinzu:
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
Prüfe: make dev startet ohne Fehler, curl http://localhost:8000/health/
gibt {"status": "ok"} zurück.
```task
id: WP-0001-T11
title: CLAUDE.md mit Build-Commands aktualisieren
status: done
Aktualisiere `/home/worsch/vergabe-teilnahme/CLAUDE.md` um einen Abschnitt
"## Entwicklungs-Commands":
```markdown
## Entwicklungs-Commands
```bash
make db # PostgreSQL via Docker starten
make dev # Django-Dev-Server (Port 8000)
make css # Tailwind CSS im Watch-Modus
make migrate # Migrations generieren und ausführen
make test # pytest ausführen
make lint # ruff + mypy
uv run manage.py test <app> # Einzelne App testen
uv run pytest tests/<pfad>.py # Einzelne Testdatei
Projektstruktur
vergabe_teilnahme/
├── apps/ # Alle Django-Apps
│ ├── core/ # FlexibleModel, CustomAttribute, EntityFieldConfig, Freigabe
│ ├── accounts/ # Mitarbeiter (AbstractUser)
│ └── ... # je eine App pro Fachdomäne
├── settings/ # base.py, dev.py, prod.py
└── urls.py
static/
├── src/main.css # Tailwind-Quelldatei
├── vendor/ # HTMX, Alpine.js
└── dist/ # Build-Output (gitignored)
workplans/ # Ralph-Loop-Workplans
wiki/ # PRD, Blueprint, Use-Case-Katalog
Füge außerdem `static/dist/` zu `.gitignore` hinzu.
id: WP-0001-T12
title: Erstes `uv run manage.py migrate` und Smoke-Test
status: done
Führe die gesamte initiale Setup-Sequenz durch und verifiziere:
1. `make db` → PostgreSQL läuft
2. `uv run manage.py migrate` → alle Django-Default-Migrationen laufen sauber durch
3. `uv run manage.py check` → keine Fehler
4. `uv run pytest` → 0 Tests gesammelt, kein Fehler
5. `npm run build` → `static/dist/` enthält die kompilierte CSS-Datei
6. `make dev` → Server startet, `/health/` antwortet mit 200
Notiere etwaige Fehler und behebe sie. Erst wenn alle 6 Checks bestanden sind
gilt dieser Task als erledigt.