114 lines
5.3 KiB
Markdown
114 lines
5.3 KiB
Markdown
# Jahresplanung & Kapazitaetsplanung
|
||
|
||
Eine schlanke Web-App zur Jahresplanung mehrerer Projekte mit integrierter
|
||
Kapazitaetsplanung pro Person.
|
||
|
||
## Funktionen
|
||
|
||
- **Projekte & Aufgaben**: Projekte in Aufgaben mit Start-/Enddatum, Aufwand
|
||
(Stunden), Zustaendigkeit, Prioritaet und optionaler Abhaengigkeit zerlegen.
|
||
- **Team**: Personen mit Wochenkapazitaet (Stunden) und Abwesenheiten
|
||
(Urlaub, Feiertage) pflegen.
|
||
- **Zeitachse**: Alle Aufgaben eines Jahres als Balken je Projekt, jahrweise
|
||
navigierbar.
|
||
- **Kapazitaet**: Automatische Auslastungsberechnung je Person und Monat.
|
||
Der Aufwand jeder Aufgabe wird gleichmaessig ueber ihre Werktage verteilt
|
||
und den betroffenen Monaten anteilig zugerechnet; Abwesenheiten reduzieren
|
||
die verfuegbare Nettokapazitaet. Ueberlast wird farblich markiert.
|
||
|
||
## Architektur
|
||
|
||
- **Backend**: Node.js + Express, liefert eine REST-API (`/api/...`) und das
|
||
statische Frontend aus.
|
||
- **Datenhaltung**: MongoDB (eigener Container, offizieller Node-Treiber
|
||
`mongodb`). Vier Collections: `people`, `projects`, `tasks`, `absences`.
|
||
Die Mongo-`_id` wird beim Ausliefern an das Frontend in ein einfaches
|
||
`id`-Feld (String) umgewandelt; Referenzen zwischen Entitaeten (z. B.
|
||
`assigneeId`, `projectId`) werden als dieser String gespeichert.
|
||
- **Frontend**: Reines HTML/CSS/JS mit [Alpine.js](https://alpinejs.dev/)
|
||
(lokal in `frontend/js/vendor` eingebettet, keine externe CDN-Abhaengigkeit
|
||
zur Laufzeit). Kein Build-Step: `frontend/` wird beim Docker-Build 1:1 nach
|
||
`backend/public` kopiert und vom Backend ausgeliefert.
|
||
|
||
## Lokale Entwicklung (optional)
|
||
|
||
```bash
|
||
# MongoDB lokal starten (z. B. per Docker)
|
||
docker run -d --name jp-mongo -p 27017:27017 mongo:7
|
||
|
||
# Backend (liefert API + Frontend zusammen aus, kein separater Frontend-Server noetig)
|
||
cd backend
|
||
npm install
|
||
MONGODB_URI=mongodb://localhost:27017/jahresplanung npm start # http://localhost:3001
|
||
```
|
||
|
||
Das Frontend liegt unter `frontend/` als reine statische Dateien (kein
|
||
`npm install`/Build noetig). Das Backend liefert es direkt aus dem
|
||
Geschwisterverzeichnis `../frontend` aus (lokal wie im Docker-Image
|
||
identisch, siehe `backend/src/index.js`). Einfach im Browser
|
||
`http://localhost:3001` oeffnen.
|
||
|
||
## Deployment in Coolify
|
||
|
||
1. **Repository verbinden**: Diesen Ordner in ein Git-Repository pushen
|
||
(GitHub/GitLab/Gitea) und in Coolify als neue Ressource hinzufuegen
|
||
(New Resource → Application → dein Repo).
|
||
2. **Build-Pack**: **Docker Compose** waehlen. Das mitgelieferte
|
||
`docker-compose.yml` startet automatisch zwei Container: die App und
|
||
MongoDB, inklusive persistentem Volume fuer die Datenbank.
|
||
3. **Port**: Der App-Container lauscht auf Port `3001` (im
|
||
`docker-compose.yml` gemappt). In Coolify unter "Domains"/der
|
||
Port-Konfiguration der Ressource **muss dieser Port (3001) explizit
|
||
eingetragen werden** — das passiert nicht automatisch, wenn sich der Port
|
||
nach einem vorherigen Deployment aendert. Falls der Host-Port bereits von
|
||
einer anderen Ressource belegt ist, in `docker-compose.yml` einen anderen
|
||
freien Port waehlen und die Coolify-Konfiguration entsprechend anpassen.
|
||
Der MongoDB-Container hat bewusst **keinen** nach aussen gemappten Port
|
||
und ist nur innerhalb des Compose-Netzwerks fuer die App erreichbar.
|
||
4. **Persistenz**: Das Volume `jahresplanung-mongo-data` sichert die
|
||
MongoDB-Datendateien. Bei Redeploys bleiben die Daten erhalten, solange
|
||
das Volume nicht geloescht wird.
|
||
5. **Deploy** klicken. Coolify baut das App-Image und startet beide
|
||
Container. Die App verbindet sich beim Start einmalig mit MongoDB; falls
|
||
das noch nicht bereit ist, beendet sich der App-Container mit einer
|
||
Fehlermeldung im Log und Coolify startet ihn (je nach Restart-Policy)
|
||
erneut — meist reicht ein manueller Restart des App-Containers, falls er
|
||
schneller hochkommt als MongoDB.
|
||
|
||
### Absicherung (optional, empfohlen fuer produktiven Einsatz)
|
||
|
||
Der MongoDB-Container laeuft standardmaessig **ohne Authentifizierung**,
|
||
ist aber nicht nach aussen exponiert (kein `ports:`-Eintrag), sondern nur
|
||
innerhalb des internen Compose-Netzwerks erreichbar. Fuer zusaetzliche
|
||
Absicherung kannst du `MONGO_INITDB_ROOT_USERNAME` /
|
||
`MONGO_INITDB_ROOT_PASSWORD` beim `mongo`-Service setzen und die
|
||
`MONGODB_URI` beim App-Service entsprechend um die Zugangsdaten ergaenzen
|
||
(`mongodb://user:pass@mongo:27017/jahresplanung?authSource=admin`).
|
||
|
||
### Ohne docker-compose (alternativ)
|
||
|
||
Falls du in Coolify statt "Docker Compose" nur "Dockerfile" als Build-Pack
|
||
waehlst, musst du MongoDB als separate Coolify-Ressource (oder externen
|
||
Dienst) anlegen und die Umgebungsvariable `MONGODB_URI` am App-Container
|
||
manuell auf die MongoDB-Verbindung zeigen lassen.
|
||
|
||
## Backup
|
||
|
||
`mongodump` / `mongorestore` gegen den Mongo-Container, oder Coolifys
|
||
eingebaute Backup-Funktion fuer das Volume `jahresplanung-mongo-data`
|
||
verwenden.
|
||
|
||
## Datenmodell (Kurzueberblick)
|
||
|
||
| Entitaet | Felder |
|
||
|---|---|
|
||
| Person | name, role, weeklyHours, color |
|
||
| Projekt | name, description, color |
|
||
| Aufgabe | projectId, name, startDate, endDate, estimatedHours, assigneeId, priority, status, dependsOn |
|
||
| Abwesenheit | personId, startDate, endDate, note |
|
||
|
||
Die Kapazitaetsberechnung (`GET /api/capacity?from=...&to=...`) aggregiert
|
||
je Person und Monat: verfuegbare Werktage minus Abwesenheiten × Tageskapazitaet
|
||
als `capacityHours`, sowie anteilig verteilte `assignedHours` aus allen
|
||
zugewiesenen Aufgaben.
|