diff --git a/Dockerfile b/Dockerfile
index 10eba53..f01ea1c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,25 +1,15 @@
-# ---- Stage 1: Frontend bauen ----
-FROM node:20-slim AS frontend-build
-WORKDIR /app/frontend
-COPY frontend/package.json ./
-RUN npm install
-COPY frontend/ ./
-RUN npm run build
-
-# ---- Stage 2: Backend + gebautes Frontend ----
-FROM node:20-slim AS runtime
-WORKDIR /app
+FROM node:20-slim
+WORKDIR /app/backend
COPY backend/package.json ./
RUN npm install --omit=dev
COPY backend/ ./
-# Vom Build-Stage kommt das fertige Frontend nach backend/public
-COPY --from=frontend-build /app/backend/public ./public
+COPY frontend/ /app/frontend
ENV NODE_ENV=production
-ENV PORT=3000
+ENV PORT=3001
-EXPOSE 3000
+EXPOSE 3001
CMD ["node", "src/index.js"]
diff --git a/README.md b/README.md
index 90a8473..a411312 100644
--- a/README.md
+++ b/README.md
@@ -19,14 +19,16 @@ Kapazitaetsplanung pro Person.
## Architektur
- **Backend**: Node.js + Express, liefert eine REST-API (`/api/...`) und das
- gebaute Frontend aus.
+ 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**: React + Vite, wird beim Docker-Build in `backend/public`
- gebaut und vom Backend ausgeliefert.
+- **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)
@@ -34,17 +36,18 @@ Kapazitaetsplanung pro Person.
# MongoDB lokal starten (z. B. per Docker)
docker run -d --name jp-mongo -p 27017:27017 mongo:7
-# Backend
+# 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:3000
-
-# Frontend (in zweitem Terminal)
-cd frontend
-npm install
-npm run dev # http://localhost:5173, proxied /api zu :3000
+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
@@ -53,11 +56,15 @@ npm run dev # http://localhost:5173, proxied /api zu :3000
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 `3000` (im
- `docker-compose.yml` gemappt). In Coolify unter "Domains" die gewuenschte
- Domain/Subdomain zuweisen. Der MongoDB-Container hat bewusst **keinen**
- nach aussen gemappten Port und ist nur innerhalb des Compose-Netzwerks
- fuer die App erreichbar.
+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.
diff --git a/backend/src/index.js b/backend/src/index.js
index 34da026..02abe0d 100644
--- a/backend/src/index.js
+++ b/backend/src/index.js
@@ -10,7 +10,7 @@ const absencesRouter = require("./routes/absences");
const capacityRouter = require("./routes/capacity");
const app = express();
-const PORT = process.env.PORT || 3000;
+const PORT = process.env.PORT || 3001;
app.use(cors());
app.use(express.json());
@@ -23,13 +23,14 @@ app.use("/api/tasks", tasksRouter);
app.use("/api/absences", absencesRouter);
app.use("/api/capacity", capacityRouter);
-// Gebautes Frontend (Vite -> dist) ausliefern
-const frontendDist = path.join(__dirname, "..", "public");
-app.use(express.static(frontendDist));
+// Statisches Frontend (HTML/CSS/JS, kein Build-Step) aus dem
+// Geschwisterverzeichnis "frontend" ausliefern
+const frontendDir = path.join(__dirname, "..", "..", "frontend");
+app.use(express.static(frontendDir));
-// SPA-Fallback: alles, was nicht /api ist, liefert die index.html aus
+// Fallback: alles, was nicht /api ist, liefert die index.html aus
app.get(/^(?!\/api).*/, (req, res) => {
- res.sendFile(path.join(frontendDist, "index.html"));
+ res.sendFile(path.join(frontendDir, "index.html"));
});
app.use((err, req, res, next) => {
diff --git a/docker-compose.yml b/docker-compose.yml
index c6a054b..40979d4 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -5,9 +5,9 @@ services:
dockerfile: Dockerfile
restart: unless-stopped
ports:
- - "3000:3000"
+ - "3001:3001"
environment:
- - PORT=3000
+ - PORT=3001
- MONGODB_URI=mongodb://mongo:27017/jahresplanung
depends_on:
- mongo
diff --git a/frontend/src/styles.css b/frontend/css/styles.css
similarity index 99%
rename from frontend/src/styles.css
rename to frontend/css/styles.css
index b50600b..72f8bfb 100644
--- a/frontend/src/styles.css
+++ b/frontend/css/styles.css
@@ -1,3 +1,7 @@
+[x-cloak] {
+ display: none !important;
+}
+
:root {
--bg: #f6f3ec;
--surface: #ffffff;
diff --git a/frontend/index.html b/frontend/index.html
index ff5b3c5..53a1600 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -10,9 +10,530 @@
href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap"
rel="stylesheet"
/>
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
Zeitachse
+
+ Alle Aufgaben eines Jahres auf einen Blick, gruppiert nach Projekt. Balkenfarbe
+ folgt der zustaendigen Person (falls zugewiesen), sonst der Projektfarbe.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Kapazitaet
+
+ Zugewiesene Stunden je Person und Monat gegen die verfuegbare Nettokapazitaet
+ (Wochenstunden minus Abwesenheiten). Die gestrichelte Linie markiert 100 %
+ Auslastung.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Noch keine Personen angelegt. Lege zuerst Team-Mitglieder mit Wochenkapazitaet an.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Im Rahmen
+
+
+ Ab 90 % ausgelastet
+
+
+ Ueberlast
+
+
+
+ 100 % Kapazitaet
+
+
+
+
+
+
+
+
+
+
+
Projekte & Aufgaben
+
+ Projekte in Aufgaben mit Start- und Enddatum, Aufwand und Zustaendigkeit
+ zerlegen. Abhaengigkeiten koennen pro Aufgabe hinterlegt werden.
+
+
+
+
+
+
+
+
+
+
+ Noch keine Projekte angelegt. Starte mit „Projekt anlegen“.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Aufgabe
+
Start
+
Ende
+
Aufwand
+
Zustaendig
+
Prioritaet
+
Status
+
+
+
+
+
+
Noch keine Aufgaben in diesem Projekt.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Team
+
+ Wochenkapazitaet pro Person hinterlegen. Sie bildet die Grundlage fuer die
+ Auslastungsberechnung auf der Kapazitaet-Ansicht.
+
+
+
+
+
+
+
+
+
+
+
+
Name
+
Rolle
+
Std. / Woche
+
+
+
+
+
+
Noch keine Personen angelegt.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Person
+
Von
+
Bis
+
Notiz
+
+
+
+
+
+
Keine Abwesenheiten hinterlegt (Urlaub, Feiertage, etc.).