This repository was archived by the owner on Jul 6, 2026. It is now read-only.
fix(app): batch-2 — SSO roles, remove-member, notifications, idle session, admin seeder (+CI/lint)#85
Merged
Merged
Conversation
…s, idle session, admin seeder + CI/lint Bug fixes: - Standup 403 (GitHub-SSO freelancer): GitHubSsoCommandHandler never assigned the Keycloak realm role (only email/pwd signup did) -> JWT lacked the role. Assign the realm role from the DB role on every SSO login (idempotent). - Remove-member button hidden: lib/api/projects.ts mapped owner from the wrong JSON keys (proj.ownerId/ownerName) instead of freelancerId/freelancerName, so isOwner was always false for everyone (also silently broke the invitations-tab gating). Fixed. - Notification bell badge persisted after click: the bell's useQuery re-hydrated the store with stale isRead=false on refetch. persistRead now optimistically updates the notifications query cache (+ invalidate-on-error) so reads stick. - Idle logout: added a proactive token keep-alive (useTokenRefresh, 4-min interval, visibility-gated; getValidAccessToken(force)) mounted in RealtimeProvider, and raised Keycloak ssoSessionIdleTimeout 1800 -> 3600 in both realm exports. Features: - Admin bootstrap: AdminSeeder (idempotent, config-driven Seed:AdminEmail/AdminPassword) ensures a Keycloak admin user + DB Role=Admin at startup. Seed__AdminEmail set in values.yaml; password supplied via loopless-secrets (not committed). Unblocks the reconcile-roles/backfill-embeddings admin endpoints. (Swagger UI is already live at https://api.project-01.gjirafa.dev/swagger — no change.) Also folded into this batch: - CI: retry the Trivy-job image builds on transient MCR 403 (was stashed). - Web: fix all 17 ESLint warnings (zero-warning lint; honor `_` prefix, memoize, justified disables, lazy-init purity, named default export). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second batch of prod fixes. Root-caused + adversarially verified before implementing (the prior batch's attempts at #1/#2/#3 didn't hold).
Still-broken bugs (root causes were different than first thought)
GitHubSsoCommandHandlercreates the DB user as Freelancer but never assigns the Keycloak realm role (only email/pwd signup did). JWT had nofreelancerrole. The PR#84 case-fix was irrelevant.lib/api/projects.tsreadproj.ownerId/ownerNamebut the backend sendsfreelancerId/freelancerName→project.freelancerId=""→isOwneralways false (also silently broke PR#84's invitations gating)useQueryre-hydrates the store with staleisRead=falseon refetch, overwriting the mark-readsetQueriesDataon the notifications cache + invalidate-on-errorssoSessionIdleTimeout=1800+ no proactive refresh (idle = no requests = token expires = SSO idle elapses)useTokenRefresh, 4-min, visibility-gated) + idle timeout → 3600Features
AdminSeeder(idempotent, config-driven) ensures a Keycloak admin user + DBRole=Adminat startup.Seed__AdminEmailin values.yaml; password vialoopless-secrets(not committed). Unblocks thereconcile-roles/backfill-embeddingsadmin endpoints.https://api.project-01.gjirafa.dev/swagger(no change needed; was hitting the web host).Folded in (per request)
Verified locally
dotnet build✓ · unit tests 22/22 ✓ ·tsc✓ ·next lint0 warnings ✓ ·next build✓Ship steps (after merge — auto-CD doesn't fire, dispatch manually)
kubectl patch secret loopless-secrets -n project-01 -p '{"stringData":{"Seed__AdminPassword":"<pw>"}}'gh workflow run cd.yml --ref main -f image_sha=<merge-sha>(Helm deploy + migrate hook)AdminSeedercreates the admin. Existing SSO freelancer: re-login (role now assigned) — orPOST /api/v1/admin/reconcile-rolesas the new admin for an immediate fix.🤖 Generated with Claude Code