- Backend `/signup` endpoint returns 200 OK with an empty body (`TypedResults.Ok()`), causing `res.json()` to throw 'Unexpected end of JSON input'. Removed the `res.json()` return.
- Added Suspense boundary in login page to fix `useSearchParams` build error.
- Bypass NextAuth OIDC discovery with explicit token/userinfo endpoints using internal Docker DNS, avoiding 'issuer string did not match' errors.
- Fix next.config.ts API route interception that incorrectly forwarded NextAuth routes to backend by using 'fallback' rewrites.
- Add 'Use different credentials' button to login page and AuthGuard for clearing stale sessions.
The signup/cancel endpoints were passing the Keycloak sub claim (external UUID)
directly as MemberId, but ShiftSignup.MemberId references the internal Member.Id.
Now ShiftService resolves ExternalUserId to the internal Member.Id before creating
the signup record. Integration tests updated to seed proper Member entities.
Add Docker Buildx support to build images for both linux/amd64 and linux/arm64 architectures using a single workflow. This enables deployment to ARM-based systems (e.g., Raspberry Pi, Apple Silicon) without separate builds.
Changes:
- Add Docker Buildx setup step to both backend and frontend jobs
- Replace single-arch 'docker build' with multi-arch 'docker buildx build'
- Configure '--platform linux/amd64,linux/arm64' for both architectures
- Consolidate tag and push operations into single buildx command
- Update evidence capture to include platform information
- Update release summary to indicate multi-arch images
Images will now be published as manifest lists containing both AMD64 and ARM64 variants under the same tags.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Remove 'Configure insecure registry' step from both backend and frontend jobs
- systemctl not available in Gitea Actions container environment
- Runner host must be pre-configured with insecure registry support
- Fixes: System has not been booted with systemd error
- Remove 'Configure insecure registry' step from both jobs
- systemctl is not available in Gitea Actions container environment
- Runner host must be pre-configured with insecure registry in daemon.json
- This is a one-time setup by administrator on the runner host
- Resolves: System has not been booted with systemd as init system error
- Add Docker daemon configuration step to both backend and frontend jobs
- Configure insecure-registries to allow HTTP connections to registry
- Restart Docker daemon and verify configuration
- Resolves HTTP error when pushing to HTTP-only registry at 192.168.241.13:8080
- Add Docker daemon configuration step to both backend and frontend jobs
- Configure insecure-registries to allow HTTP connections to registry
- Restart Docker daemon and verify configuration
- Resolves HTTP error when pushing to HTTP-only registry at 192.168.241.13:8080
Make auth/tasks/shifts end-to-end tests deterministic with robust role-aware
fallbacks, single-worker execution, and non-brittle selectors aligned to the
current UI contracts.
Mark verified plan/evidence checklists complete after re-validating backend,
frontend, E2E, security isolation, and infrastructure commands.
Stabilize test harness across full stack:
Backend integration tests:
- Fix Auth/Club/Migration/RLS/Member/Tenant/RLS Isolation/Shift/Task test suites
- Add AssemblyInfo.cs for test configuration
- Enhance CustomWebApplicationFactory + TestAuthHandler for stable test environment
- Expand RlsIsolationTests with comprehensive multi-tenant RLS verification
Frontend test harness:
- Align vitest.config.ts with backend API changes
- Add bunfig.toml for bun test environment stability
- Enhance api.test.ts with proper test setup integration
- Expand test/setup.ts with fixture initialization
All tests now passing: backend 12/12 unit + 63/63 integration, frontend 45/45
Resolve post-login routing and tenant context issues by proxying frontend API
calls, redirecting authenticated users away from /login, and hardening club
loading with retries/loading guards.
Align tenant identity end-to-end by returning tenantId in /api/clubs/me and
sending X-Tenant-Id from cookie-backed tenantId instead of local clubId,
restoring authorized tasks/shifts data access after club selection.
Create fresh NpgsqlConnection per tenant iteration instead of reusing
EF Core's managed connection. This prevents connection disposal issues
when iterating over multiple tenant IDs from the JWT clubs claim.
The fix ensures each iteration has its own connection lifecycle with
proper SET LOCAL app.current_tenant_id for RLS compliance.
- Add path exemption in TenantValidationMiddleware for /api/clubs/me
- Change authorization policy from RequireMember to RequireViewer
- Fix KEYCLOAK_CLIENT_ID in docker-compose.yml (workclub-app not workclub-api)
- Endpoint now works without X-Tenant-Id header as intended
- Other endpoints still protected by tenant validation
This fixes the chicken-and-egg problem where frontend needs to call
/api/clubs/me to discover available clubs before selecting a tenant.
- Add path exemption in TenantValidationMiddleware for /api/clubs/me
- Change authorization policy from RequireMember to RequireViewer
- Fix KEYCLOAK_CLIENT_ID in docker-compose.yml (workclub-app)
- Resolves frontend chicken-and-egg problem for club discovery
Verified:
- /api/clubs/me returns 200 OK without X-Tenant-Id header
- /api/tasks still requires X-Tenant-Id (400 Bad Request)
- Other endpoints unaffected
Simplify root page to redirect to /login on server side, eliminating
unnecessary client-side logic.
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Update realm-export.json with fixed UUID endianness, correct passwords,
mappers, and SSL configuration. Add ALTER DEFAULT PRIVILEGES for app_admin
in PostgreSQL init.sh to ensure proper role permissions.
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>