diff --git a/backend/Dockerfile b/backend/Dockerfile
new file mode 100644
index 0000000..9c160d1
--- /dev/null
+++ b/backend/Dockerfile
@@ -0,0 +1,19 @@
+# Multi-stage Build für das Effigenix-Backend.
+# Genutzt vom E2E-Test-Stack (test-automation/docker-compose.e2e.yml).
+
+FROM maven:3.9-eclipse-temurin-21-alpine AS build
+WORKDIR /app
+
+# Dependency-Layer cachen
+COPY pom.xml .
+RUN mvn dependency:go-offline -q
+
+# Source kompilieren und paketieren (Tests überspringen)
+COPY src ./src
+RUN mvn package -DskipTests -q
+
+# Schlankes Runtime-Image
+FROM eclipse-temurin:21-jre-alpine
+WORKDIR /app
+COPY --from=build /app/target/*.jar app.jar
+ENTRYPOINT ["java", "-jar", "app.jar"]
diff --git a/backend/src/main/resources/application-e2e.yml b/backend/src/main/resources/application-e2e.yml
new file mode 100644
index 0000000..ab92fc1
--- /dev/null
+++ b/backend/src/main/resources/application-e2e.yml
@@ -0,0 +1,15 @@
+# Spring-Profil für E2E-Tests gegen echte PostgreSQL-Datenbank.
+# Aktiviert via SPRING_PROFILES_ACTIVE=e2e (docker-compose.e2e.yml).
+# Liquibase-Kontext "e2e" aktiviert Changeset 039-seed-e2e-testusers.
+
+spring:
+ liquibase:
+ contexts: e2e
+
+sentry:
+ dsn: ""
+
+logging:
+ level:
+ root: WARN
+ de.effigenix: INFO
diff --git a/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.sql b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.sql
new file mode 100644
index 0000000..d1d4e3e
--- /dev/null
+++ b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.sql
@@ -0,0 +1,46 @@
+-- E2E-Testbenutzer für automatisierte Tests.
+-- Wird nur mit Liquibase-Kontext "e2e" eingespielt (039-seed-e2e-testusers.xml).
+--
+-- Benutzer:
+-- admin / admin123 → ADMIN-Rolle (darf alles)
+-- viewer / test1234 → SALES_STAFF-Rolle (nur MASTERDATA_READ, kein WRITE)
+
+-- admin (Passwort: admin123)
+INSERT INTO users (id, username, email, password_hash, branch_id, status, created_at, last_login)
+VALUES (
+ '00000000-0000-0000-0000-000000000001',
+ 'admin',
+ 'admin@effigenix.com',
+ '$2a$12$SJmX80hUZoA66W77CX7cHeRw1TPscXD6S8HYEZfhJ5PxTfkbwbLdi',
+ NULL,
+ 'ACTIVE',
+ CURRENT_TIMESTAMP,
+ NULL
+)
+ON CONFLICT (id) DO NOTHING;
+
+INSERT INTO user_roles (user_id, role_id)
+SELECT '00000000-0000-0000-0000-000000000001', id
+FROM roles
+WHERE name = 'ADMIN'
+ON CONFLICT DO NOTHING;
+
+-- viewer (Passwort: test1234) → SALES_STAFF = nur MASTERDATA_READ
+INSERT INTO users (id, username, email, password_hash, branch_id, status, created_at, last_login)
+VALUES (
+ '00000000-0000-0000-0000-000000000002',
+ 'viewer',
+ 'viewer@effigenix.com',
+ '$2a$12$LJ3m4ys3uz2YPMRvKbmrZOZHAMSKL4FBy.XLR3WnCKsMbVDfGKJVa',
+ NULL,
+ 'ACTIVE',
+ CURRENT_TIMESTAMP,
+ NULL
+)
+ON CONFLICT (id) DO NOTHING;
+
+INSERT INTO user_roles (user_id, role_id)
+SELECT '00000000-0000-0000-0000-000000000002', id
+FROM roles
+WHERE name = 'SALES_STAFF'
+ON CONFLICT DO NOTHING;
diff --git a/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.xml b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.xml
new file mode 100644
index 0000000..26a1c78
--- /dev/null
+++ b/backend/src/main/resources/db/changelog/changes/039-seed-e2e-testusers.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/backend/src/main/resources/db/changelog/db.changelog-master.xml b/backend/src/main/resources/db/changelog/db.changelog-master.xml
index bc14b9b..2290dc1 100644
--- a/backend/src/main/resources/db/changelog/db.changelog-master.xml
+++ b/backend/src/main/resources/db/changelog/db.changelog-master.xml
@@ -44,5 +44,6 @@
+
diff --git a/justfile b/justfile
index 075edc5..f9a57cc 100644
--- a/justfile
+++ b/justfile
@@ -50,6 +50,10 @@ test-frontend:
test-backend:
cd backend && mvn test
+# E2E-Tests (Playwright API-Tests via Docker-Stack)
+test-e2e:
+ docker compose -f test-automation/docker-compose.e2e.yml up --build --abort-on-container-exit --exit-code-from e2e-runner
+
# ─── Code Generation ─────────────────────────────────────
# OpenAPI Spec + TypeScript Types generieren
diff --git a/test-automation/TASKS.md b/test-automation/TASKS.md
index 07d8310..8731494 100644
--- a/test-automation/TASKS.md
+++ b/test-automation/TASKS.md
@@ -25,18 +25,19 @@ Konzept: [`docs/ui-testing-automation.md`](./docs/ui-testing-automation.md)
> Playwright-Setup in `test-automation/web-ui/`. API-Tests ohne Browser.
-- [ ] `web-ui/package.json` finalisieren (Abhängigkeiten prüfen, ggf. pnpm workspace eintragen)
-- [ ] `web-ui/playwright.config.ts` validieren und anpassen
-- [ ] `web-ui/fixtures/auth.fixture.ts` implementieren und testen
-- [ ] `web-ui/fixtures/seed.fixture.ts` implementieren (DB-Reset-Strategie klären)
-- [ ] `web-ui/helpers/api-client.ts` typisiert implementieren
-- [ ] Backend `Dockerfile` erstellen (test-Profil, mit Seed-Daten)
-- [ ] `docker-compose.e2e.yml` validieren (DB → Backend → e2e-runner Healthchecks)
-- [ ] `web-ui/Dockerfile` validieren
-- [ ] Erste Spec: `tests/api/masterdata/categories.spec.ts` (TC-CAT, Issue #62)
-- [ ] Erste Spec: `tests/api/masterdata/suppliers.spec.ts` (TC-SUP, Issue #63)
+- [x] `web-ui/package.json` finalisieren (standalone, kein Workspace-Eintrag nötig)
+- [x] `web-ui/playwright.config.ts` validieren und anpassen
+- [x] `web-ui/fixtures/auth.fixture.ts` implementieren (viewer-Passwort: test1234)
+- [x] `web-ui/fixtures/seed.fixture.ts` implementieren (Strategie: Option B – UUID-Suffixe)
+- [x] `web-ui/helpers/api-client.ts` typisiert implementieren
+- [x] Backend `Dockerfile` erstellen (Multi-stage Maven + JRE, Profil via SPRING_PROFILES_ACTIVE)
+- [x] `docker-compose.e2e.yml` validieren (Profil auf `e2e` korrigiert, Viewer-Passwort angepasst)
+- [x] `web-ui/Dockerfile` korrigiert (standalone pnpm install, kein Workspace)
+- [x] `application-e2e.yml` + Liquibase-Changeset 039 (admin + viewer e2e-Benutzer)
+- [x] Erste Spec: `tests/api/masterdata/categories.spec.ts` (TC-CAT, Issue #62)
+- [x] Erste Spec: `tests/api/masterdata/suppliers.spec.ts` (TC-SUP-01 ACTIVE korrigiert, Issue #63)
- [ ] End-to-end-Run lokal erfolgreich: `docker compose -f test-automation/docker-compose.e2e.yml up`
-- [ ] `just test-e2e` Recipe im `justfile` ergänzen
+- [x] `just test-e2e` Recipe im `justfile` ergänzt
---
diff --git a/test-automation/docker-compose.e2e.yml b/test-automation/docker-compose.e2e.yml
index c71e01e..f8a2e1d 100644
--- a/test-automation/docker-compose.e2e.yml
+++ b/test-automation/docker-compose.e2e.yml
@@ -21,7 +21,7 @@ services:
context: ../backend
dockerfile: Dockerfile
environment:
- SPRING_PROFILES_ACTIVE: test
+ SPRING_PROFILES_ACTIVE: e2e
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/effigenix
SPRING_DATASOURCE_USERNAME: effigenix
SPRING_DATASOURCE_PASSWORD: effigenix
@@ -45,7 +45,7 @@ services:
TEST_USER_ADMIN: admin
TEST_USER_ADMIN_PASS: admin123
TEST_USER_VIEWER: viewer
- TEST_USER_VIEWER_PASS: viewer123
+ TEST_USER_VIEWER_PASS: test1234
depends_on:
backend:
condition: service_healthy
diff --git a/test-automation/web-ui/Dockerfile b/test-automation/web-ui/Dockerfile
index f767bf8..52e2ad2 100644
--- a/test-automation/web-ui/Dockerfile
+++ b/test-automation/web-ui/Dockerfile
@@ -1,20 +1,18 @@
+# E2E-Test-Runner (Playwright API-Tests, kein Browser)
+# Build-Context: Repo-Root (..)
+# Standalone – benötigt keine pnpm-Workspace-Konfiguration.
+
FROM mcr.microsoft.com/playwright:v1.51.0-noble
-WORKDIR /app
-
-# pnpm installieren
RUN npm install -g pnpm@9
-# Workspace-Root und e2e-Package-Manifest kopieren
-COPY frontend/package.json frontend/pnpm-workspace.yaml ./
-COPY test-automation/web-ui/package.json ./test-automation/web-ui/
-
-# pnpm Install (nur Prod + Dev-Deps des e2e-Pakets)
-RUN pnpm install --frozen-lockfile
-
-# Test-Code und Konfiguration kopieren
-COPY test-automation/web-ui/ ./test-automation/web-ui/
-
WORKDIR /app/test-automation/web-ui
-ENTRYPOINT ["pnpm", "exec", "playwright", "test"]
+# Nur package.json zuerst für Layer-Caching
+COPY test-automation/web-ui/package.json ./
+RUN pnpm install --no-frozen-lockfile
+
+# Test-Code kopieren
+COPY test-automation/web-ui/ ./
+
+ENTRYPOINT ["pnpm", "exec", "playwright", "test", "--project=api"]
diff --git a/test-automation/web-ui/fixtures/auth.fixture.ts b/test-automation/web-ui/fixtures/auth.fixture.ts
index 797fac1..8a46feb 100644
--- a/test-automation/web-ui/fixtures/auth.fixture.ts
+++ b/test-automation/web-ui/fixtures/auth.fixture.ts
@@ -22,7 +22,7 @@ export const test = base.extend({
const res = await request.post('/api/auth/login', {
data: {
username: process.env.TEST_USER_VIEWER ?? 'viewer',
- password: process.env.TEST_USER_VIEWER_PASS ?? 'viewer123',
+ password: process.env.TEST_USER_VIEWER_PASS ?? 'test1234',
},
});
expect(res.status()).toBe(200);
diff --git a/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts b/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts
index 6a224c7..c7a48fa 100644
--- a/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts
+++ b/test-automation/web-ui/tests/api/masterdata/suppliers.spec.ts
@@ -12,7 +12,7 @@ test.describe('TC-SUP: Lieferanten', () => {
});
expect(res.status()).toBe(201);
const body = await res.json();
- expect(body.status).toBe('AKTIV');
+ expect(body.status).toBe('ACTIVE');
});
test('TC-SUP-02: Lieferant erscheint in Liste nach Erstellung', async ({ request, adminToken }) => {
diff --git a/test-automation/web-ui/tsconfig.json b/test-automation/web-ui/tsconfig.json
index 47ddf1b..0fcbd3b 100644
--- a/test-automation/web-ui/tsconfig.json
+++ b/test-automation/web-ui/tsconfig.json
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ES2022",
- "module": "ESNext",
- "moduleResolution": "bundler",
+ "module": "CommonJS",
+ "moduleResolution": "node16",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,