Review: Add paldocs Keycloak OIDC client via Terraform (re-review)
Verdict: APPROVED
Re-review of board item #1387. Previous review (
review-1387-2026-07-03) returned NEEDS_REFINEMENT with four recommendations. All four have been addressed. Scope is solid, file targets verified, traceability complete, fits in a single agent pass.Previous Findings -- Resolution Status
- [x]
[SCOPE]"Create architecture note arch-keycloak" -- FIXED.arch-keycloak-paldocscreated (architecture type, active, paldocs project). Comprehensive content: mermaid sequence diagram, component table, key decisions (confidential client rationale, PKCE S256, refresh tokens, CSS-only theme, Terraform-managed). References landscaping-assistant as reference implementation. Platform-levelarch-keycloakalso exists in pal-enterprises. - [x]
[BODY]"Update Constraints: change precedent from pal-enterprises to landscaping-assistant" -- FIXED. Context section now says "The landscaping-assistant client is the closest precedent -- same CONFIDENTIAL type, PKCE S256, realm roles mapper enabled, and critically it includes both Tailscale hostnames AND the public domain." Constraints section says "Follow the existing landscaping-assistant client pattern (dual-origin: Tailscale + public domain)." - [x]
[BODY]"Add pal-e-platform #491 to Related" -- FIXED. Related section now includes both pal-e-platform#490 (DNS A record + Caddy) and pal-e-platform#491 (NetworkPolicy) with dependency descriptions. - [x]
[BODY]"Repo placement advisory" -- Acknowledged (non-blocking). Issue remains on paldocs with### Repofield set toldraney/pal-e-services. The Repo field disambiguates for agents.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Child of paldocs#23 (spike: Keycloak auth + visibility-based access control)
- [x] Repo -- ldraney/pal-e-services
- [x] User Story -- As a platform operator, I want a Keycloak OIDC client provisioned for paldocs
- [x] Context -- References landscaping-assistant dual-origin pattern, pal-e-docs realm, existing roles
- [x] File Targets -- 1 modify target + 2 no-touch targets
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 7 items (expanded from 4 in previous review)
- [x] Test Expectations -- tofu validate + tofu plan -var-file=k3s.tfvars
- [x] Constraints -- 6 constraints including dual-origin pattern
- [x] Checklist -- 3 items
- [x] Related -- 5 items including both platform dependencies
Traceability
- [x] story:auth label -- present on board item #1387
- [x] story note verified --
story-paldocs-authexists in project paldocs, listed on project-paldocs user-stories section ("role-based access control via Keycloak") - [x] arch:keycloak label -- present on board item #1387
- [x] arch note verified --
arch-keycloak-paldocsexists (architecture type, active status, paldocs project). Covers OIDC client, themes, secrets wiring, NetworkPolicy. Alsoarch-keycloakexists in pal-enterprises as platform-level reference. - [x] Forgejo issue -- ldraney/paldocs#26, open
File Targets
- [x]
terraform/k3s.tfvars-- verified: exists (symlink to ~/secrets/pal-e-services/k3s.tfvars).keycloak_clientsmap present. Nopaldocsentry yet.landscaping-assistantprecedent confirmed:public_client=false,standard_flow_enabled=true,direct_access_grants_enabled=false,pkce_code_challenge_method="S256",include_realm_roles_mapper=true,use_refresh_tokens=true, dual-origin URIs (Tailscale + landscaping-assistant.app). - [x]
terraform/keycloak.tf-- verified: exists.keycloak_openid_client.thisat line 148 usesfor_eachonvar.keycloak_clients. Realm roles mapper at line 186. No changes needed -- correct. - [x]
terraform/variables.tf-- verified: exists. Type definition at line 167-196 supports all fields needed:public_client(line 173),standard_flow_enabled(line 174),direct_access_grants_enabled(line 175),pkce_code_challenge_method(line 176),include_realm_roles_mapper(line 185),use_refresh_tokens(line 194). No changes needed -- correct.
Repo Placement
Advisory (non-blocking): issue filed on ldraney/paldocs, work is in ldraney/pal-e-services. The
### Repo field says ldraney/pal-e-services, which disambiguates for agents. Other cross-repo items on the paldocs board (pal-e-platform #490, #491, pal-e-deployments #224) are filed where the work happens, but this convention break is not blocking.Dependencies
- Upstream: pal-e-platform #491 / board #1708 (NetworkPolicy: paldocs to Keycloak) -- on board, sprint:3, backlog. Now documented in Related section.
- Upstream: pal-e-platform #490 / board #1703 (DNS A record + Caddy block for paldocs.app) -- on board, sprint:3, backlog. Now documented in Related. Public domain must resolve before public redirect URIs work, but client creation itself doesn't depend on this.
- Downstream: #1704 (KEYCLOAK_* env vars), #1389 (Rails OIDC integration), #1390 (visibility filtering). All depend on this client existing.
- Realm:
pal-e-docsrealm already exists with admin and user roles. No realm-level changes needed.
Acceptance Criteria
7 criteria, all agent-verifiable. Expanded from 4 in previous review to cover both domains:
- [x] paldocs client exists in pal-e-docs realm -- verifiable via tofu plan output
- [x] Realm roles mapper attached -- verifiable via tofu plan (mapper resource)
- [x] Redirect URIs include both paldocs.tail5b443a.ts.net and paldocs.app -- verifiable via tfvars inspection
- [x] Web origins include both domains -- verifiable via tfvars inspection
- [x] Post-logout redirect URIs include both domains -- verifiable via tfvars inspection
- [x] tofu plan shows only new client + mapper -- verifiable via plan output
- [x] Client secret retrievable -- verifiable post-apply via Keycloak admin console
Blast Radius
Low. The
for_each pattern in keycloak.tf isolates each client as a separate Terraform resource. Adding paldocs to keycloak_clients cannot affect existing clients. The pal-e-docs realm is shared with pal-e-app but no realm-level changes are needed (admin/user roles already defined).Decomposition Assessment
1 file target, 7 AC, estimated agent work under 5 minutes. No decomposition needed.
Recommendations
No action needed.