diff --git a/.gitea/workflows/cd-deploy.yml b/.gitea/workflows/cd-deploy.yml index f368e3f..cec4b8b 100644 --- a/.gitea/workflows/cd-deploy.yml +++ b/.gitea/workflows/cd-deploy.yml @@ -47,11 +47,12 @@ jobs: - name: Kustomize Edit Image Tag working-directory: ./infra/k8s/overlays/dev run: | - kustomize edit set image 192.168.241.13:8080/workclub-api=192.168.241.13:8080/workclub-api:$IMAGE_TAG - kustomize edit set image 192.168.241.13:8080/workclub-frontend=192.168.241.13:8080/workclub-frontend:$IMAGE_TAG + kustomize edit set image workclub-api=192.168.241.13:8080/workclub-api:$IMAGE_TAG + kustomize edit set image workclub-frontend=192.168.241.13:8080/workclub-frontend:$IMAGE_TAG - name: Deploy to Kubernetes run: | + set -euo pipefail export KUBECONFIG=$HOME/.kube/config mkdir -p $HOME/.kube if echo "${{ secrets.KUBECONFIG }}" | grep -q "apiVersion"; then @@ -63,28 +64,34 @@ jobs: printf '%s' "${{ secrets.KUBECONFIG }}" | base64 -d > $KUBECONFIG fi chmod 600 $KUBECONFIG + + kubectl --kubeconfig="$KUBECONFIG" config view >/dev/null # Diagnostics echo "Kubeconfig path: $KUBECONFIG" echo "Kubeconfig size: $(wc -c < $KUBECONFIG) bytes" echo "Available contexts:" - kubectl config get-contexts + kubectl --kubeconfig="$KUBECONFIG" config get-contexts if ! grep -q "current-context" $KUBECONFIG; then echo "Warning: current-context missing, attempting to fix..." - FIRST_CONTEXT=$(kubectl config get-contexts -o name | head -n 1) + FIRST_CONTEXT=$(kubectl --kubeconfig="$KUBECONFIG" config get-contexts -o name | head -n 1) if [ -n "$FIRST_CONTEXT" ]; then - kubectl config use-context "$FIRST_CONTEXT" + kubectl --kubeconfig="$KUBECONFIG" config use-context "$FIRST_CONTEXT" fi fi - echo "Current context: $(kubectl config current-context)" + echo "Current context: $(kubectl --kubeconfig="$KUBECONFIG" config current-context)" # Ensure target namespace exists - kubectl create namespace workclub-dev --dry-run=client -o yaml | kubectl apply -f - + kubectl --kubeconfig="$KUBECONFIG" create namespace workclub-dev --dry-run=client -o yaml | kubectl --kubeconfig="$KUBECONFIG" apply -f - - # Delete existing StatefulSet to allow immutable field changes (vct -> emptyDir) - kubectl delete statefulset workclub-postgres -n workclub-dev --ignore-not-found - - kubectl config view --minify # Verification of context - kubectl apply -k infra/k8s/overlays/dev + # Apply manifests (non-destructive by default; avoid DB state churn) + kubectl --kubeconfig="$KUBECONFIG" config view --minify # Verification of context + kustomize build --load-restrictor LoadRestrictionsNone infra/k8s/overlays/dev | kubectl --kubeconfig="$KUBECONFIG" apply -f - + + # Rollout verification + kubectl --kubeconfig="$KUBECONFIG" rollout status statefulset/workclub-postgres -n workclub-dev --timeout=300s + kubectl --kubeconfig="$KUBECONFIG" rollout status deployment/workclub-keycloak -n workclub-dev --timeout=600s + kubectl --kubeconfig="$KUBECONFIG" rollout status deployment/workclub-api -n workclub-dev --timeout=300s + kubectl --kubeconfig="$KUBECONFIG" rollout status deployment/workclub-frontend -n workclub-dev --timeout=300s diff --git a/.sisyphus/plans/club-work-manager.md b/.sisyphus/plans/club-work-manager.md index 239e187..1e2af58 100644 --- a/.sisyphus/plans/club-work-manager.md +++ b/.sisyphus/plans/club-work-manager.md @@ -12,6 +12,7 @@ > - Docker Compose for local development (hot reload, Keycloak, PostgreSQL) > - Kubernetes manifests (Kustomize base + dev overlay) > - Gitea CI pipeline (`.gitea/workflows/ci.yml`) for backend/frontend/infrastructure validation +> - Gitea CD bootstrap + deployment pipelines (`.gitea/workflows/cd-bootstrap.yml`, `.gitea/workflows/cd-deploy.yml`) > - Comprehensive TDD test suite (xUnit + Testcontainers, Vitest + RTL, Playwright E2E) > - Seed data for development (2 clubs, 5 users, sample tasks + shifts) > @@ -36,7 +37,7 @@ Build a multi-tenant internet application for managing work items over several m - **Testing**: TDD approach (tests first). - **Notifications**: None for MVP. - **CI extension**: Add Gitea-hosted CI pipeline for this repository. -- **Pipeline scope**: CI-only (build/test/lint/manifest validation), no auto-deploy in this iteration. +- **Pipeline scope (updated)**: CI + CD. CI handles build/test/lint/manifest validation; CD bootstrap publishes multi-arch images; CD deploy applies Kubernetes manifests. **Research Findings**: - **Finbuckle.MultiTenant**: ClaimStrategy + HeaderStrategy fallback is production-proven (fullstackhero/dotnet-starter-kit pattern). @@ -73,6 +74,8 @@ Deliver a working multi-tenant club work management application where authentica - `/docker-compose.yml` — Local dev stack (PostgreSQL, Keycloak, .NET API, Next.js) - `/infra/k8s/` — Kustomize manifests (base + dev overlay) - `/.gitea/workflows/ci.yml` — Gitea Actions CI pipeline (parallel backend/frontend/infra checks) +- `/.gitea/workflows/cd-bootstrap.yml` — Gitea Actions CD bootstrap workflow (manual multi-arch image publish) +- `/.gitea/workflows/cd-deploy.yml` — Gitea Actions CD deployment workflow (Kubernetes deploy with Kustomize overlay) - PostgreSQL database with RLS policies on all tenant-scoped tables - Keycloak realm configuration with test users and club memberships - Seed data for development @@ -106,6 +109,8 @@ Deliver a working multi-tenant club work management application where authentica - TDD: all backend features have tests BEFORE implementation - Gitea-hosted CI pipeline for this repository (`code.hal9000.damnserver.com/MasterMito/work-club-manager`) - CI jobs run in parallel (backend, frontend, infrastructure validation) +- Gitea-hosted CD bootstrap workflow for private registry image publication (`workclub-api`, `workclub-frontend`) +- Gitea-hosted CD deployment workflow for Kubernetes dev namespace rollout (`workclub-dev`) ### Must NOT Have (Guardrails) - **No CQRS/MediatR** — Direct service injection from controllers/endpoints @@ -124,7 +129,7 @@ Deliver a working multi-tenant club work management application where authentica - **No in-memory database for tests** — Real PostgreSQL via Testcontainers - **No billing, subscriptions, or analytics dashboard** - **No mobile app** -- **No automatic deployment in this CI extension** — CD remains out-of-scope for this append +- **No single-step build-and-deploy coupling** — keep image bootstrap and cluster deployment as separate workflows --- @@ -193,11 +198,11 @@ Wave 5 (After Wave 4 — polish + Docker): ├── Task 24: Frontend Dockerfiles (dev + prod standalone) (depends: 18) [quick] └── Task 25: Kustomize dev overlay + resource limits + health checks (depends: 6, 23, 24) [unspecified-high] -Wave 6 (After Wave 5 — E2E + integration): +Wave 6 (After Wave 5 — E2E + CI/CD integration): ├── Task 26: Playwright E2E tests — auth flow + club switching (depends: 21, 22) [unspecified-high] ├── Task 27: Playwright E2E tests — task management flow (depends: 19, 22) [unspecified-high] ├── Task 28: Playwright E2E tests — shift sign-up flow (depends: 20, 22) [unspecified-high] -└── Task 29: Gitea CI workflow (backend + frontend + infra checks) (depends: 12, 17, 23, 24, 25) [unspecified-high] +└── Task 29: Gitea CI/CD workflows (CI checks + image bootstrap + Kubernetes deploy) (depends: 12, 17, 23, 24, 25) [unspecified-high] Wave FINAL (After ALL tasks — independent review, 4 parallel): ├── Task F1: Plan compliance audit (oracle) @@ -2525,34 +2530,37 @@ Max Concurrent: 6 (Wave 1) - Files: `frontend/tests/e2e/shifts.spec.ts` - Pre-commit: `bunx playwright test tests/e2e/shifts.spec.ts` -- [x] 29. Gitea CI Pipeline — Backend + Frontend + Infra Validation +- [x] 29. Gitea CI/CD Pipelines — CI Validation + Image Bootstrap + Kubernetes Deploy **What to do**: - - Create `.gitea/workflows/ci.yml` for repository `code.hal9000.damnserver.com/MasterMito/work-club-manager` - - Configure triggers: + - Maintain `.gitea/workflows/ci.yml` for repository `code.hal9000.damnserver.com/MasterMito/work-club-manager` + - Maintain `.gitea/workflows/cd-bootstrap.yml` for manual multi-arch image publishing to private registry + - Maintain `.gitea/workflows/cd-deploy.yml` for Kubernetes deployment using Kustomize overlays + - Configure CI triggers: - `push` on `main` and feature branches - `pull_request` targeting `main` - `workflow_dispatch` for manual reruns - - Structure pipeline into parallel jobs (fail-fast disabled so all diagnostics are visible): + - CI workflow structure (parallel validation jobs): - `backend-ci`: setup .NET 10 SDK, restore, build, run backend unit/integration tests - `frontend-ci`: setup Bun, install deps, run lint, type-check, unit tests, production build - `infra-ci`: validate Docker Compose and Kustomize manifests - - Add path filters so docs-only changes skip heavy jobs when possible - - Add dependency caching: - - NuGet cache keyed by `**/*.csproj` + lock/context - - Bun cache keyed by `bun.lockb` - - Add artifact upload on failure: - - `backend-test-results` (trx/log output) - - `frontend-test-results` (vitest output) - - `infra-validation-output` + - CD bootstrap workflow behavior: + - Manual trigger with `image_tag` + build flags + - Buildx multi-arch build (`linux/amd64,linux/arm64`) for `workclub-api` and `workclub-frontend` + - Push image tags to `192.168.241.13:8080` and emit task-31/task-32/task-33 evidence artifacts + - CD deploy workflow behavior: + - Triggered by successful bootstrap (`workflow_run`) or manual dispatch (`image_tag` input) + - Install kubectl + kustomize on runner + - Run `kustomize edit set image` in `infra/k8s/overlays/dev` + - Apply manifests with `kubectl apply -k infra/k8s/overlays/dev` + - Ensure namespace `workclub-dev` exists and perform deployment diagnostics - Enforce branch protection expectation in plan notes: - Required checks: `backend-ci`, `frontend-ci`, `infra-ci` - - Keep CD out-of-scope in this append (no image push, no deploy steps) **Must NOT do**: - - Do NOT add deployment jobs (Kubernetes apply/helm/kustomize deploy) - - Do NOT add secrets for registry push in this CI-only iteration - - Do NOT couple CI workflow to release-tag deployment behavior + - Do NOT collapse bootstrap and deployment into one opaque pipeline stage + - Do NOT bypass image-tag pinning in deployment + - Do NOT remove CI validation gates (`backend-ci`, `frontend-ci`, `infra-ci`) **Recommended Agent Profile**: - **Category**: `unspecified-high` @@ -2568,10 +2576,13 @@ Max Concurrent: 6 (Wave 1) **References**: **Pattern References**: + - `.gitea/workflows/ci.yml` — Source of truth for CI checks + - `.gitea/workflows/cd-bootstrap.yml` — Source of truth for image publish bootstrap + - `.gitea/workflows/cd-deploy.yml` — Source of truth for deployment apply logic - `docker-compose.yml` — Source of truth for `docker compose config` validation - - `infra/k8s/base/kustomization.yaml` and `infra/k8s/overlays/dev/kustomization.yaml` — Kustomize build inputs used by infra-ci job + - `infra/k8s/base/kustomization.yaml` and `infra/k8s/overlays/dev/kustomization.yaml` — Kustomize build/apply inputs - `backend/WorkClub.sln` — Backend restore/build/test entrypoint for .NET job - - `frontend/package.json` + `frontend/bun.lockb` — Frontend scripts and cache key anchor + - `frontend/package.json` + `frontend/bun.lock` — Frontend scripts and cache key anchor **External References**: - Gitea Actions docs: workflow syntax and trigger model (`.gitea/workflows/*.yml`) @@ -2596,6 +2607,18 @@ Max Concurrent: 6 (Wave 1) Failure Indicators: Missing job, skipped required job, or non-success conclusion Evidence: .sisyphus/evidence/task-29-gitea-ci-success.json + Scenario: CD bootstrap and deploy workflows are present and wired + Tool: Bash + Preconditions: Repository contains workflow files + Steps: + 1. Assert `.gitea/workflows/cd-bootstrap.yml` exists + 2. Assert `.gitea/workflows/cd-deploy.yml` exists + 3. Grep bootstrap workflow for buildx multi-arch publish step + 4. Grep deploy workflow for `workflow_run`, `kustomize edit set image`, and `kubectl apply -k` + Expected Result: Both CD workflows exist with expected bootstrap and deploy steps + Failure Indicators: Missing file, missing trigger, or missing deploy commands + Evidence: .sisyphus/evidence/task-29-gitea-cd-workflows.txt + Scenario: Pipeline fails on intentional backend break Tool: Bash (git + Gitea API) Preconditions: Temporary branch available, ability to push test commit @@ -2611,8 +2634,8 @@ Max Concurrent: 6 (Wave 1) ``` **Commit**: YES - - Message: `ci(gitea): add parallel CI workflow for backend, frontend, and infra validation` - - Files: `.gitea/workflows/ci.yml` + - Message: `ci(cd): add CI validation plus bootstrap and Kubernetes deployment workflows` + - Files: `.gitea/workflows/ci.yml`, `.gitea/workflows/cd-bootstrap.yml`, `.gitea/workflows/cd-deploy.yml` - Pre-commit: `docker compose config && kustomize build infra/k8s/overlays/dev > /dev/null` --- @@ -2662,7 +2685,7 @@ Max Concurrent: 6 (Wave 1) | 4 | T18-T21 | `feat(ui): add layout, club-switcher, login, task and shift pages` | frontend/src/app/**/*.tsx, frontend/src/components/**/*.tsx | `bun run build && bun run test` | | 5 | T22-T25 | `infra(deploy): add full Docker Compose stack, Dockerfiles, and Kustomize dev overlay` | docker-compose.yml, **/Dockerfile*, infra/k8s/overlays/dev/**/*.yaml | `docker compose config && kustomize build infra/k8s/overlays/dev` | | 6 | T26-T28 | `test(e2e): add Playwright E2E tests for auth, tasks, and shifts` | frontend/tests/e2e/**/*.spec.ts | `bunx playwright test` | -| 6 | T29 | `ci(gitea): add parallel CI workflow for backend, frontend, and infra validation` | .gitea/workflows/ci.yml | `docker compose config && kustomize build infra/k8s/overlays/dev > /dev/null` | +| 6 | T29 | `ci(cd): add CI validation plus bootstrap and Kubernetes deployment workflows` | .gitea/workflows/ci.yml, .gitea/workflows/cd-bootstrap.yml, .gitea/workflows/cd-deploy.yml | `docker compose config && kustomize build infra/k8s/overlays/dev > /dev/null` | --- @@ -2699,6 +2722,12 @@ kustomize build infra/k8s/overlays/dev > /dev/null # Expected: Exit 0 # CI workflow file present and includes required jobs grep -E "backend-ci|frontend-ci|infra-ci" .gitea/workflows/ci.yml # Expected: all 3 job names present + +# CD bootstrap workflow present with multi-arch publish +grep -E "buildx|linux/amd64,linux/arm64|workclub-api|workclub-frontend" .gitea/workflows/cd-bootstrap.yml + +# CD deploy workflow present with deploy trigger and apply step +grep -E "workflow_run|kustomize edit set image|kubectl apply -k" .gitea/workflows/cd-deploy.yml ``` ### Final Checklist @@ -2710,6 +2739,7 @@ grep -E "backend-ci|frontend-ci|infra-ci" .gitea/workflows/ci.yml # Expected: a - [x] Docker Compose stack starts clean and healthy - [x] Kustomize manifests build without errors - [x] Gitea CI workflow exists and references backend-ci/frontend-ci/infra-ci +- [x] Gitea CD bootstrap and deploy workflows exist and are wired to image publish/deploy steps - [x] RLS isolation proven at database level - [x] Cross-tenant access returns 403 - [x] Task state machine rejects invalid transitions (422) diff --git a/backend/WorkClub.Infrastructure/Seed/SeedDataService.cs b/backend/WorkClub.Infrastructure/Seed/SeedDataService.cs index 26dad9a..7807410 100644 --- a/backend/WorkClub.Infrastructure/Seed/SeedDataService.cs +++ b/backend/WorkClub.Infrastructure/Seed/SeedDataService.cs @@ -62,6 +62,22 @@ public class SeedDataService "); // Create admin bypass policies (idempotent) + await context.Database.ExecuteSqlRawAsync(@" + DO $$ + BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'app_admin') THEN + CREATE ROLE app_admin; + END IF; + END + $$; + GRANT app_admin TO app; + GRANT USAGE ON SCHEMA public TO app_admin; + GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_admin; + GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO app_admin; + ALTER DEFAULT PRIVILEGES FOR ROLE app IN SCHEMA public GRANT ALL ON TABLES TO app_admin; + ALTER DEFAULT PRIVILEGES FOR ROLE app IN SCHEMA public GRANT ALL ON SEQUENCES TO app_admin; + "); + await context.Database.ExecuteSqlRawAsync(@" DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='clubs' AND policyname='bypass_rls_policy') THEN diff --git a/infra/k8s/base/backend-deployment.yaml b/infra/k8s/base/backend-deployment.yaml index 1e70c78..39d8cdb 100644 --- a/infra/k8s/base/backend-deployment.yaml +++ b/infra/k8s/base/backend-deployment.yaml @@ -67,8 +67,13 @@ spec: secretKeyRef: name: workclub-secrets key: database-connection-string - - name: Keycloak__Url + - name: Keycloak__Authority valueFrom: configMapKeyRef: name: workclub-config - key: keycloak-url + key: keycloak-authority + - name: Keycloak__Audience + valueFrom: + configMapKeyRef: + name: workclub-config + key: keycloak-audience diff --git a/infra/k8s/base/configmap.yaml b/infra/k8s/base/configmap.yaml index 93f1537..3454e7d 100644 --- a/infra/k8s/base/configmap.yaml +++ b/infra/k8s/base/configmap.yaml @@ -9,6 +9,8 @@ data: cors-origins: "http://localhost:3000" api-base-url: "http://workclub-api" keycloak-url: "http://workclub-keycloak" + keycloak-authority: "http://workclub-keycloak/realms/workclub" + keycloak-audience: "workclub-api" keycloak-realm: "workclub" # Database configuration @@ -39,3 +41,18 @@ data: \c workclub GRANT ALL PRIVILEGES ON SCHEMA public TO app; ALTER SCHEMA public OWNER TO app; + + -- App admin role for RLS bypass policies used by API startup seed + DO $$ + BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'app_admin') THEN + CREATE ROLE app_admin; + END IF; + END + $$; + GRANT app_admin TO app WITH INHERIT FALSE, SET TRUE; + GRANT USAGE ON SCHEMA public TO app_admin; + GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_admin; + GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO app_admin; + ALTER DEFAULT PRIVILEGES FOR ROLE app IN SCHEMA public GRANT ALL ON TABLES TO app_admin; + ALTER DEFAULT PRIVILEGES FOR ROLE app IN SCHEMA public GRANT ALL ON SEQUENCES TO app_admin; diff --git a/infra/k8s/base/keycloak-deployment.yaml b/infra/k8s/base/keycloak-deployment.yaml index 4e29140..db8b87f 100644 --- a/infra/k8s/base/keycloak-deployment.yaml +++ b/infra/k8s/base/keycloak-deployment.yaml @@ -7,6 +7,9 @@ metadata: component: auth spec: replicas: 1 + strategy: + type: Recreate + progressDeadlineSeconds: 1800 selector: matchLabels: app: workclub-keycloak @@ -21,25 +24,37 @@ spec: image: quay.io/keycloak/keycloak:26.1 imagePullPolicy: IfNotPresent args: - - start + - start-dev + - --import-realm ports: - name: http containerPort: 8080 protocol: TCP + - name: management + containerPort: 9000 + protocol: TCP readinessProbe: httpGet: path: /health/ready - port: http - initialDelaySeconds: 150 + port: management + initialDelaySeconds: 240 periodSeconds: 15 timeoutSeconds: 5 failureThreshold: 10 + startupProbe: + httpGet: + path: /health/ready + port: management + initialDelaySeconds: 60 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 120 livenessProbe: httpGet: path: /health/live - port: http - initialDelaySeconds: 240 + port: management + initialDelaySeconds: 420 periodSeconds: 20 timeoutSeconds: 5 failureThreshold: 5 @@ -84,3 +99,11 @@ spec: value: "true" - name: KC_HEALTH_ENABLED value: "true" + volumeMounts: + - name: keycloak-realm-import + mountPath: /opt/keycloak/data/import + readOnly: true + volumes: + - name: keycloak-realm-import + configMap: + name: keycloak-realm-import diff --git a/infra/k8s/base/keycloak-realm-import-configmap.yaml b/infra/k8s/base/keycloak-realm-import-configmap.yaml new file mode 100644 index 0000000..66df0f4 --- /dev/null +++ b/infra/k8s/base/keycloak-realm-import-configmap.yaml @@ -0,0 +1,246 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: keycloak-realm-import + labels: + app: workclub-keycloak +data: + realm-export.json: | + { + "realm": "workclub", + "enabled": true, + "displayName": "Work Club Manager", + "registrationAllowed": false, + "rememberMe": true, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": true, + "editUsernameAllowed": false, + "bruteForceProtected": true, + "clients": [ + { + "clientId": "workclub-api", + "name": "Work Club API", + "enabled": true, + "protocol": "openid-connect", + "clientAuthenticatorType": "client-secret", + "secret": "dev-secret-workclub-api-change-in-production", + "redirectUris": [], + "webOrigins": [], + "publicClient": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "fullScopeAllowed": true, + "protocolMappers": [ + { + "name": "audience-workclub-api", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "included.client.audience": "workclub-api", + "id.token.claim": "false", + "access.token.claim": "true" + } + }, + { + "name": "clubs-claim", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "clubs", + "claim.name": "clubs", + "jsonType.label": "String", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "clientId": "workclub-app", + "name": "Work Club Frontend", + "enabled": true, + "protocol": "openid-connect", + "publicClient": true, + "redirectUris": [ + "http://localhost:3000/*", + "http://localhost:3001/*", + "http://workclub-frontend/*" + ], + "webOrigins": [ + "http://localhost:3000", + "http://localhost:3001", + "http://workclub-frontend" + ], + "directAccessGrantsEnabled": true, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "fullScopeAllowed": true, + "protocolMappers": [ + { + "name": "audience-workclub-api", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "included.client.audience": "workclub-api", + "id.token.claim": "false", + "access.token.claim": "true" + } + }, + { + "name": "clubs-claim", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "user.attribute": "clubs", + "claim.name": "clubs", + "jsonType.label": "String", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + } + ], + "roles": { + "realm": [ + { + "name": "admin", + "description": "Club admin" + }, + { + "name": "manager", + "description": "Club manager" + }, + { + "name": "member", + "description": "Club member" + }, + { + "name": "viewer", + "description": "Club viewer" + } + ] + }, + "users": [ + { + "username": "admin@test.com", + "enabled": true, + "email": "admin@test.com", + "firstName": "Admin", + "lastName": "User", + "credentials": [ + { + "type": "password", + "value": "testpass123", + "temporary": false + } + ], + "realmRoles": [ + "admin" + ], + "attributes": { + "clubs": [ + "64e05b5e-ef45-81d7-f2e8-3d14bd197383,Admin,3b4afcfa-1352-8fc7-b497-8ab52a0d5fda,Member" + ] + } + }, + { + "username": "manager@test.com", + "enabled": true, + "email": "manager@test.com", + "firstName": "Manager", + "lastName": "User", + "credentials": [ + { + "type": "password", + "value": "testpass123", + "temporary": false + } + ], + "realmRoles": [ + "manager" + ], + "attributes": { + "clubs": [ + "64e05b5e-ef45-81d7-f2e8-3d14bd197383,Manager" + ] + } + }, + { + "username": "member1@test.com", + "enabled": true, + "email": "member1@test.com", + "firstName": "Member", + "lastName": "One", + "credentials": [ + { + "type": "password", + "value": "testpass123", + "temporary": false + } + ], + "realmRoles": [ + "member" + ], + "attributes": { + "clubs": [ + "64e05b5e-ef45-81d7-f2e8-3d14bd197383,Member,3b4afcfa-1352-8fc7-b497-8ab52a0d5fda,Member" + ] + } + }, + { + "username": "member2@test.com", + "enabled": true, + "email": "member2@test.com", + "firstName": "Member", + "lastName": "Two", + "credentials": [ + { + "type": "password", + "value": "testpass123", + "temporary": false + } + ], + "realmRoles": [ + "member" + ], + "attributes": { + "clubs": [ + "64e05b5e-ef45-81d7-f2e8-3d14bd197383,Member" + ] + } + }, + { + "username": "viewer@test.com", + "enabled": true, + "email": "viewer@test.com", + "firstName": "Viewer", + "lastName": "User", + "credentials": [ + { + "type": "password", + "value": "testpass123", + "temporary": false + } + ], + "realmRoles": [ + "viewer" + ], + "attributes": { + "clubs": [ + "64e05b5e-ef45-81d7-f2e8-3d14bd197383,Viewer" + ] + } + } + ] + } diff --git a/infra/k8s/base/kustomization.yaml b/infra/k8s/base/kustomization.yaml index e9fea2c..4d6652b 100644 --- a/infra/k8s/base/kustomization.yaml +++ b/infra/k8s/base/kustomization.yaml @@ -9,6 +9,10 @@ resources: - postgres-statefulset.yaml - postgres-service.yaml - keycloak-deployment.yaml + - keycloak-realm-import-configmap.yaml - keycloak-service.yaml - configmap.yaml - ingress.yaml + +generatorOptions: + disableNameSuffixHash: true diff --git a/infra/k8s/overlays/dev/kustomization.yaml b/infra/k8s/overlays/dev/kustomization.yaml index 0661b92..0272792 100644 --- a/infra/k8s/overlays/dev/kustomization.yaml +++ b/infra/k8s/overlays/dev/kustomization.yaml @@ -11,10 +11,10 @@ commonLabels: environment: development images: - - name: workclub-api + - name: 192.168.241.13:8080/workclub-api newName: 192.168.241.13:8080/workclub-api newTag: dev - - name: workclub-frontend + - name: 192.168.241.13:8080/workclub-frontend newName: 192.168.241.13:8080/workclub-frontend newTag: dev