Intelligence Staffing Systems
Notes
Review 66
-
Review: deploy#242 ISS staging: provision CNPG database + re-add migrate init container (re-review)
review-1928-2026-07-26-r2Verdict: READY
Re-review after refinement. Previous review
review-1928-2026-07-26issued NEEDS_REFINEMENT with three[BODY]recommendations. All three have been addressed in the updated issue body.Previous Recommendations -- Resolution
- [x] Clarify CNPG database provisioning mechanism -- ADDRESSED. Context section now documents: "done by adding the database name to the CNPG Cluster CR's managed.databases list in pal-e-services, or by running CREATE DATABASE via psql." Note: the actual mechanism is
databases.tfusing thepostgresql_databaseTerraform resource with theservice_databasesvariable (not CNPG managed.databases), andk3s.tfvars.examplealready has theiss-stagingentry prepared with all 4 databases. The mechanism name is imprecise but the intent (declarative provisioning in pal-e-services) is correct and does not affect the file targets for this ticket. - [x] Add explicit cross-repo sequencing -- ADDRESSED. Issue now states: "The config/database.yml change in ldraney/intelligentstaffingsystems is a hard prerequisite -- without DATABASE_URL support, the init container would still connect to the prod database regardless of env vars set in the overlay. That ISS-repo PR must merge first; then this overlay PR can land."
- [x] Add DATABASE_URL env var to file target descriptions -- ADDRESSED. File targets now explicitly state: deployment-patch.yaml gets DATABASE_URL in both init container and app container; secrets.enc.yaml gets DATABASE_URL pointing to
intelligentstaffingsystems_staging.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Follow-up from PR #241
- [x] Repo -- ldraney/pal-e-deployments
- [x] User Story
- [x] Context -- Includes CNPG provisioning and cross-repo sequencing
- [x] File Targets -- Two pal-e-deployments files + one cross-repo prerequisite
- [x] Feature Flag -- none
- [x] Acceptance Criteria -- 4 items
- [x] Test Expectations -- kubectl kustomize build command
- [x] Constraints -- Including cross-repo merge ordering
- [x] Checklist
- [x] Related -- project-iss, #198, #199, PR #241
Traceability
- [x] story:dev-environment label -- Dev environment pipeline story
- [x] story note verified -- found in project-iss user-stories section (key: dev-environment, backing: #192/#193/#194 + docs/pipeline.md)
- [x] arch:kustomize label -- Kustomize overlays
- [x] arch note verified -- arch-kustomize note exists in pal-e-docs (covers kustomize overlay conventions)
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/pal-e-deployments/issues/242, open
File Targets
- [x]
overlays/intelligentstaffingsystems/staging/deployment-patch.yaml-- verified: file exists, currently has no init container (removed in commit 9869037). Issue correctly specifies re-adding init container with DATABASE_URL and adding DATABASE_URL to app container. - [x]
overlays/intelligentstaffingsystems/staging/secrets.enc.yaml-- verified: file exists, SOPS-encrypted, currently has POSTGRES_USER/PASSWORD/HOST but no DATABASE_URL. Issue correctly specifies adding DATABASE_URL. - [x]
ldraney/intelligentstaffingsystems/config/database.yml(cross-repo prerequisite) -- verified: production section hardcodes database nameintelligentstaffingsystemswith no DATABASE_URL support. Correctly marked as must-merge-first. - [x] Prod overlay correctly marked as do-not-touch. Prod deployment-patch.yaml has a working migrate init container using POSTGRES_USER/PASSWORD/HOST pattern -- staging will use DATABASE_URL instead to override the hardcoded database name.
Repo Placement
Correct. Issue filed on pal-e-deployments for the overlay work. Cross-repo dependency on intelligentstaffingsystems clearly documented with sequencing. CNPG provisioning (pal-e-services) is a separate prerequisite handled via terraform apply, not a code change in this PR.
Dependencies
Well documented. Peer staging tickets on board-iss:
- #1930 platform#560 -- DNS CNAME (backlog)
- #1931 svc#198 -- Caddy reverse proxy (backlog)
- #1932 svc#199 -- Harbor pull secret (backlog)
Issue correctly notes staging needs all peers to be fully functional. Cross-repo prerequisite (ISS database.yml) is now explicitly documented with merge ordering.
Acceptance Criteria
4 AC items, all verifiable by an agent.
kubectl kustomize overlays/intelligentstaffingsystems/stagingis a concrete runnable command. "Prod database is unaffected" is verifiable by confirming prod overlay unchanged and staging DATABASE_URL targets the staging database.Blast Radius
Low. ISS is the only service with a staging overlay. Other services with migrate init containers (palinks, basketball-api, landscaping-assistant) are unaffected. Other overlays (westside-basketball, paldocs) already use DATABASE_URL successfully -- ISS staging follows an established pattern.
Decomposition Assessment
2 file targets in 1 repo, 4 AC. Well within the 5-minute rule. Cross-repo prerequisite is a separate PR, not part of this agent pass. No decomposition needed.
Recommendation
No action needed. All previous recommendations addressed. Minor note: the Context section describes the CNPG provisioning mechanism as "managed.databases" when the actual mechanism is
databases.tfusing thepostgresql_databaseTerraform resource with theservice_databasesvariable. This does not affect the ticket scope or file targets -- the provisioning is a prerequisite handled separately, andk3s.tfvars.examplealready has theiss-stagingentry prepared. - [x] Clarify CNPG database provisioning mechanism -- ADDRESSED. Context section now documents: "done by adding the database name to the CNPG Cluster CR's managed.databases list in pal-e-services, or by running CREATE DATABASE via psql." Note: the actual mechanism is
-
Review: Harbor pull secret for staging image (re-review)
review-1932-2026-07-26-r2Verdict: READY
Re-review after refinement. Both requested fixes confirmed: Test Expectations section added, board label corrected from type:feature to type:task.
Template Completeness
- [x] Type -- Task
- [x] Lineage -- Follow-up from #193, discovered during PR #196 review
- [x] Repo -- ldraney/pal-e-services
- [ ] User Story -- Omitted; acceptable for foundational infra task
- [x] Context -- Clear explanation of cross-project pull access gap
- [x] Scope -- Replaces File Targets correctly for Task type
- [x] Acceptance Criteria -- 3 items, all verifiable
- [x] Test Expectations -- Added in refinement; 3 concrete checks
- [x] Constraints -- Generic solution requirement stated
- [x] Checklist -- Standard items
- [x] Related -- References #193 parent and arch-argocd
Traceability
- [x] story:dev-environment label -- verified in project-iss user-stories section
- [x] story note verified -- "dev-environment" row exists: "Dev to staging to prod pipeline"
- [x] arch:infra label -- infrastructure category
- [x] arch note verified -- arch-infra note exists in pal-e-docs
- [x] Forgejo issue -- svc#199, open
File Targets
N/A -- Task type uses Scope section. Verified the scope is accurate:
services.tflines 98-118 create pull robots scoped per-project viaharbor_project.service[each.key].name. The staging service entry ink3s.tfvars(line 387-394) sharesimage_repo = "intelligentstaffingsystems/app"with prod but gets its own Harbor projectintelligentstaffingsystems-staging, confirming the cross-project pull gap.Repo Placement
Correct. The Harbor robot and pull secret logic lives in
pal-e-services/terraform/services.tf. The Forgejo issue is filed onldraney/pal-e-services. Single repo fix.Dependencies
- #193 (staging environment) -- done, parent of this issue
- Sibling staging tickets on board: svc#198 (Caddy), platform#560 (DNS), deploy#242 (CNPG database) -- parallel, not blocking
- No upstream blockers identified
Acceptance Criteria
3 criteria, all agent-verifiable:
- "Staging pods can pull images" -- verifiable via kubectl
- "Terraform manages access" -- verifiable via terraform plan output
- "Must not weaken prod access controls" -- verifiable by reviewing terraform diff for read-only scope
Test Expectations align with AC: terraform plan check, kubectl pod status check, no manual steps required.
Blast Radius
Low. ISS is currently the only service with a staging variant (
image_updaterdefaults totrueinvariables.tf). The constraint requiring a generic solution ensures future staging services benefit. No other services currently share images across Harbor projects.Decomposition Assessment
No decomposition needed. Single repo (pal-e-services), likely 1-2 terraform files, 3 acceptance criteria, estimated under 5 minutes of agent work.
Recommendation
No action needed.
-
Review: svc#198 Caddy reverse proxy for staging.intelligentstaffingsystems.ai (re-review)
review-1931-2026-07-26-v2Verdict: READY
Re-review after refinement. Issue body updated with User Story, Test Expectations, and blast-radius AC. Board label corrected from type:feature to type:task.
Template Completeness
- [x] Type — Task
- [x] Lineage — Follow-up from #193, discovered during PR #196 review
- [x] Repo — ldraney/pal-e-services
- [x] User Story — present (added in refinement)
- [x] Context — explains DNS CNAME exists but Caddy entry missing
- [x] Scope — add Caddy reverse proxy block following existing pattern
- [x] Acceptance Criteria — 3 items, all concrete
- [x] Test Expectations — present (added in refinement), curl commands specified
- [x] Constraints — SaltStack-managed, must not disrupt existing routing
- [x] Checklist — present
- [x] Related — #193, arch-argocd
Traceability
- [x] story:dev-environment label — Dev to staging to prod pipeline
- [x] story note verified — found in project-iss user-stories section (references #192/#193/#194)
- [x] arch:infra label — Hetzner Edge, DNS, Traffic Routing
- [x] arch note verified — arch-infra note exists, covers exactly the Caddy/edge proxy pattern
- [x] Forgejo issue — ldraney/pal-e-services#198, open
File Targets
N/A — Task type uses Scope instead of File Targets. Scope describes adding a Caddy reverse proxy block on the edge VPS, following the existing pattern for intelligentstaffingsystems.ai and dev.intelligentstaffingsystems.ai.
Repo Placement
OK. Issue filed on pal-e-services (infrastructure services repo). Actual work is a Caddy config change on the Hetzner edge VPS managed by SaltStack. The issue acknowledges this constraint. No additional repos needed.
Dependencies
- DNS CNAME — already added in PR #196 (prerequisite satisfied)
- svc#193 (parent, staging environment) — done
- svc#199 (Harbor pull secret for staging) — sibling in backlog, not a blocker for this task
- deploy#242 (ISS staging CNPG database) — sibling in backlog, not a blocker
- platform#560 (DNS CNAME) — in backlog on board but PR #196 already merged the work; board item may need updating
Acceptance Criteria
All 3 criteria are concrete and agent-verifiable via curl. Test Expectations section provides the exact commands. Includes blast-radius check for existing ISS domains.
Blast Radius
Low risk. The change is additive (new Caddy config block). The issue includes AC to verify existing ISS domains still respond. Per arch-infra, other domains also route through the same edge proxy (palinks.app, landscaping-assistant.app, westsidekingsandqueens.com). A syntax error in the Caddy config could theoretically affect all domains, but the additive nature and SaltStack management mitigate this. The operator should verify Caddy reloads cleanly after the change.
Decomposition Assessment
No decomposition needed. Single additive infra operation, 0 codebase file targets, 3 AC, well under the 5-minute rule.
Recommendation
No action needed.
-
Review: deploy#242 ISS staging: provision CNPG database + re-add migrate init container
review-1928-2026-07-26Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:dev-environment label -- Dev environment pipeline story
- [x] story note verified -- found in project-iss user-stories section (key: dev-environment, backing: #192/#193/#194 + docs/pipeline.md)
- [x] arch:kustomize label -- Kustomize overlays
- [x] arch note verified -- arch-kustomize note exists in pal-e-docs (covers kalshi-assistant pattern; same overlay conventions apply to ISS)
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/pal-e-deployments/issues/242, open
File Targets
- [x]
overlays/intelligentstaffingsystems/staging/deployment-patch.yaml-- verified: file exists, currently has no init container (consistent with ticket context about removal in commit 9869037) - [x]
overlays/intelligentstaffingsystems/staging/secrets.enc.yaml-- verified: file exists, SOPS-encrypted, currently has POSTGRES_USER/PASSWORD/HOST but no DATABASE_URL or DATABASE_NAME key - [x]
ldraney/intelligentstaffingsystems/config/database.yml(cross-repo) -- verified: production section hardcodes database nameintelligentstaffingsystemswith no DATABASE_URL or DATABASE_NAME env var support. This confirms the core problem the ticket describes. - [ ] CNPG database provisioning resource -- ISSUE: title says "provision CNPG database" but no file target covers the provisioning mechanism. No CNPG custom resources exist anywhere in pal-e-deployments. If Rails
db:preparehandles creation, this should be stated. If a manual step or separate resource is needed, add the target.
Repo Placement
Issue filed on
ldraney/pal-e-deployments-- correct for the kustomize overlay work. Cross-repo dependency onldraney/intelligentstaffingsystems/config/database.ymlis identified under File Targets. However, the work requires PRs to two repos. The sequencing is critical: the database.yml change in ISS must land BEFORE the staging init container can safely run, otherwise it would still target the prod database. This sequencing is not documented in the issue body.Dependencies
Peer tickets with sprint:staging label on board-iss:
- #1930 platform#560 -- DNS CNAME for staging.intelligentstaffingsystems.ai (backlog)
- #1931 svc#198 -- Caddy reverse proxy for staging (backlog)
- #1932 svc#199 -- Harbor pull secret for staging image (backlog)
The issue correctly notes staging needs all three peers to be fully functional. These are co-dependencies, not blockers. The implicit prerequisite (database.yml must change first) is not documented.
Acceptance Criteria
4 AC, all testable by an agent.
kubectl kustomizebuild check is a concrete runnable command. "Prod database is unaffected" is verifiable but requires the agent to confirm the staging init container's DATABASE_URL points to the staging database. The missing piece: no AC verifies that the ISS Rails app actually reads DATABASE_URL/DATABASE_NAME (the cross-repo change).Blast Radius
Low. ISS is the only service with a staging overlay in pal-e-deployments. Other services with migrate init containers (palinks, basketball-api, landscaping-assistant) use their own database configs and are unaffected. The database.yml change in ISS would only affect staging behavior (prod section currently uses hardcoded names and would continue to do so unless DATABASE_URL is set).
Decomposition Assessment
3 file targets across 2 repos, 4 AC. At the boundary but within limits. The cross-repo nature adds coordination complexity but does not require decomposition -- a single agent can handle both PRs if sequencing is documented. No decomposition needed.
Recommendation
[BODY]Clarify CNPG database provisioning mechanism: state whetherdb:preparecreates the database (requires CREATE DATABASE privilege on the CNPG user) or whether a manual step / CNPG Database resource is needed. If a manual prerequisite, add it to Constraints.[BODY]Add explicit cross-repo sequencing: "Step 1: PR to ldraney/intelligentstaffingsystems adding DATABASE_URL support to config/database.yml. Step 2: PR to ldraney/pal-e-deployments re-adding init container with DATABASE_URL env var in staging overlay." The ISS change is a hard prerequisite.[BODY]Add DATABASE_URL (or DATABASE_NAME) env var to the staging deployment-patch.yaml file target description -- both the init container and app container need this new env var to point at the staging database instead of the hardcoded prod name.
-
Review: svc#199 Harbor pull secret for staging image
review-1932-2026-07-26Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- present (Task)
- [x] Lineage -- present (follow-up from #193)
- [x] Repo -- present (ldraney/pal-e-services)
- [ ] User Story -- missing (foundational infra work, acceptable for Task type)
- [x] Context -- present, well-explained
- [x] Scope -- present (replaces File Targets for Task type)
- [x] Acceptance Criteria -- present (3 criteria)
- [ ] Test Expectations -- MISSING
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:dev-environment label -- present on board item
- [x] story note verified -- found in project-iss user-stories section (backing: #192 / #193 / #194 + docs/pipeline.md)
- [x] arch:infra label -- present on board item
- [x] arch note verified -- arch-infra note exists in pal-e-docs (covers infrastructure patterns; note is paldocs-scoped but the arch label is valid)
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/pal-e-services/issues/199, open
File Targets
Task type -- no file targets required. Scope section describes the work (grant staging pull robot cross-project access in terraform).
Repo Placement
OK. Issue filed on ldraney/pal-e-services, which is where the terraform service definitions and Harbor robot configuration live. No repo mismatch.
Dependencies
- Parent: svc#193 (staging environment) -- done on board (#1893)
- Sibling staging tickets in backlog: svc#198 Caddy reverse proxy (#1931), platform#560 DNS CNAME (#1930), deploy#242 CNPG database (#1928)
- This ticket is a prerequisite for staging pods to pull images -- it unblocks staging deployment functionality
- Dependencies are partially documented in the Related section (#193 parent, arch-argocd) but sibling staging tickets are not cross-referenced
Acceptance Criteria
3 criteria, all verifiable:
- "Staging pods can pull intelligentstaffingsystems/app images" -- verifiable via kubectl on staging namespace
- "No manual Harbor configuration -- terraform manages the access" -- verifiable by inspecting terraform plan output
- "Must not weaken prod Harbor project access controls" -- verifiable by reviewing terraform diff and Harbor project member list
AC are clear and testable. Count is under the 5-threshold.
Blast Radius
The ISS repo's .woodpecker.yaml pushes images to harbor.tail5b443a.ts.net. The issue correctly identifies that the solution should be generic (any service sharing images across staging/prod). Other services with staging variants would benefit from the same cross-project pull pattern. No immediate sibling services in the ISS repo are affected -- the blast radius is contained within pal-e-services terraform.
Decomposition Assessment
No decomposition needed. Single repo (pal-e-services), 3 AC, estimated agent work under 5 minutes (terraform configuration change for Harbor robot permissions).
Recommendation
- [LABEL] Fix type label mismatch: board item has
type:featurebut issue body says### Type: Task. Change board label totype:task. - [BODY] Add
### Test Expectationssection. Suggested content:terraform planshows robot member added to prod Harbor project;kubectl get pods -n intelligentstaffingsystems-stagingshows no ImagePullBackOff; no manual Harbor console steps required.
-
Review: deploy#240 Re-land stranded ISS dev port fix + staging overlay onto main
review-1925-2026-07-26Verdict: READY
Board item: 1925 (board-iss) —
type:feature,arch:kustomize,story:project-setup,scope:unplanned, 2 pts
Forgejo issue: ldraney/pal-e-deployments#240 (open)
Issue type: Feature → validated againsttemplate-issue-feature
Reviewed: 2026-07-26Every substantive claim in this ticket was independently reproduced, including a full test cherry-pick onto current
origin/main. The scope is accurate, the root-cause diagnosis is correct, and the work is atomic. Three cosmetic[BODY]nits are listed below; none of them would cause an implementing agent to do the wrong thing.Template Completeness
All 12 sections of
template-issue-featurepresent. No gaps.- [x]
### Type— Feature - [x]
### Lineage— standalone, discovered validatingpal-e-services#192/#193 - [x]
### Repo—ldraney/pal-e-deployments - [x]
### User Story— As/I want/So that, complete - [x]
### Context— root cause stated inline, not referenced - [x]
### File Targets— both "modify or create" and "should NOT touch" lists - [x]
### Feature Flag— "none" with justification (infra overlay, no user-visible workflow) - [x]
### Acceptance Criteria— 7 criteria - [x]
### Test Expectations— 3 expectations + run command - [x]
### Constraints— worktree-workflow, no-rebase, out-of-scope list - [x]
### Checklist— standard 3 - [x]
### Related— project + deliberately excluded follow-ups
Traceability
- [x]
story:project-setuplabel — present - [x] story note verified —
project-setuprow found inproject-issuser-stories table (backing: README + docs/architecture.md + docs/adoption-plan.md) - [x]
arch:kustomizelabel — present - [x] arch note verified —
arch-kustomizeexists in pal-e-docs (id 2341) - [x] Forgejo issue —
pal-e-deployments#240, open, valid
Observation (non-blocking):
arch-kustomizeis scoped to theprediction-assistantproject and documents the kalshi-assistant prod/dev overlay pattern, not ISS. It is the generic pattern note ISS follows, and prior ISS board item 1784 (#5 Deployment overlay in pal-e-deployments) used the identical label, so the precedent is consistent. The skill's existence check passes.File Targets
All five verified by test cherry-pick of
effec9e+3cd11e1ontoorigin/main(458b6fd) in a throwaway clone. Result: CLEAN, zero conflicts, exactly 5 files — matching the File Targets list byte for byte.- [x]
overlays/intelligentstaffingsystems/dev/deployment.yaml— exists on main;UPSTREAMcurrently"100.110.151.59:9999", cherry-pick changes it to:8888as claimed - [x]
overlays/intelligentstaffingsystems/dev/README.md— exists on main; two9999refs (Upstream bullet + mermaid node) fixed by the cherry-pick. Stale purpose statement confirmed verbatim: "enabling mobile testing without Tailscale on the device" — the cherry-pick does not touch this sentence, so AC #5 correctly identifies extra work beyond the replay - [x]
overlays/intelligentstaffingsystems/staging/kustomization.yaml— new (65 lines);namespace: intelligentstaffingsystems-staging; mirrors prod (same../../../bases/standardref, same rename-patch structure) - [x]
overlays/intelligentstaffingsystems/staging/deployment-patch.yaml— new (132 lines) - [x]
overlays/intelligentstaffingsystems/staging/secrets.enc.yaml— new (32 lines); genuinely SOPS/age-encrypted,lastmodified 2026-07-21, same age recipient as prod - [x] DO NOT TOUCH
overlays/intelligentstaffingsystems/prod/kustomization.yaml— instruction to drop241567cis correct. Main's copy carries no cache-bust line (c566ec6removed the earlier one), and241567cadds only# cache-bust 1784333337, which collides with the image-updater'snewTag:bump. Confirmed this is the sole conflict source - [x]
bases/standard/— exists on main (6 files); the staging overlay's relative ref resolves
Root-cause claims — all confirmed
- [x]
effec9eis not an ancestor oforigin/main(git merge-base --is-ancestor→ false) - [x]
3cd11e1is not an ancestor oforigin/main - [x] PR
#239reportsmerged: truewithbase.ref = palinks-dev-overlayandmerge_commit_sha = effec9e436d0b...— the wrong-base merge is real - [x]
intelligentstaffingsystems#99is closed — auto-closed by that stranded PR, as described - [x]
pal-e-services#193closed with only its own slice landed; no pal-e-deployments PR was ever opened for the overlay - [x] Commit
3cd11e1sits on193-iss-staging-environment, stacked oneffec9eand241567c— branch topology matches the description exactly
Urgency claim — confirmed
k3s.tfvarsregistersintelligentstaffingsystems-stagingwithsource_path = "overlays/intelligentstaffingsystems/staging"andcmp_plugin = kustomize-sops. That path does not exist on main. The nexttofu applywould create an ArgoCD app pointing at a missing path. The ticket's framing of this as a must-land-before-apply blocker is accurate.Repo Placement
OK. All five file targets live in
ldraney/pal-e-deploymentsand the issue is filed on that repo. Single-repo change — no split or companion issue needed. The multi-repo follow-ups (pal-e-platform DNS, pal-e-services Caddy and Harbor) are correctly carved out into the Related section rather than absorbed here.Dependencies
Nothing blocks this ticket; this ticket blocks the next
tofu apply.pal-e-services#193(board 1893,validation) — this ticket is its missing pal-e-deployments slice. Documented in Lineage.pal-e-services#192(board 1892,validation) — dev-environment registration, closed. Documented.intelligentstaffingsystems#99(board 1887,done) — the issue the stranded PR auto-closed. Documented.pal-e-services#198(Caddy staging vhost) and#199(Harbor cross-project pull) — both verified open, correctly listed as deliberately excluded follow-ups.- Open PRs on pal-e-deployments (7 total) — none other than
#241touches any ISS overlay. No collision risk. - Board hygiene drift (unrelated to this ticket): board item 1904 sits in
in_progress, but its issuepal-e-services#200is closed and the ISS repo already merged the promote-to-prod pipeline step (PR #109). Worth a board sweep, does not gate this work.
Acceptance Criteria
Seven criteria, all machine-verifiable, each mapping to a concrete command. This is unusually strong — AC #6 even names the exact API endpoint and JSON field (
GET /pulls/{n}→.base.ref == "main"), which is precisely the defect being fixed being turned into its own gate. AC #3 (git diff --name-onlylists exactly 5 files) is a tight regression net that catches an accidental241567creplay.AC #1 pins the base as
e6423a3or later;origin/mainhas since advanced to458b6fd. The "or later" wording absorbs this correctly.AC #5 is the only criterion requiring prose judgment rather than a command, and it is the one place an agent could stall — see the first
[BODY]recommendation, which supplies the missing evidence chain. No missing criteria identified.Blast Radius
- Swept every
source_pathink3s.tfvarsagainst pal-e-deployments main.overlays/intelligentstaffingsystems/stagingis the only path targeting pal-e-deployments that is missing. Two other apparent misses (k8s,k8s/overlays/prod) resolve to different source repos (ldraney/pal-e-apiand kalshi-assistant) and are false positives. The exposure is contained to this one service. - Swept ~150 closed PRs on pal-e-deployments for merged PRs with
base != main.#239is the only occurrence. The stranded-merge defect class is isolated — there is no second re-land hiding elsewhere in this repo. - Latent inconsistency, out of scope, worth its own ticket:
k3s.tfvarsstill registers the ISS Keycloak client withhttp://localhost:9999/auth/keycloak/callbackand web originhttp://localhost:9999, while the repo has moved local dev to 8888 (CLAUDE.md, anddocs/architecture.md:154listshttp://localhost:8888/*). Landing this ticket does not break anything — the overlay'sUPSTREAMis a cluster-side proxy target, entirely separate from browser redirect URIs — but the tfvars/docs disagreement is real and belongs in a pal-e-services ticket. - Prod overlay is untouched by the cherry-pick set; the running prod ArgoCD app is unaffected.
Decomposition Assessment
No decomposition needed.
- File targets: 5 files across 1 repo — under the ">3 files across >2 repos" threshold.
- Acceptance criteria: 7, which literally exceeds the >5 heuristic. It should not trigger a split here: 5 of the 7 are verification gates on a single atomic change (branch base, cherry-pick set, diff file list, PR base ref, PR body wording), not separate units of work. Only two AC (#4 port value, #5 README purpose) describe content changes. The two cherry-picks are stacked and must land in one commit set — splitting them would recreate the exact stranded-branch failure this ticket exists to fix.
- Standing directive:
feedback_no_decomposition— write inclusive tickets, review them whole. - Estimated agent work: clone,
checkout -B main origin/main, two cherry-picks, one README paragraph edit, two kustomize builds, push, open PR. Well under 5 minutes. 2 points is right-sized.
Recommendation
Verdict is READY. The three items below are polish that would make an already-strong ticket easier to execute; none blocks implementation.
[BODY]Add the evidence chain for AC #5. AC #5 asserts the dev overlay's purpose is "making the local Docker dev server reachable on the public URLdev.intelligentstaffingsystems.ai" — but nothing inside the overlay mentions that domain. Its ingress is a Tailscale Funnel ingress servingiss-dev(→iss-dev.tail5b443a.ts.net), so an agent reading only the overlay could reasonably conclude the AC is wrong and skip it. I verified the AC is correct, and the proof lives outside the repo:/home/ldraney/pal-e-platform/salt/pillar/caddy.slslines 37-40 define vhostiss-dev: domain dev.intelligentstaffingsystems.ai → proxy_target iss-dev.tail5b443a.ts.net, andterraform/dns.tfline 64 (iss_dev) points the CNAME at the Hetzner edge. Chain:dev.intelligentstaffingsystems.ai→ GoDaddy CNAME → Hetzner edge → Caddy → Tailscale Funnel → this overlay's nginx → local Docker dev server on:8888. Citing that in the issue lets the agent write an accurate README instead of guessing. (Corroborated byintelligentstaffingsystems/docs/local-dev-setup.md:121,141.)[BODY]Fix the divergence count in Context. The ticket says "mainis 17 commits ahead of the branch, and all 17 are bot image-bump commits." It is now 19, and 3 are not bot bumps:c566ec6(docs: add ISS overlay to repo inventory, #238),7458cbe(fix: replace ISS placeholder secrets with real production values, #236),19d8a02(chore: force ArgoCD re-render for ISS SOPS plugin). I re-verified the load-bearing part —prod/kustomization.yamlis still the only overlapping file, and the cherry-pick is still clean — so the conclusion holds. Because the image-updater bot pushes continuously, suggest dropping the fixed count entirely: "mainhas advanced past the branch; the only overlapping file isprod/kustomization.yaml."[BODY]Fix the test run command.kustomizeis not installed on this host (which kustomize→ not found;kubectlandsopsare present), so the stated run command fails withcommand not found. Usekubectl kustomize overlays/intelligentstaffingsystems/dev && kubectl kustomize overlays/intelligentstaffingsystems/staging. I ran both against the cherry-picked tree: both exit 0, and staging rendersnamespace: intelligentstaffingsystems-stagingacross 4 resources, satisfying test expectation #3. Note the SOPS caveat in the ticket is moot for this path —kubectl kustomizepasses the encrypted Secret through as an opaque resource without attempting decryption, so the build is genuinely clean and the PR body can say so honestly.[LABEL]Optional: considerstory:dev-environmentover (or alongside)story:project-setup. Thedev-environmentrow in theproject-issuser-stories table reads "#192 / #193 / #194 + docs/pipeline.md — Dev → staging → prod pipeline", which is exactly this work, and every sibling item (1892, 1893, 1904) carries that key. Both keys are valid table entries, so this is precision, not correctness.
Verification Method
Findings were produced against a throwaway clone at
scratchpad/pedcut fresh from the Forgejo origin — not the shared~/pal-e-deploymentscheckout, which was inspected read-only and left untouched. No branches were created, rebased, force-pushed, or deleted on the remote; the test cherry-pick lived only in the local throwaway clone.Incidental note: the ticket states the shared clone is checked out on
palinks-dev-overlay. As of this review it is onmainat the stale2bf7b6bwith a stale cachedorigin/main(458b6fdupstream). The stale-local-mainhazard the Constraints section warns about is therefore still live, and thegit fetch origin && git checkout -B main origin/maininstruction remains necessary.Related
skill-review-ticket— workflow followedtemplate-issue-feature— template validated againstproject-iss— user-stories backing forstory:project-setuparch-kustomize— arch note backingarch:kustomize
- [x]
-
Review: Google Play Store submission (round 3)
review-1885-2026-07-25-r3Verdict: READY
Round 3 re-review of board item #1885. Previous reviews:
review-1885-2026-07-25(NEEDS_REFINEMENT, 5 findings),review-1885-2026-07-25-r2(NEEDS_REFINEMENT, 2 remaining findings). Both r2 findings resolved.Previous Findings Status (r2)
- [x] Finding 1 (cross-repo AC contradiction) -- RESOLVED. Privacy policy page removed from Agent work AC. Now appears only in Prerequisites as a blocker. Agent work AC reduced to 2 items (signing config, Fastlane scaffold).
- [x] Finding 2 (arch label wrong project) -- RESOLVED. Board label changed from
arch:apptoarch:frontend. Thearch-frontendnote in pal-e-docs belongs to Prediction Assistant, butarch:frontendis an established convention on the ISS board (7+ items use it: landing-page, navigation, UI/UX tickets -- all in done). This is a systemic project-level gap (ISS has no project-specific arch notes), not a ticket-specific scope issue.
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] Prerequisites (bonus section, documents blockers)
- [x] File Targets
- [x] Feature Flag (none -- acceptable, store submission config)
- [x] Acceptance Criteria (split into Agent work + Manual steps)
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:android-app label -- present on board item
- [x] story note verified --
android-appfound in project-iss user-stories table. Backing doc:docs/ios.md (same Turbo Native model). Success metric: "Play Store app loads the Rails app; same update model as iOS" - [x] arch:frontend label -- present on board item
- [x] arch note exists --
arch-frontendnote exists in pal-e-docs. Note: belongs to Prediction Assistant project, butarch:frontendis an established ISS board convention (7+ items). Systemic gap, not ticket-specific. - [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/iss-android/issues/1, open
File Targets
- [x]
app/build.gradle.kts-- verified: file exists in iss-android repo. Has release buildType with proguard config (lines 18-23) but no signing config. Ticket correctly identifies signing config needs to be added. - [x]
fastlane/Fastfile-- emptyfastlane/directory exists. No Fastfile yet. Ticket marks this as conditional ("if using Fastlane"). Acceptable. - [x] Store assets directory -- does not exist yet (expected for new creation).
Repo Placement
OK. Issue filed on
ldraney/iss-android, board item onboard-iss. The Android app is part of the ISS ecosystem. Agent work is scoped entirely to the iss-android repo. Cross-repo privacy page dependency properly scoped as a Prerequisite (blocker), not as agent AC -- resolving the contradiction flagged in r2.Dependencies
- Privacy policy page -- documented in Prerequisites as a blocker. No
/privacyroute, controller, or view exists in ISS Rails app. Properly identified as work that must complete before Play Store submission. Not part of agent AC. - Store assets -- documented in Prerequisites as manual work.
- iOS app (#1798) -- Done. No blocking dependency.
- Landing page rewrite (#1883/#95) -- In backlog, sprint:E. Not a direct dependency.
- No items on board-iss currently block this ticket.
Acceptance Criteria
10 total AC (2 agent, 8 manual). Clean agent/manual split. Agent work is tightly scoped: signing config + optional Fastlane scaffold. All criteria are verifiable. Manual steps cover Play Store console operations that an agent cannot perform.
Blast Radius
Self-contained to iss-android repo for code changes. Privacy policy page is a documented prerequisite in a separate repo (ISS Rails app). No downstream consumers affected. No similar patterns in sibling services need updating.
Decomposition Assessment
2 agent AC items (well under 5-AC threshold). File targets in 1 repo (iss-android). Estimated agent work: <5 minutes. No decomposition needed.
Observation (non-blocking)
The issue body contains a stale note referencing
arch-appmismatch, but the board label is nowarch:frontend. This is cosmetic and does not affect agent execution or scope correctness.Recommendation
No action needed. Ticket is ready for implementation.
-
Review: Google Play Store submission (re-review)
review-1885-2026-07-25-r2Verdict: NEEDS_REFINEMENT
Re-review of board item #1885. Previous review (
review-1885-2026-07-25) returned NEEDS_REFINEMENT with 5 findings. 4 of 5 resolved. 2 findings remain (1 carried forward, 1 new).Previous Findings Status
- [x] Finding 1 (story note missing) -- RESOLVED.
android-approw added to project-iss user-stories table: "Play Store app loads the Rails app; same update model as iOS" - [ ] Finding 2 (arch note wrong project) -- ACKNOWLEDGED, NOT FIXED. Issue body notes the mismatch but defers the decision.
arch-appstill belongs to Prediction Assistant. Board item still carriesarch:applabel. - [x] Finding 3 (privacy policy blocker) -- RESOLVED. Prerequisites section now documents the privacy page blocker with checkbox.
- [x] Finding 4 (agent vs manual split) -- RESOLVED. AC split into "Agent work" (3 items) and "Manual steps" (8 items).
- [x] Finding 5 (store asset production) -- RESOLVED. Documented as prerequisite and in manual steps AC.
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] Prerequisites (bonus section, not in template)
- [x] File Targets
- [x] Feature Flag (none -- acceptable, store submission config)
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:android-app label -- present on board item
- [x] story note verified --
android-appfound in project-iss user-stories section with backing doc referencedocs/ios.md (same Turbo Native model) - [x] arch:app label -- present on board item
- [ ] arch note WRONG PROJECT -- [SCOPE]
arch-appnote exists but belongs to Prediction Assistant (Kalshi), not ISS. Issue body acknowledges this ("If the review process requires an ISS-scoped architecture note, a separate one will need to be created") but no fix applied. Either createarch-iss-androidorarch-androidin pal-e-docs, or re-label the board item with a valid ISS arch tag. - [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/iss-android/issues/1, open
File Targets
- [x]
app/build.gradle.kts-- verified: file exists in iss-android repo. Has release buildType with minify/proguard but no signing config. Ticket correctly identifies signing config needs to be added. - [x]
fastlane/Fastfile-- emptyfastlane/directory exists (scaffolded). No Fastfile yet. Ticket marks this as conditional ("if using Fastlane"). Acceptable. - [x] Store assets directory -- does not exist yet (expected for new creation).
Repo Placement
Issue filed on
ldraney/iss-android, board item onboard-iss. The Android app is part of the ISS ecosystem.Cross-repo concern: Agent work AC #3 says "Privacy policy page route (
/privacy) added to ISS Rails app (inldraney/intelligentstaffingsystems)." This requires changes to a different repo than where the issue is filed. Verified: no/privacyroute, controller, or view exists in the ISS Rails app currently. This work is also listed as a Prerequisite (blocker), creating a contradiction -- it cannot be both a prerequisite (done before) and an AC item (done during).Dependencies
- Privacy policy page -- documented in Prerequisites. No route/view/controller exists in ISS Rails app. Properly identified as a blocker, but contradicted by also appearing as an Agent work AC item.
- Store assets -- documented in Prerequisites as manual work.
- iOS app (#1798) -- Done. No blocking dependency.
- Landing page rewrite (#1883/#95) -- In backlog, sprint:E. Not a direct dependency.
- No items on board-iss currently block this ticket.
Acceptance Criteria
11 total AC (3 agent, 8 manual). The agent/manual split is now clear and well-structured. Agent work is focused: signing config, optional Fastlane, and privacy page. Manual steps cover all Play Store console operations.
The 3 agent AC items are reasonable for a single agent pass. However, AC #3 (privacy page) targets a different repo -- see Repo Placement concern.
Blast Radius
Self-contained to iss-android repo for build/signing changes. Privacy policy page touches ISS Rails app but is a separate, isolated page addition. No downstream consumers affected. No similar patterns in sibling services.
Decomposition Assessment
3 agent AC items (under 5-AC threshold). File targets span 2 repos (iss-android + intelligentstaffingsystems) but the cross-repo work is a single static page. Estimated agent work: <5 minutes total. No decomposition needed for agent scope, but the cross-repo privacy page AC should be resolved (separate ticket or remove from prerequisites).
Recommendation
[SCOPE]Thearch-appnote belongs to Prediction Assistant, not ISS. Create an ISS-scoped architecture note (e.g.,arch-iss-androidorarch-android) in pal-e-docs, or re-label the board item with a valid ISS arch tag. This was flagged in the first review and acknowledged but not resolved.[BODY]The privacy policy page appears as both a Prerequisite (blocker) and an Agent work AC item. Pick one: (a) keep it as a prerequisite only and create a separate issue onldraney/intelligentstaffingsystemsto track the privacy page, removing AC #3 from agent work; or (b) remove it from Prerequisites and keep it as AC agent work, accepting that this issue spans two repos.
- [x] Finding 1 (story note missing) -- RESOLVED.
-
Review: Fastlane setup + first TestFlight beta (re-review)
review-1832-2026-07-25Verdict: APPROVED
Re-review of board item #1832. Previous review returned NEEDS_REFINEMENT with 5 [BODY] and 1 [SCOPE] recommendation. All [BODY] recommendations have been addressed. The [SCOPE] recommendation (arch-app note) is carried forward as documentation debt but does not block this ticket's scope clarity.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Decomposition of #18, acknowledges ios#1 (DONE)
- [x] Repo -- ldraney/intelligentstaffingsystems-ios (with cross-repo note)
- [x] User Story -- present (platform owner / working TestFlight beta)
- [x] Context -- present, explicitly lists what ios#1 delivered
- [x] File Targets -- present (2 files: Matchfile, .env.default)
- [x] Feature Flag -- None (appropriate for build infrastructure)
- [x] Acceptance Criteria -- present (3 criteria)
- [x] Test Expectations -- present (3 manual tests)
- [x] Constraints -- present (5 constraints)
- [x] Checklist -- present
- [x] Related -- present (project-iss, #18, ios#1, #95)
- [x] Manual Prerequisites -- added (new section, addresses previous recommendation)
- [x] Manual Steps -- added (new section, addresses previous recommendation)
Previous Recommendations Resolution
- [x]
[BODY]Stale file targets removed -- FIXED. Reduced from 6 to 2 targets. Removed fastlane/Fastfile, fastlane/Appfile, README.md (all created by ios#1). Retained only Matchfile and .env.default as valid new targets. - [x]
[BODY]Already-met AC removed -- FIXED. Reduced from 9 to 3 AC. Removed AC for fastlane install, beta lane creation, release lane creation, and SceneDelegate URL (all completed by ios#1). - [x]
[BODY]Manual work separated -- FIXED. Added "Manual Prerequisites" section (Apple Developer enrollment, ASC app creation, API key, export compliance) and "Manual Steps" section (TestFlight upload, tester invites, device verification). - [x]
[BODY]Cross-repo AC removed -- FIXED. TestFlight CTA removed from AC. Related section explicitly notes "#95 -- landing page rewrite (TestFlight CTA belongs there, not here)". - [x]
[BODY]Repo placement acknowledged -- FIXED. Added explicit note under ### Repo: "This issue is filed on ldraney/intelligentstaffingsystems but all work lives in the iOS repo." - [ ]
[SCOPE]ISS-specific arch note -- CARRIED FORWARD. arch-app note still belongs to prediction-assistant (Kalshi). Does not affect ticket scope clarity; documented as debt below.
Traceability
- [x] story:ios-app label -- ios-app story exists in project-iss user-stories table (key: ios-app, backing: docs/ios.md, role: Lead/Client, metric: "App Store app loads the Rails app; rebuilds almost never")
- [x] story note verified -- found in project-iss user-stories section
- [~] arch:app label -- arch-app note EXISTS but belongs to prediction-assistant project, not ISS. [SCOPE] Carryforward: create ISS-specific app architecture note or use a different arch key (e.g., arch:ios). Does not block this ticket -- scope is clear without the backing note.
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/60, open
File Targets
- [x]
fastlane/Matchfile-- valid target. Not present in iOS repo (match not set up by ios#1). Needed if adopting match for code signing. - [x]
.env.default-- valid target. Not present in iOS repo. Template for ASC API key path and team ID (gitignored).
Both targets are in the iOS repo as documented. 2 files in 1 repo -- well within scope limits.
Repo Placement
Acknowledged cross-repo filing. Issue is on ldraney/intelligentstaffingsystems but explicitly notes all work is in ldraney/intelligentstaffingsystems-ios. The predecessor ios#1 was filed directly on the iOS repo. The cross-repo note is sufficient for this ticket since the ISS board tracks work across repos.
Dependencies
- ios#1 (board item #1798, DONE) -- predecessor. Delivered Fastfile, Appfile, Gemfile, README. Dependency met.
- #18 -- parent issue (iOS Turbo Native shell and App Store submission). Decomposition source.
- #95 -- landing page rewrite. TestFlight CTA explicitly deferred there. No blocking relationship.
- Production backend -- intelligentstaffingsystems.ai must be live. Domain wiring confirmed done per board history.
- Apple Developer Program -- external manual prerequisite, documented in Manual Prerequisites section.
- App Store Connect -- external manual prerequisite, documented in Manual Prerequisites section.
No blocking items on the board. All dependencies documented.
Acceptance Criteria
3 AC, all assessable:
- AC 1: Code signing via match or manual profiles -- Agent can create Matchfile and configure match. Verifiable by inspecting config.
- AC 2: fastlane beta runs end to end -- Configuration correctness verifiable by agent; actual execution is a Manual Step (done by Lucas on MacBook). The distinction between agent config and manual run is explicit.
- AC 3: App connects to production backend -- Agent can verify URL configuration in SceneDelegate or equivalent. Manual verification in Manual Steps section.
Clear division: agent handles configuration, Lucas handles execution on MacBook. Test Expectations are all marked "Manual:" which is consistent.
Blast Radius
Minimal. iOS repo only -- build and distribution infrastructure. No Rails consumers affected. No cross-service changes.
Decomposition Assessment
- File targets: 2 files in 1 repo -- under threshold
- AC: 3 -- under 5 threshold
- Estimated agent work: create Matchfile, create .env.default template, verify production URL config -- approximately 2-3 minutes
- No decomposition needed.
Recommendation
[SCOPE]Carryforward: Create ISS-specific app architecture note (arch-app belongs to prediction-assistant/Kalshi). Options: (a) create arch-ios note for the ISS iOS app component, (b) rename board label to arch:ios, (c) add ISS context to a shared arch-app note. This is documentation debt that does not block ticket execution.
All [BODY] recommendations from the previous review have been resolved. The ticket scope is clear, file targets are valid, AC are reasonable and within the 5-minute rule. Ticket is approved to move to todo.
-
Review: CRM tab (admin): business pipeline with search and promotion (re-review)
review-1826-2026-07-25-r2Verdict: READY
Re-review of board item #1826. All 4 findings from
review-1826-2026-07-25have been addressed.Previous Findings Resolution
- [x] [BODY] Add
app/models/lead.rbto File Targets -- FIXED. Now listed with description: "add Lead.search scope for case-insensitive search by name, email, and business_name" - [x] [BODY] Add
test/controllers/crm_controller_test.rbto File Targets -- FIXED. Now listed with description: "already exists with 7 stub tests; expand with the ~10 tests described in Test Expectations below" - [x] [BODY] Note
make_requestPOST support inkeycloak_admin_service.rbdescription -- FIXED. Description now notes: "make_request (around line 127) currently only handles GET and PUT in its case statement; add :post to support the realm-role-mapping endpoint" - [x] [SCOPE] Add "crm" story entry to project-iss user-stories section -- FIXED. Row now present: key=crm, backing="docs/ui-ux.md (CRM tab layout) + Epic 6 (US-6.1-6.2)", role=Admin
Template Completeness
- [x] Type -- Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] Dependencies
- [x] File Targets (10 entries, all verified)
- [x] Feature Flag -- none (appropriate for core admin functionality)
- [x] Acceptance Criteria (13 items)
- [x] Test Expectations (10 items)
- [x] Constraints
- [x] Checklist
- [x] Related
All 12 required sections present. Template is complete.
Traceability
- [x] story:crm label -- confirmed in project-iss user-stories table
- [x] story note verified -- "crm" row present with backing docs and success metric
- [x] arch:rails label -- arch-rails note exists in pal-e-docs
- [x] arch note verified -- active note with ISS Rails Architecture content
- [x] Forgejo issue -- ldraney/intelligentstaffingsystems#56, state: open
File Targets
- [x]
app/controllers/crm_controller.rb-- verified: stub exists withrequire_role :adminand emptyindexmethod (13 lines) - [x]
app/models/lead.rb-- verified: exists (38 lines), no search scope yet. Ticket correctly identifies need forLead.searchscope - [x]
app/views/crm/index.html.erb-- verified: placeholder "coming soon" template exists (35 lines) - [x]
app/views/crm/_business_card.html.erb-- to be created. OK - [x]
app/views/crm/show.html.erb-- to be created. OK - [x]
app/assets/stylesheets/crm.css-- to be created. OK (stylesheets dir confirmed) - [x]
app/services/keycloak_admin_service.rb-- verified:make_requestat line 127, supports only:getand:put. Ticket correctly notes need for:post - [x]
config/routes.rb-- verified: CRM stub route at line 42 (get "/crm"only). Needs expansion for show and promote actions - [x]
Gemfile-- verified: exists, no paper_trail currently - [x]
test/controllers/crm_controller_test.rb-- verified: exists with exactly 7 stub tests. Ticket correctly says "7 stub tests"
Repo Placement
OK. All work in
ldraney/intelligentstaffingsystems. Keycloak admin calls use existingKeycloakAdminServicein same repo. No cross-repo work needed.Dependencies
- #54 (Appointment scheduling) -- board item #1824, in validation. Correctly handled as soft dependency: "appointment data is additive, not blocking."
- #51 (Projects tab) -- done. Project requests model exists (
has_many :project_requestson Lead). - #6 (Keycloak auth) -- done. KeycloakAdminService exists.
- #14 (Admin user management) -- superseded by this ticket (documented in Lineage).
- No undocumented blockers found.
Acceptance Criteria
13 acceptance criteria, all verifiable by an agent. Test commands reference real paths (
rails test test/controllers/crm_controller_test.rb). Minor observations (not blocking):- Lead.search scope tested via test expectations ("Model test: Lead.search scope") even though no standalone AC for it -- search behavior is covered by AC #2.
- Constraints section covers graceful Keycloak handling ("Keycloak admin API credentials from SOPS-encrypted env vars").
promoted_atcolumn already exists in schema (verified at db/schema.rb line 93). No migration needed for that field.
Blast Radius
KeycloakAdminService#make_request-- adding:postto case statement is low risk, isolated change.paper_trailgem -- Docker build impact (bundle install). Agent must update Gemfile.lock.Lead.roleenum andpromoted_atcolumn already in schema -- no migration needed for promotion model support.- No similar promotion patterns exist elsewhere. No downstream consumers affected.
Decomposition Assessment
13 ACs across 10 files in 1 repo. Exceeds the >5 AC threshold. Per user preference (no decomposition), inclusive tickets are preferred. 8-point sizing is appropriate. All work is in a single repo and domain. No decomposition needed.
Recommendation
No action needed. All previous findings resolved. Scope is solid, file targets verified, traceability complete.
- [x] [BODY] Add
-
Review: Local dev tests fail due to bundle install network timeouts
review-1895-2026-07-25Verdict: READY
Template Completeness
- [x] Type — Bug
- [x] Lineage — Standalone, discovered during CSS consolidation session (#63)
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] What Broke — bundle install network timeout, well-described with error output
- [x] Repro Steps — 3 steps, clear and reproducible
- [x] Expected Behavior — present
- [x] Environment — local dev (docker compose), Harbor image specified
- [x] Acceptance Criteria — 3 criteria, all testable
- [x] Related — project-iss and #47 CI pipeline referenced
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section (key: "project-setup", backing: README + docs/architecture.md + docs/adoption-plan.md)
- [x] arch:infra label — arch-infra note exists in pal-e-docs (note covers shared infrastructure patterns; scoped to paldocs but infrastructure is a cross-project concern, acceptable)
- [x] Forgejo issue — ldraney/intelligentstaffingsystems#65, state: open
File Targets
Bug template — no explicit File Targets section required. Implied files verified:
- [x] docker-compose.yml — exists, confirmed: bundle install in command (line 13), bundle volume (lines 18, 35), BUNDLE_PATH env var (line 28)
- [x] .woodpecker.yaml — exists, confirmed: CI uses
cp -a /usr/local/bundle/. vendor/bundle/to seed gems from base image (line 9), providing a clear fix pattern - [x] Makefile — exists, confirmed:
make testrunsdocker compose run --rm web rails test(line 61) - [x] Harbor image reference
harbor.tail5b443a.ts.net/library/ruby-rails-build:latest— confirmed in docker-compose.yml line 11
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, fix applies to the same repo (docker-compose.yml, possibly entrypoint script or Makefile).
Dependencies
- #99 (board item #1887, validation column) — partially related. PR #102 added
bundle installto the docker-compose command but did not solve the network timeout root cause. #99's body explicitly references#65 — Docker bundle install networkas related. - #47 (board item #1819, done) — CI pipeline setup. CI works correctly with cached gems; its approach (copy pre-baked gems from base image) provides the fix pattern for #65.
- No blockers — #65 can be worked independently.
Acceptance Criteria
3 criteria, all agent-verifiable:
docker compose run web rails testworks without network access to rubygems.org — testable (run with network disabled or check that no rubygems.org fetch occurs)- Local dev gems are either baked into the image or volume-cached — testable (verify volume contents or entrypoint logic)
- CI pipeline continues to work unchanged — testable (run CI pipeline)
Note: MEMORY.md documents "Docker tests hang (#65); agents must skip docker verification" — resolving this issue would lift that operational constraint.
Blast Radius
Limited to local development workflow. No production impact. The fix should not affect CI (which already works with its own gem seeding approach). docs/local-dev-setup.md references the bundle volume pattern (line 40, 47) and may need updates if the fix changes the seeding approach.
Decomposition Assessment
1-2 file targets in 1 repo, 3 acceptance criteria, estimated well under 5 minutes. No decomposition needed.
Recommendation
No action needed.
-
Review: CRM tab (admin): business pipeline with search and promotion
review-1826-2026-07-25Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria (13 items)
- [x] Test Expectations (10 items)
- [x] Constraints
- [x] Checklist
- [x] Related
- [x] Dependencies (bonus section, not required)
All 12 required sections present. Template is complete.
Traceability
- [x] story:crm label -- maps to Epic 7: CRM (Admin) in docs/user-stories.md (US-7.1, US-7.2, US-7.3)
- [ ] story note MISSING -- [SCOPE] project-iss user-stories section has "admin" key (Epic 6) but no "crm" key for Epic 7. Add "crm" story entry to project-iss user-stories section.
- [x] arch:rails label -- arch-rails note exists in pal-e-docs (verified)
- [x] arch note verified -- arch-rails note active with ISS Rails Architecture content
- [x] Forgejo issue -- ldraney/intelligentstaffingsystems#56, state: open
File Targets
- [x]
app/controllers/crm_controller.rb-- verified: stub exists withrequire_role :adminand emptyindexmethod. Ticket correctly references existing stub. - [x]
app/views/crm/index.html.erb-- verified: placeholder "coming soon" template exists (35 lines). - [x]
app/views/crm/_business_card.html.erb-- to be created. OK. - [x]
app/views/crm/show.html.erb-- to be created. OK. - [x]
app/assets/stylesheets/crm.css-- to be created. OK. - [x]
app/services/keycloak_admin_service.rb-- verified: exists withget_user/update_usermethods. Note:make_requestonly supports:getand:put; needs:postfor realm-role-mapping endpoint. Not mentioned in ticket. - [x]
config/routes.rb-- verified: CRM stub route at line 42 (get "/crm"only). Needs expansion forshowandpromoteactions. - [x]
Gemfile-- verified: exists, no paper_trail currently. - [ ]
app/models/lead.rb-- MISSING from file targets. AC requires search filtering (ILIKE) and test expectations list "Model test: Lead.search scope (name, email, business_name)". Model needs asearchscope added. - [ ]
test/controllers/crm_controller_test.rb-- MISSING from file targets. File exists with 7 stub tests for the placeholder, needs expansion with 10 new tests per test expectations.
Repo Placement
OK. All work is in
ldraney/intelligentstaffingsystems. Keycloak admin calls go through the existingKeycloakAdminServicealready in this repo. No cross-repo work needed.Dependencies
- #54 (Appointment scheduling) -- board item #1824, currently in validation column. Correctly handled as soft dependency: "appointment data is additive, not blocking."
- #51 (Projects tab) -- done. Project requests model and controller exist.
- #6 (Keycloak auth) -- done. KeycloakAdminService exists.
- #14 (Admin user management) -- superseded by this ticket (documented in Lineage).
- No undocumented blockers found.
Acceptance Criteria
13 acceptance criteria, all verifiable by an agent. Test commands reference real test paths (
rails test test/controllers/crm_controller_test.rb). Observations:- No explicit AC for
Lead.searchscope behavior (tests reference it but AC does not). - No AC for graceful handling when KeycloakAdminService is not configured (dev environment without Keycloak admin credentials).
- Promotion audit trail (PaperTrail) has an AC but no corresponding test expectation.
Blast Radius
KeycloakAdminService#make_requestcurrently supports only:getand:put. Adding:postchanges a shared utility method -- low risk, simple case statement extension.- Adding
paper_trailgem impacts Docker builds (bundle install in container image). Agent must runbundle installand updateGemfile.lock. Lead.roleenum (lead/client/admin) andpromoted_atcolumn already exist in schema -- promotion model support is already in place. No migration needed for those fields.- No similar promotion patterns exist elsewhere to break. No downstream consumers affected.
Decomposition Assessment
13 ACs across 8+ files in 1 repo. Exceeds the >5 AC threshold. However, per user preference, inclusive tickets are preferred over decomposition. The 8-point sizing is appropriate. All work is in a single repo and a single domain (Rails CRM tab). No decomposition needed.
Recommendations
- [BODY] Add
app/models/lead.rbto File Targets -- needsLead.searchscope per AC #2 ("Search bar filters businesses") and Test Expectations ("Model test: Lead.search scope"). - [BODY] Add
test/controllers/crm_controller_test.rbto File Targets -- existing file (7 stub tests) needs expansion with new tests per Test Expectations section. - [BODY] Note in
app/services/keycloak_admin_service.rbfile target description thatmake_requestneeds:postmethod support for the realm-role-mapping endpoint. - [SCOPE] Add "crm" story entry to project-iss user-stories section. The repo has Epic 7: CRM (Admin) in
docs/user-stories.md, but the pal-e-docs project page only lists "admin" (Epic 6). The board item correctly usesstory:crmper the repo docs.
-
Review: Google Play Store submission
review-1885-2026-07-25Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag (none -- acceptable, this is store submission config)
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:android-app label -- present on board item
- [ ] story note MISSING -- [SCOPE] No
android-appentry in project-iss user-stories section. The table listsios-appbut has no Android counterpart. Create user story entry on project-iss user-stories section. - [x] arch:app label -- present on board item
- [ ] arch note WRONG PROJECT -- [SCOPE]
arch-appnote exists but belongs to Prediction Assistant (Kalshi), not ISS. Either create an ISS-specific architecture note (e.g.,arch-iss-apporarch-android) or re-label the board item with a more specific arch tag. - [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/iss-android/issues/1, open
File Targets
- [x]
app/build.gradle.kts-- verified: file exists in iss-android repo. Currently has release buildType with minify/proguard but no signing config. Ticket correctly identifies this needs signing config added. - [x]
fastlane/Fastfile-- directory does not exist (expected). Ticket marks this as conditional ("if using Fastlane"). Acceptable. - [x] Store assets directory -- new directory, does not exist yet (expected for new creation).
Repo Placement
OK. Issue is filed on
ldraney/iss-android, board item is onboard-iss. The Android app is part of the ISS ecosystem. The issue body correctly states### Repo: ldraney/iss-android. No cross-repo code changes needed -- only the iss-android repo is modified.However, there is an implicit dependency on the ISS Rails app for the privacy policy page (see Dependencies).
Dependencies
- Privacy policy page (UNDOCUMENTED BLOCKER) -- The Constraints section states "Need privacy policy page deployed before submission" and AC #5 references
intelligentstaffingsystems.ai/privacy. However: no/privacyroute exists in the ISS Rails app, no privacy view template exists, and no board item on board-iss tracks this work. This is an undocumented external dependency that blocks Play Store submission. - Store assets -- Screenshots and 1024x500 feature graphic are listed as constraints but no source or process is documented for producing them.
- iOS app (#1798) -- Done. The Android ticket mirrors the iOS app pattern. No blocking dependency.
- Landing page rewrite (#1883/#95) -- In backlog, sprint:E. Not a direct dependency, but if the landing page changes significantly, Play Store screenshots may need updating.
Acceptance Criteria
7 acceptance criteria. Most are manual external operations that an agent cannot perform or verify programmatically:
- Agent-automatable: AC #2 (signed release AAB), partially AC #5 (setting URL in config)
- Manual/external: AC #1 (Google Play Developer account -- requires payment), AC #3 (Play Store listing -- requires Google Play Console), AC #4 (content rating questionnaire), AC #6 (app live on Play Store), AC #7 (install link works)
The test expectations are both manual. This is reasonable for a store submission ticket, but means an agent can only handle the build/signing automation portion. The ticket should clarify which AC are agent work vs. human work.
Blast Radius
Self-contained to iss-android repo for code changes. The privacy policy dependency touches the ISS Rails app but is a separate concern. No downstream consumers affected. No similar patterns in sibling services need updating.
Decomposition Assessment
7 acceptance criteria (exceeds 5-AC threshold on count). However, the agent-automatable work is small: adding signing config to
app/build.gradle.ktsand optionally scaffolding a Fastlane lane. Estimated agent work: <5 minutes for the code changes. The remaining AC are manual operations. No decomposition needed for the code portion, but the ticket would benefit from clearly separating agent work from manual steps.Recommendation
[SCOPE]Createandroid-appuser story entry in the project-iss user-stories section. Mirror the existingios-appstory pattern.[SCOPE]Thearch-appnote belongs to Prediction Assistant, not ISS. Either create an ISS-scoped arch note (e.g.,arch-iss-android) or re-label the board item with a valid arch tag for the ISS project.[BODY]Add a dependency note: "Blocked by: privacy policy page on ISS Rails app (no route/view exists yet). Needs a separate ticket or must be completed before this ticket can finish."[BODY]Clarify which AC are agent-automatable vs. manual human steps. Consider splitting into: (a) agent ticket for build/signing config, (b) manual checklist for Play Store operations.[BODY]Document the process for producing store assets (screenshots, feature graphic, icon). Are these generated from the running app? Designed manually?
-
Review: Fix action_mailer default_url_options (still references example.com)
review-1867-2026-07-25Verdict: BLOCK
Template Completeness
- [x] Type -- Bug
- [x] Lineage -- Standalone, discovered during QA review of PR #70
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] What Broke -- described clearly
- [x] Repro Steps -- 3 steps provided
- [x] Expected Behavior -- described
- [x] Environment -- prod, current main
- [x] Acceptance Criteria -- 3 items
- [x] Related -- project-iss, PR #70 / #69
Traceability
- [x] story:project-setup label -- found in project-iss user-stories section
- [x] arch:rails label -- arch-rails note exists in pal-e-docs
- [x] Forgejo issue #71 -- open (should be closed as already-fixed)
File Targets
- [ ]
config/environments/production.rb-- ISSUE: The bug no longer exists. Line 60 already readsconfig.action_mailer.default_url_options = { host: "intelligentstaffingsystems.ai" }. This was fixed by PR #87 which addressed issue #85.
Repo Placement
OK -- issue filed on correct repo.
Dependencies
Issue #85 (board item #1875, column: done) already fixed this bug as part of "fix: CI minitest/mock LoadError + placeholder k8s secrets + action_mailer example.com" via PR #87. This issue is a duplicate of work already completed.
Acceptance Criteria
All three acceptance criteria are already satisfied in the current codebase:
- [x]
action_mailer.default_url_optionshost set tointelligentstaffingsystems.ai-- confirmed at production.rb line 60 - [x] No other references to
example.comremain in production config -- remaining references are all in comments (lines 22, 66, 83-84), not active code - [x] Bug no longer reproduces -- the file already has the correct value
Blast Radius
Grep found additional
example.comreferences, none of which are bugs in this context:app/mailers/application_mailer.rb:2--default from: "from@example.com"is a scaffold default "from" address. This is a separate concern (not a URL option) and could warrant its own ticket if mailers are ever activated.config/environments/test.rb:40--example.comin test mailer config is standard practice.- Test files and fixtures -- standard use of
example.comdomain for test data.
Decomposition Assessment
Not applicable -- no work to perform. The bug is already fixed.
Recommendation
[SCOPE]Close Forgejo issue #71 as already-fixed. The fix shipped in PR #87 (issue #85). Remove board item #1867 from the board or move to done.[SCOPE]Consider filing a separate ticket forapp/mailers/application_mailer.rbfrom@example.comif/when mailers are activated.
-
Review: Replace favicon with ISS helmet logo
review-1897-2026-07-20Verdict: READY
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, designed in iss-logo repo
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- present (As a site visitor...)
- [x] Context -- detailed background on logo design and current placeholders
- [x] File Targets -- 2 modify targets + 1 do-not-touch, clearly scoped
- [x] Feature Flag -- none (appropriate for static asset swap)
- [x] Acceptance Criteria -- 4 criteria
- [x] Test Expectations -- visual verification (appropriate for favicon)
- [x] Constraints -- 4 constraints covering upscale, SVG quality, transparency, source of truth
- [x] Checklist -- standard 3 items
- [x] Related -- present
Traceability
- [x] story:ui-ux label -- "Design doc + tab architecture established as single source of truth"
- [x] story note verified -- found in project-iss user-stories section (key: ui-ux, backing: docs/ui-ux.md)
- [x] arch:frontend label -- frontend component
- [x] arch note verified -- arch-frontend note exists in pal-e-docs (note: arch-frontend describes prediction-assistant frontend; ISS uses similar Turbo Native + Hotwire stack but has no ISS-specific arch-frontend note. Not a blocker for a favicon swap.)
- [x] Forgejo issue -- https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/106, open
File Targets
- [x]
public/icon.png-- verified: exists (4.2K), is the placeholder to be replaced - [x]
public/icon.svg-- verified: exists (122 bytes), confirmed red circle placeholder SVG - [x]
app/views/layouts/application.html.erb:17-19-- verified: lines 17-19 contain icon.png, icon.svg, and apple-touch-icon link tags. Correctly listed as do-not-touch. - [x] Source:
~/iss-logo.png-- verified: exists (45K, 300x300) - [x] Source:
~/iss-logo/logos.html-- verified: exists (11K), contains V1-R2 helmet canvas drawing code
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems, fix targets are in the same repo. Source artwork is in the separate iss-logo workspace (design-only, not deployed).
Dependencies
None. Standalone work. No blocking or blocked items on board-iss. Logo design is finalized in the iss-logo workspace.
Acceptance Criteria
4 visual criteria, all reasonable for a static asset swap. AC #2 (iOS apple-touch-icon) technically requires a device but the link tag already points to /icon.png, so file replacement handles it. Test expectations are visual-only -- appropriate since there is no behavioral logic to unit test.
Blast Radius
Low. Observation:
app/views/pwa/manifest.json.erbalso references/icon.png(lines 5 and 10) for PWA icons. Not mentioned in the issue, but since the file is replaced in-place at the same path, the PWA manifest will automatically pick up the new icon. No action needed -- this is handled by the in-place replacement strategy.Decomposition Assessment
No decomposition needed. 2 file targets in 1 repo. 4 acceptance criteria. Estimated agent work well under 5 minutes -- straightforward file copy (PNG) and SVG redraw from existing canvas source.
Recommendation
No action needed.
-
Review: Create ISS staging environment with auto-deploy on merge to main
review-1893-2026-07-20Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references #192 and #194
- [x] Repo -- ldraney/pal-e-services
- [x] User Story -- As a developer / staging auto-deploy / verify before prod
- [x] Context -- explains current risk (auto-deploy to prod), staging rationale
- [x] File Targets -- 4 targets across 2 repos + DNS
- [x] Feature Flag -- none (appropriate for infra work)
- [x] Acceptance Criteria -- 7 items
- [x] Test Expectations -- 4 items with run command
- [x] Constraints -- 4 constraints
- [x] Checklist -- standard PR gates
- [x] Related -- project-iss, #192, #194
- [x] Dependency Chain -- bonus section, well-documented
- [x] Keycloak -- bonus section, clear instructions
Traceability
- [x] story:dev-environment label -- verified in project-iss user-stories section (row: "dev-environment", backing "#192 / #193 / #194 + docs/pipeline.md")
- [x] story note verified -- found in project-iss user-stories table
- [x] arch:argocd label -- references ArgoCD deployment pattern
- [x] arch note verified -- arch-argocd note exists in pal-e-docs (slug: arch-argocd, "ArgoCD + Image Updater Deployment Pattern")
- [x] Forgejo issue -- ldraney/pal-e-services#193, open
File Targets
- [x]
terraform/k3s.tfvars.example(pal-e-services) -- verified: containsservicesmap (line 517, existing ISS entry) andservice_databasesmap (line 551, existingissentry). Agent needs to add staging service entry and staging database entry. - [x]
terraform/keycloak.tf(pal-e-services) -- verified: usesfor_each = var.keycloak_clients. Issue correctly says "no structural changes needed" -- Keycloak client URIs are managed in k3s.tfvars, not keycloak.tf. - [x]
terraform/databases.tf(pal-e-services) -- verified: usesfor_each = var.service_databases. Issue correctly says "no structural changes needed". - [x]
overlays/intelligentstaffingsystems/staging/(pal-e-deployments) -- verified: does not exist yet (expected, to be created). Prod overlay exists atoverlays/intelligentstaffingsystems/prod/with kustomization.yaml, deployment-patch.yaml, secrets.enc.yaml, README.md -- staging should mirror this structure. - [ ] DNS -- ISSUE: Issue says "add A record via DNS provider (GoDaddy)" but DNS records are terraform-managed in
pal-e-platform/terraform/dns.tf. Existing pattern:godaddy_dns_record.iss_dev(line 64) uses a CNAME pointing tointelligentstaffingsystems.ai, not an A record. Staging should follow the same CNAME pattern. This is a 3rd repo not listed in File Targets. - [ ] Caddy reverse proxy -- MISSING: The custom domain routing path (per arch-argocd) requires Caddy on the Hetzner edge VPS to proxy
staging.intelligentstaffingsystems.aitointelligentstaffingsystems-staging.tail5b443a.ts.net. Caddy is managed by SaltStack (hetzner-edge module usessalt_master_ip). The issue does not mention Caddy/Salt configuration. Without this, DNS alone will not route traffic to staging.
Repo Placement
Issue is filed on
pal-e-services. Work actually spans 3 repos:pal-e-services-- terraform k3s.tfvars (service entry, database entry, Keycloak client URIs)pal-e-deployments-- staging overlay (acknowledged in issue)pal-e-platform-- DNS record in dns.tf + Caddy/Salt config (NOT acknowledged in issue)
The issue does not clarify whether the agent should create PRs in all 3 repos or how cross-repo coordination works.
Dependencies
- #192 (dev environment, board item 1892) -- backlog, independent. Confirmed parallel.
- #194 (prod manual promotion, board item 1894) -- backlog, blocked by this ticket. Confirmed: both open.
- No in-progress blockers found on board-iss.
- Dependency chain is well-documented in the issue body.
Acceptance Criteria
7 ACs, all verifiable by an agent:
- AC1 (namespace) --
kubectl get ns intelligentstaffingsystems-staging - AC2 (ArgoCD synced) --
argocd app get intelligentstaffingsystems-staging - AC3 (image updater) -- check annotations on ArgoCD application CR
- AC4 (staging URL) --
curl -sI https://staging.intelligentstaffingsystems.ai - AC5 (databases) -- kubectl or psql verification
- AC6 (Keycloak) -- verify redirect URIs via Keycloak admin API
- AC7 (DNS) --
dig staging.intelligentstaffingsystems.ai
All criteria are testable. AC4 depends on Caddy/Salt configuration which is not scoped in the issue (see File Targets issues).
Blast Radius
- var.services addition: Low risk. New entry follows arch-argocd's var.services pattern (7 resources via for_each). Does not modify existing services.
- Keycloak client URIs: Medium risk. Adding staging redirect URIs to the shared
intelligentstaffingsystemsclient. Misconfiguration could affect prod/dev auth flows. However, the pattern matches the existing dev URIs already added. - Image updater overlap: During the gap between #193 (this) and #194 (prod manual promotion), BOTH staging and prod will auto-deploy on new images. This is documented and expected but worth noting -- any broken merge to main hits prod immediately during this period.
- Network policies: pal-e-platform's
network-policies.tfhas explicit entries for theintelligentstaffingsystemsnamespace. The newintelligentstaffingsystems-stagingnamespace may need its own network policy entries. Not mentioned in the issue. - Stale image_repo in k3s.tfvars.example: The example file says
image_repo = "intelligentstaffingsystems/intelligentstaffingsystems"(line 519), but the production overlay referencesharbor.tail5b443a.ts.net/intelligentstaffingsystems/app. Per the "Image Repo Mismatch Fix" memory note, the actual k3s.tfvars was fixed tointelligentstaffingsystems/app. The issue's constraint perpetuates the stale value. The agent must use the correct value (intelligentstaffingsystems/app) for staging.
Decomposition Assessment
File targets: 4+ files across 3 repos (pal-e-services + pal-e-deployments + pal-e-platform). ACs: 7 (exceeds threshold of 5). Estimated time: 5-10 minutes for an experienced agent. Per user preference (memory: "No Decomposition"), no decomposition recommended. The work is cohesive -- it follows the arch-argocd "Onboarding a New Service" pattern, and splitting it would create coordination overhead. A single agent with platform knowledge can execute this as one unit.
Recommendations
[BODY]Fix image_repo reference in Constraints section:intelligentstaffingsystems/intelligentstaffingsystemsshould beintelligentstaffingsystems/app(matches prod overlay and image repo mismatch fix). Also update k3s.tfvars.example line 519 to reflect the actual value.[BODY]Fix DNS file target: DNS is terraform-managed inpal-e-platform/terraform/dns.tf, not added manually via GoDaddy. Addpal-e-platform/terraform/dns.tfto File Targets. Follow the existing CNAME pattern (cf.godaddy_dns_record.iss_devat line 64) rather than an A record.[BODY]Add Caddy/Salt configuration to scope:staging.intelligentstaffingsystems.aineeds a Caddy reverse proxy entry on the Hetzner edge VPS to route tointelligentstaffingsystems-staging.tail5b443a.ts.net. This is managed by SaltStack. Without it, AC4 (staging URL serves app) will fail. Document whether this is handled in this ticket or a separate one.[BODY]Clarify cross-repo PR strategy: Work spans pal-e-services, pal-e-deployments, and pal-e-platform. State whether the agent should create PRs in all repos, and specify the order of operations (e.g., pal-e-services terraform first, then pal-e-deployments overlay, then pal-e-platform DNS).
-
Review: Register ISS dev environment as terraform-managed service
review-1892-2026-07-20Verdict: NEEDS_REFINEMENT
Re-reviewed 2026-07-20. Previous review flagged two issues; one resolved (arch-argocd note now exists), one still outstanding (invalid paldocs-dev reference).
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, discovered debugging 502
- [x] Repo — ldraney/pal-e-services
- [x] User Story — As a developer / I want / So that
- [x] Context — Comprehensive: 502 cause, overlay state, Harbor/image-updater gap
- [x] File Targets — 4 pal-e-services files + cross-repo pal-e-deployments
- [x] Feature Flag — none
- [x] Acceptance Criteria — 6 criteria
- [x] Test Expectations — 4 items with run commands
- [x] Constraints — 4 constraints
- [x] Checklist — Present
- [x] Related — Present
All 12 required sections present.
Traceability
- [x] story:dev-environment label — verified in project-iss user-stories table (backing: "#192 / #193 / #194 + docs/pipeline.md")
- [x] story note verified — found in project-iss user-stories section
- [x] arch:argocd label — present on board item
- [x] arch note verified — arch-argocd note exists in pal-e-docs (doc type, tags: architecture, argocd, platform). Created 2026-07-21. RESOLVED from previous review.
- [x] Forgejo issue — ldraney/pal-e-services#192, state: open
File Targets
- [x]
terraform/k3s.tfvars— verified: symlink to secrets; confirms ISS prod registered (L370) but no dev entry exists - [x]
terraform/k3s.tfvars.example— verified: exists, contains ISS prod entry and my-service-dev pattern (L470) - [x]
terraform/variables.tf— verified: services type (L269-282) has no image_updater/harbor opt-out field yet - [x]
terraform/services.tf— verified: harbor_project (L43), harbor_robot_account (L54, L90), harbor_creds secret (L127), and ArgoCD image-updater annotations (L196-202) all use unconditionalfor_each = var.services - [x]
overlays/intelligentstaffingsystems/dev/*.yaml(pal-e-deployments) — verified: 7 files present, namespace consistentlyiss-devacross all manifests (namespace.yaml, deployment.yaml, service.yaml, ingress.yaml, configmap.yaml, kustomization.yaml)
Repo Placement
OK. Issue filed on ldraney/pal-e-services where all terraform files reside. Cross-repo dependency on pal-e-deployments is documented in File Targets section (conditional namespace rename). No separate Forgejo issue needed for pal-e-deployments — the change is minor and conditional.
Dependencies
- Board items #1893 (pal-e-services#193 — staging) and #1894 (pal-e-services#194 — prod promotion) both depend on this ticket's opt-out flag. Documented in issue: "This ticket owns the opt-out flag; #193 and #194 consume it."
- #193 is independent of #192 (can proceed in parallel). #194 is blocked by #193.
- #86 (dev environment, Rails side) — done. No blockers on this ticket.
- No items in in_progress that block this work.
Acceptance Criteria
6 criteria, all verifiable by an agent:
- [x] Namespace exists —
kubectl get ns {chosen-namespace} - [x] ArgoCD app Synced/Healthy —
kubectl get applications.argoproj.io -n argocd - [x] curl returns 200 —
curl -sI https://dev.intelligentstaffingsystems.ai - [x] No Harbor project/robot accounts —
terraform planoutput verification - [x] No image updater annotations —
kubectl get app -n argocd -o yaml - [x] terraform plan clean —
terraform plan -var-file=k3s.tfvars
All criteria are concrete and machine-verifiable. 6 ACs is at the boundary of the >5 threshold, but these are verification steps for the same terraform apply, not independent implementation work. No decomposition needed.
Blast Radius
The opt-out flag (e.g.,
image_updater = optional(bool, true)) defaults to true, so all 13 existing services retain current behavior with no tfvars changes. Safe.Resources that must be gated behind the flag in services.tf:
harbor_project.service(L43)harbor_robot_account.service_ci(L54)harbor_robot_account.service_pull(L90)kubernetes_secret_v1.harbor_creds(L127)- ArgoCD image-updater annotations in
argocd_application.service(L196-202)
No similar pattern gaps found in sibling services — this is the first non-Harbor service in the stack.
Decomposition Assessment
4 file targets in 1 primary repo + conditional cross-repo rename. 6 AC (boundary case, all verification of same apply). Estimated agent time: ~5 minutes. Work is tightly coupled in one terraform directory. No decomposition needed.
Recommendation
[BODY]Fix invalid reference: Context section says "seepaldocs-devas reference" but nopaldocs-devservice exists in k3s.tfvars or k3s.tfvars.example. Replace with reference tomy-service-devpattern in k3s.tfvars.example (line 470), or remove the reference entirely and let the agent infer the pattern from existing entries.
Previous
[SCOPE]recommendation (create arch-argocd note) is RESOLVED — note was created 2026-07-21. -
Review: Local dev tests fail due to bundle install network timeouts
review-1895-2026-07-20Verdict: BLOCK
Root cause already fixed. The bug described in this ticket (bundle install network timeouts in local dev) was caused by k3s iptables rules breaking Docker bridge NAT. The fix —
network_mode: hoston the web container — was merged in PR #94 (board item #1876, done) and refined in PR #102 (issue #99). The issue should be closed rather than advanced.Template Completeness
- [x] Type — Bug
- [x] Lineage — Standalone, discovered during CSS consolidation (#63)
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] What Broke — bundle install timeouts, bundler: command not found
- [x] Repro Steps — 3 steps provided
- [x] Expected Behavior — described
- [x] Environment — local dev, Harbor image, CI image
- [x] Acceptance Criteria — 3 criteria listed
- [x] Related — project-iss, issue #47
All required sections present. Template is complete.
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section
- [ ] arch:infra label — present on board item, but arch note MISSING — [SCOPE] Create architecture note arch-infra
- [x] Forgejo issue — #65, open
File Targets
- [x]
docker-compose.yml— verified:network_mode: hostalready on line 14 of committed main.bundle:/usr/local/bundlevolume already in place for gem caching.
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, fix is in same repo.
Dependencies
- PR #94 (merged, board item #1876, done) — introduced
network_mode: hostand dev environment overhaul - PR #102 (merged, issue #99) — fixed port convention (9999 to 8888) and Docker bundler failure
- Board item #1887 (issue #99, backlog) — related port/bundler fix, also addresses overlapping symptoms
Acceptance Criteria
All 3 AC are already satisfied by the existing fix:
- AC1:
docker compose run web rails testworks without network access to rubygems.org —network_mode: hostenables reliable network access;bundlevolume caches gems across runs. - AC2: Local dev gems are volume-cached —
bundle:/usr/local/bundlevolume is committed on main. - AC3: CI pipeline unchanged — Woodpecker uses its own
.woodpecker.yamlwithbundle install --jobs=4, unaffected by compose changes.
Blast Radius
No concerns. The fix is already merged and operational.
bundle installappears in two independent paths:docker-compose.yml(local dev, host networking) and.woodpecker.yaml(CI, Woodpecker networking). They do not interact.Decomposition Assessment
No decomposition needed — no work remains. The fix was delivered as part of other tickets.
Recommendation
- [SCOPE] Close Forgejo issue #65 — root cause fixed by
network_mode: host(PR #94, PR #102). All acceptance criteria are met by existing committed code. - [SCOPE] Remove or move board item #1895 to done — no implementation work remains.
- [SCOPE] Create architecture note
arch-infrafor the infra component (missing traceability note, but not blocking since issue should be closed).
-
Review: CRM tab (admin): business pipeline with search and promotion (re-review)
review-1826-2026-07-18-v2Verdict: APPROVED
Re-review after body refinements. All five previously flagged [BODY] issues are resolved. Ticket scope is solid and implementable.
Template Completeness
- [x] Type — Feature
- [x] Lineage — replaces #14
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — As the admin, I want a searchable pipeline with filtering and promotion
- [x] Context — modeled after landscaping-assistant "today tab"
- [x] Dependencies — #54 soft dependency documented with graceful handling
- [x] File Targets — 8 files listed (including Gemfile for PaperTrail) plus exclusions
- [x] Feature Flag — none (core admin functionality)
- [x] Acceptance Criteria — 13 items
- [x] Test Expectations — 10 items plus run command
- [x] Constraints — 8 constraints listed including realm-role-mapping specifics
- [x] Checklist — standard 3-item
- [x] Related — references project and related issues
Traceability
- [x] story:crm label — documented in repo docs/user-stories.md as Epic 7: CRM (Admin), covering US-7.1, US-7.2, US-7.3. Sprint roadmap maps #56 to Epic 7.
- [ ] story note on project page — [SCOPE] project-iss user-stories table uses key "admin" (Epic 6) but repo distinguishes Epic 6 (Account) from Epic 7 (CRM). Add "crm" row to project-iss user-stories table mapping to Epic 7.
- [ ] arch note MISSING — [SCOPE] No arch-rails note exists in pal-e-docs. Systemic gap (many board items use arch:rails). Create architecture note arch-rails.
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/56, state: open
File Targets
- [x]
app/controllers/crm_controller.rb— verified: EXISTS as stub with require_role :admin. Matches top-level tab controller convention (catalog, communications, messages). - [x]
app/views/crm/index.html.erb— verified: EXISTS as stub view (empty-state placeholder). - [x]
app/views/crm/_business_card.html.erb— to be created; correct path under existing crm/ view directory. - [x]
app/views/crm/show.html.erb— to be created; correct path. - [x]
app/assets/stylesheets/crm.css— to be created; matches existing convention (catalog.css, communications.css, dashboard.css, etc.). - [x]
app/services/keycloak_admin_service.rb— verified: EXISTS with get_user and update_user. Ticket specifies adding promote_to_client using realm-role-mapping API (POST /admin/realms/{realm}/users/{id}/role-mappings/realm). Needs POST method added to make_request. - [x]
config/routes.rb— verified: EXISTS with stub route at line 37 (get "/crm"). Needs show and promote action routes added. - [x]
Gemfile— verified: EXISTS. PaperTrail NOT present (correct — ticket says to add it).
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all work targets that repo. Keycloak admin API calls go outbound to the Keycloak server, no cross-repo changes needed.
Dependencies
- #6 (Keycloak OIDC auth) — DONE. Provides KeycloakAdminService foundation and session role extraction.
- #51 (Projects tab) — DONE. ProjectRequest model exists for "project requests visible on business detail" AC.
- Messaging subsystem — DONE. Message model and threads exist for "message thread link" AC.
- #54 (Appointment scheduling) — NOT landed. Ticket explicitly handles this: "If #54 has not landed, show last activity from messages and project requests only; appointment data is additive, not blocking." AC #5 uses conditional "(+ last appointment if #54 has landed)". Graceful.
- Lead.search scope — does not exist yet. Will be created as part of this ticket.
- promoted_at column — EXISTS in schema (line 80). Role column EXISTS (line 82, default "lead").
- PaperTrail gem — NOT installed. Explicitly listed as Gemfile file target to add.
Acceptance Criteria
13 acceptance criteria. All are testable by an agent:
- AC #1-4 (access control, search, filter, card display) — standard controller/view testing with session stubbing per testing-strategy.md.
- AC #5 (last activity) — aggregates across messages and project_requests (both exist). Appointment is conditional. Clear and implementable.
- AC #6 (business detail) — show view with related data. Straightforward.
- AC #7-8 (promote button, confirmation) — UI elements, testable via view rendering.
- AC #9 (Keycloak role update) — NOW PRECISELY SPECIFIED: realm-role-mapping API, POST endpoint given. KeycloakAdminService can be extended cleanly.
- AC #10-11 (mirror to Lead.role, set promoted_at) — model update; columns already exist in schema.
- AC #12 (PaperTrail audit) — gem addition now in file targets. Standard Rails gem integration.
- AC #13 (project requests in detail) — ProjectRequest model exists, belongs_to :lead.
Blast Radius
- Tab bar helper (app/helpers/navigation_helper.rb) already references CRM path for admin — no route rename needed (stub route stays at /crm).
- KeycloakAdminService: adding promote_to_client method with POST support extends the service without modifying existing get_user/update_user methods. Safe.
- PaperTrail installation adds a versions table and initializer — standard Rails concern, isolated to new model integration.
- No search scope exists anywhere in the app — Lead.search will be the first. No conflicting patterns.
Decomposition Assessment
Per project convention ("Stop decomposing; write inclusive tickets, review them whole"), this 8-point inclusive ticket is accepted as-is. The 13 ACs form a cohesive feature (CRM pipeline) rather than unrelated concerns. An agent can implement search/filter, detail view, and promotion as a single coherent pass since they share the same controller, model scope, and view directory.
Previous Review Issues — Resolution Status
- File target namespace mismatch — FIXED. All paths now use top-level convention matching existing stub.
- PaperTrail not in Gemfile — FIXED. Explicitly listed in File Targets.
- Appointments model dependency — FIXED. Dependencies section added with graceful handling. ACs use conditional language.
- Keycloak promotion API — FIXED. Constraints and file targets now specify realm-role-mapping endpoint precisely.
- Decomposition suggested — NOT decomposing per project convention. Accepted.
Recommendation
[SCOPE]Add "crm" row to project-iss user-stories table: Key=crm, Backing=Epic 7 (US-7.1–7.3), Role=Admin, Success metric="Searchable pipeline; lead→client promotion with audit"[SCOPE]Create architecture note arch-rails (systemic gap — affects many board items, not just this ticket)
Neither [SCOPE] item blocks implementation. The ticket body is complete and actionable.
-
Review: Live DM messaging: real-time client-admin threads
review-1825-2026-07-18bVerdict: NEEDS_REFINEMENT
Re-review after full rewrite. The ticket is now correctly scoped as a delta (controller-level lead blocking). One critical AC issue remains that would block an implementing agent.
Template Completeness
- [x] Type — Feature
- [x] Lineage — delta on #40 + #42
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag — None (correct, this is a security gate)
- [x] Acceptance Criteria — 4 items
- [x] Test Expectations — 4 items + run command
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:messaging label — verified in project-iss user-stories section (Epic 4, US-4.1–4.2)
- [ ] arch note MISSING — [SCOPE] No
arch-railsnote found in pal-e-docs. However,arch:railsis a framework-level label used across many tickets; a dedicated note is acceptable to defer. - [x] Forgejo issue — ldraney/intelligentstaffingsystems#55, state: open
File Targets
- [x]
app/controllers/messages_controller.rb— verified: 103 lines, no lead-blocking guard exists. Usescurrent_user_has_role?("admin")pattern. An existingrestrict_to_rolesclass method in ApplicationController (line 26) provides the same pattern. - [x]
test/controllers/messages_controller_test.rb— verified: 375 lines, 40 test methods. Contains 22 tests usingsign_in_as :leadthat assert successful access (200 OK, message content, forms, etc.).
Repo Placement
OK — issue filed in ldraney/intelligentstaffingsystems, all targets are in that repo.
Dependencies
- #40 Message CRUD — done (board item 1817)
- #42 Turbo Streams live delivery — done (board item 1818)
- No active blockers. All upstream work is complete.
Acceptance Criteria
CRITICAL: AC #4 is contradictory and would block implementation.
AC #4 states: "Existing 49 message tests still pass (no regressions)." However:
- The test file has 40 test methods (not 49)
- 22 of those 40 tests use
sign_in_as :leadand assert successful access (200, content rendering, form presence, turbo streams, etc.) - Adding a
before_actionthat redirects leads will cause all 22 to fail with 302 instead of 200 - An implementing agent following AC #4 literally would be stuck in an impossible state — it cannot both block leads AND keep lead-success tests passing
AC #1–3 are clear and testable. The Test Expectations section correctly specifies new redirect tests but does not acknowledge that existing lead tests must be rewritten.
Blast Radius
docs/messaging.mdline 1 says "At the controller level, both leads and clients can access their own thread" — must be updated (ticket's Related section acknowledges this)docs/security.mdreferences the controller role map — would need updating- No other controllers use the same pattern for leads — the change is isolated to MessagesController
- The existing
restrict_to_rolesmethod in ApplicationController could be reused instead of a customrequire_client_or_admin
Decomposition Assessment
2 file targets in 1 repo, 4 AC. The actual work (1 before_action + test rewrites) fits in a single agent pass well under 5 minutes. No decomposition needed.
Recommendation
[BODY]Replace AC #4 with: "Lead-role tests in messages_controller_test.rb rewritten to assert redirect (22 tests converted from success assertions to 302 redirect assertions); client and admin tests unchanged (no regressions in non-lead tests)"[BODY]Fix test count: file has 40 test methods, not 49[BODY]Add to Test Expectations: "Rewrite existing lead tests (sign_in_as :lead) to assert 302 redirect to /communications. Convert tests that verify lead-specific rendering (compose form, turbo streams, etc.) to use client role instead."
-
Review: Communications tab (admin): incoming management
review-1827-2026-07-18-bVerdict: READY
RE-REVIEW. All previously flagged blockers have been resolved. Traceability gaps are known and low-priority.
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] Dependencies
- [x] File Targets
- [x] Feature Flag (None)
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:communications label present
- [ ] story note MISSING from project-iss user-stories table — however, US-5.4 in repo docs/user-stories.md covers this exactly. Known low-priority gap; story IS documented in-repo.
- [x] arch:rails label present
- [ ] arch note MISSING — no arch-rails note in pal-e-docs. Known low-priority gap; arch:rails is a technology label used across dozens of tickets, not a novel component.
- [x] Forgejo issue — #57 open, valid
File Targets
- [x] app/controllers/communications_controller.rb — verified: admin branch renders :admin_index (line 16), data loading to be fleshed out
- [x] app/views/communications/admin_index.html.erb — verified: exists as placeholder, references ticket #57
- [x] app/views/communications/_inbox_card.html.erb — new partial (to be created), no conflict
- [x] app/assets/stylesheets/communications.css — verified: exists with lead/client card styles, inbox styles to be added
Repo Placement
OK. Single repo (ldraney/intelligentstaffingsystems). Forgejo issue filed on same repo.
Dependencies
- #54 (Appointment scheduling) — documented in Dependencies section. Board item #1824 in backlog. ACs properly make appointment display optional/graceful.
- #55 (Live DM) — listed in Related. Not a blocker: Message model and messages inbox already exist on main.
- #52 (Communications lead/client) — done (board item #1822). Provides the route and controller branching this ticket extends.
Acceptance Criteria
8 ACs, all testable by an agent. Role-based rendering (AC1, AC8) verifiable via endpoint tests with stubbed sessions. Filter behavior (AC4) properly conditioned on Appointment model existence. Quick actions (AC5-7) are link presence checks. Sort order (AC2) testable via fixture ordering. No ambiguity.
Blast Radius
Existing messages/inbox.html.erb provides admin DM thread list. This ticket adds a higher-level unified view. Constraint "Must not duplicate DM thread UI" plus "link to those controllers" correctly delineates boundary. No collision risk — communications admin_index aggregates; messages inbox drills into DM threads.
Decomposition Assessment
4 file targets in 1 repo, 8 ACs (all related view/controller work), estimated agent time well under 5 minutes. No decomposition needed.
Recommendation
No action needed. Ticket is ready for implementation.
Previous Review Issues — Resolution Status
- [x] File target mismatch (inbox.html.erb vs admin_index.html.erb) — FIXED: now targets existing admin_index.html.erb
- [x] Dependency on #54 for appointment data — FIXED: Dependencies section added, ACs graceful/optional
- [x] Traceability gaps — acknowledged known low-priority gaps, not blocking
-
Review: Appointment scheduling: 24hr advance, text and attachments (re-review)
review-1824-2026-07-18-v2Verdict: APPROVED
Re-review after body refinements. All three [BODY] issues from review-1824-2026-07-18 are resolved.
Template Completeness
- [x] ### Type — Feature
- [x] ### Lineage — Related to #15
- [x] ### Repo — ldraney/intelligentstaffingsystems
- [x] ### User Story — As a lead or client...
- [x] ### Context — Clear background on 24hr rule and scheduling flow
- [x] ### File Targets — 7 files to create/modify, 2 files to remove, 1 exclusion
- [x] ### Feature Flag — None (core workflow, acceptable)
- [x] ### Acceptance Criteria — 10 items, all testable
- [x] ### Test Expectations — 9 items + run command
- [x] ### Constraints — 4 items (server-side enforcement, session-based lead_id, ActiveStorage, strong params)
- [x] ### Checklist — Present
- [x] ### Related — Present (project-iss, #15, #52)
Traceability
- [x] story:communications label — present on board item
- [ ] story note — "communications" not listed in project-iss user-stories section. Known gap (3 board items use this key, including done item #1822). [SCOPE] Register "communications" story key on project-iss or map to existing "messaging" (Epic 4).
- [x] arch:rails label — present on board item
- [ ] arch note — arch-rails note does not exist. Known systemic gap across ISS tickets. [SCOPE] Create architecture note arch-rails.
- [x] Forgejo issue — #54, open
File Targets
- [x]
app/controllers/appointments_controller.rb— verified: does not exist, to be created - [x]
app/views/appointments/new.html.erb— verified: does not exist, to be created - [x]
app/views/appointments/_confirmation.html.erb— verified: does not exist, to be created - [x]
app/models/appointment.rb— verified: does not exist, to be created. Lead model exists for FK reference. - [x]
app/assets/stylesheets/appointments.css— verified: does not exist, to be created (matches existing convention) - [x]
db/migrate/XXX_create_appointments.rb— verified: correctly specifies CREATE TABLE with lead_id, scheduled_at, topic, notes, status (previous review fix confirmed) - [x]
config/routes.rb— verified: placeholderget "booking", to: "leads#booking"exists at line 7 (previous review fix confirmed — now in File Targets) - [x]
app/controllers/leads_controller.rb— verified: booking action at line 31 (listed in "Files to remove") - [x]
app/views/leads/booking.html.erb— verified: exists (listed in "Files to remove") - [x]
app/controllers/communications_controller.rb— correctly excluded (button linking to booking_path already exists in _contact_cards.html.erb:50)
Repo Placement
OK — single-repo change in ldraney/intelligentstaffingsystems. All file targets are in this repo.
Dependencies
- #52 (Communications tab, board item #1822) — DONE. The "Set an Appointment" button exists in _contact_cards.html.erb linking to booking_path. Dependency satisfied.
- #15 (Appointment booking and calendar) — Lineage reference. This ticket implements what #15 originally scoped.
- ActiveStorage — configured (migration 20260706183426_create_active_storage_tables exists). No blocker.
- Lead model — exists at app/models/lead.rb. FK target confirmed.
- No in_progress items block this ticket.
Acceptance Criteria
All 10 criteria are testable by an agent. Test expectations align well (9 test cases covering auth, validation, happy path, attachments). Run command is specific and correct.
Blast Radius
app/controllers/leads_controller.rbline 23 — redirects tobooking_pathafter lead creation. Implementing agent should keepbooking_pathas a named route alias (e.g.get "booking", to: "appointments#new", as: :booking) or update this redirect.app/views/communications/_contact_cards.html.erbline 50 — usesbooking_path. Same route alias concern.test/controllers/leads_controller_test.rblines 32, 79-80 — tests booking redirect and placeholder. Need update/removal.test/controllers/communications_controller_test.rbline 114 — tests appointment card links to booking_path.- Assessment: a route alias preserves backward compatibility. The implementing agent will naturally handle this when they see the codebase. Not a scope gap — standard Rails refactoring.
Decomposition Assessment
7 file targets + 2 removals in 1 repo. 10 acceptance criteria (exceeds 5 threshold). However, all work is cohesive (single controller + model + views + migration + route), user preference is inclusive tickets, and estimated agent time is under 5 minutes. No decomposition needed.
Recommendation
All [BODY] fixes from the previous review are confirmed resolved. Two [SCOPE] items remain as informational carry-forwards (systemic project-level gaps, not blockers):
[SCOPE]Register "communications" story key in project-iss user-stories section (3 board items use it; #1822 already shipped).[SCOPE]Create architecture note arch-rails (systemic gap across all ISS rails tickets).
Neither blocks implementation. Ticket is technically complete, all file targets verified, scope is actionable.
-
Review: Live DM messaging: real-time client-admin threads
review-1825-2026-07-18Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type: Feature
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:messaging label — Epic 4 (US-4.1–4.2), verified in project-iss user-stories section
- [x] story note verified — found in project-iss user-stories table (key: messaging, role: Lead/Client/Admin, metric: "One thread per lead; admin sees all")
- [ ] arch:rails label — arch note MISSING — [SCOPE] Create architecture note arch-rails (note: "rails" is the whole app framework; this may be intentionally broad and not warrant a dedicated arch note)
- [x] Forgejo issue — #55, open
File Targets
- [x]
app/controllers/messages_controller.rb— verified: EXISTS, fully implemented (thread view, admin inbox, create, role-based access, Turbo Stream response) - [x]
app/views/messages/index.html.erb— verified: EXISTS - [x]
app/views/messages/_message.html.erb— verified: EXISTS - [x]
app/views/messages/_form.html.erb— verified: EXISTS - [x]
app/models/message.rb— verified: EXISTS (lead_id FK, sender_sub, body, sent_at; broadcasts_to :lead; scopes) - [x]
app/assets/stylesheets/messages.css— verified: EXISTS - [ ]
app/javascript/controllers/scroll_controller.js— ISSUE: Does not exist at this path. Functionality implemented atapp/javascript/controllers/messages_thread_controller.js(auto-scroll + broadcast alignment) - [x]
config/cable.yml— verified: EXISTS (solid_cable in production, async in dev) - [x]
db/migrate/XXX_create_messages.rb— verified: EXISTS as20260705000003_create_messages.rb
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all targets within same repo.
Dependencies
- #12 "Messaging model and conversation threads" (8pts, sprint:4, decomposed) — parent scope, in backlog
- #40 "Message CRUD (decomp:1792)" — DONE, implements message controller, views, model
- #42 "Turbo Streams live delivery + cable fix (decomp:1792)" — DONE, implements real-time delivery + Action Cable
- #52 Communications tab (sprint:B) — DONE, the DM button linking to messages exists
- #54 (story:communications, sprint:C) — in backlog, may relate
Critical finding: Tickets #40 and #42 (both completed) already implement 95%+ of what #55 describes. The feature is live in the codebase with comprehensive tests (35 controller tests + 14 model tests covering all listed test expectations).
Acceptance Criteria
- [x] Message model: lead_id, sender_sub, body, sent_at — DONE (migration + model exist)
- [x] One thread per client (lead_id is the thread) — DONE
- [x] Client can view their own thread and send messages — DONE + tested
- [x] Admin can view and reply in any client's thread — DONE + tested (inbox + thread view)
- [ ] Lead role blocked from DM endpoint — CONTRADICTS docs/messaging.md which explicitly states: "The controller does not distinguish between the two roles — UI-level gating on the Communications tab prevents leads from reaching the messages route." Existing tests verify leads CAN access messages.
- [x] Real-time delivery via Turbo Streams — DONE + tested
- [x] Solid Cable adapter configured — DONE (production uses solid_cable)
- [x] Message bubbles: sent right (navy), received left (bordered) — DONE + tested
- [x] Auto-scroll to latest message — DONE (messages_thread_controller.js)
- [x] sender_sub set from session — DONE + tested
9 of 10 AC are met. The 1 unmet AC (lead-blocking) contradicts the established architecture in docs/messaging.md.
Blast Radius
Messaging feature is self-contained. Communications controller (not-to-touch) exists separately. Turbo Streams pattern is consistent with existing code. No sibling services affected. If lead-blocking were added at the controller level, it would break existing tests that verify lead access.
Decomposition Assessment
10 acceptance criteria exceeds the 5-AC threshold. However, 9/10 AC are already implemented and tested. The actual remaining work is trivial (either close as done, or resolve the lead-blocking decision). No decomposition needed — the ticket needs SCOPE REDUCTION, not decomposition.
Recommendations
[BODY]The feature is 95%+ implemented by completed tickets #40 and #42. Either close this issue as already done, or rewrite scope to describe ONLY the delta (the lead-blocking decision).[BODY]Fix file path:app/javascript/controllers/scroll_controller.js→app/javascript/controllers/messages_thread_controller.js(already exists with full scroll + alignment functionality).[BODY]AC "Lead role blocked from DM endpoint" contradictsdocs/messaging.mdwhich documents UI-only gating as the intentional architecture. Either update the AC to match the doc, or update the doc if controller-level blocking is actually desired.[SCOPE]Decide whether lead-blocking should be controller-level (contradicts existing doc + tests) or remain UI-only (current implementation). This is a human decision.[SCOPE]arch:rails has no backing note in pal-e-docs. Consider whether a broad "rails" arch note is needed or if the label is acceptable without one.
-
Review: Appointment scheduling: 24hr advance, text and attachments
review-1824-2026-07-18Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] ### Type — Feature
- [x] ### Lineage — Related to #15
- [x] ### Repo — ldraney/intelligentstaffingsystems
- [x] ### User Story — Present (As a lead or client...)
- [x] ### Context — Present, good background
- [x] ### File Targets — Present (6 files to create/modify, 1 exclusion)
- [x] ### Feature Flag — None (acceptable for core workflow)
- [x] ### Acceptance Criteria — Present (10 items)
- [x] ### Test Expectations — Present (9 items + run command)
- [x] ### Constraints — Present (4 items)
- [x] ### Checklist — Present
- [x] ### Related — Present
Traceability
- [x] story:communications label — present on board item
- [ ] story note MISSING — [SCOPE] "communications" is not registered as a story key in project-iss user-stories section. Only "messaging" exists (Epic 4). Create user story entry on project-iss for "communications" or clarify whether this should use story:messaging.
- [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] Search for "arch-rails" returned no results. Known gap (also flagged in review-1820). Create architecture note arch-rails for the Rails component.
- [x] Forgejo issue — #54, open
File Targets
- [x]
app/controllers/appointments_controller.rb— verified: does not exist, to be created (correct) - [x]
app/views/appointments/new.html.erb— verified: does not exist, to be created (correct) - [x]
app/views/appointments/_confirmation.html.erb— verified: does not exist, to be created (correct) - [x]
app/models/appointment.rb— verified: does not exist, to be created (correct) - [x]
app/assets/stylesheets/appointments.css— verified: directory exists, file to be created (correct, matches existing convention) - [ ]
db/migrate/XXX_add_topic_and_attachments_to_appointments.rb— ISSUE: Migration description says "add topic, notes columns if not present" implying ALTER TABLE, but no appointments table exists in schema. Migration should CREATE the full appointments table (id, lead_id, scheduled_at, topic, notes, status, timestamps). - [ ] MISSING:
config/routes.rb— Currently has placeholderget "booking", to: "leads#booking". Must be updated to route to the new appointments controller. Without this, the new controller is unreachable. - [ ] MISSING:
app/controllers/leads_controller.rb— Thebookingaction (line 31) becomes dead code after route change. Should be addressed (remove or redirect). - [ ] MISSING:
app/views/leads/booking.html.erb— Placeholder view ("Appointment booking is coming soon") should be removed after the real implementation ships. - [x]
app/controllers/communications_controller.rb— correctly excluded (button linking to booking_path already exists in _contact_cards.html.erb)
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all file targets are in this repo. Single-repo change.
Dependencies
- #52 (Communications tab, board item #1822) — DONE. The "Set an Appointment" button exists in
_contact_cards.html.erbline 50, linking tobooking_path. Dependency satisfied. - #15 (Appointment booking and calendar) — Referenced in lineage. The current
booking_pathplaceholder was created for #15. This ticket (#54) implements the authenticated booking flow that #15 originally scoped. - ActiveStorage — Already configured (migration
20260706183426_create_active_storage_tablesexists in schema). No blocker. - No in_progress items block this ticket.
Acceptance Criteria
All 10 criteria are testable by an agent. The test expectations align well with the acceptance criteria. The run command is specific:
rails test test/controllers/appointments_controller_test.rb test/models/appointment_test.rb.Minor gap: No AC covers the route change or what happens to the existing
booking_pathplaceholder. An agent implementing this may not realize the route needs updating.Blast Radius
test/controllers/leads_controller_test.rbline 79 — tests the current booking placeholder. Will need removal or update.test/controllers/communications_controller_test.rbline 111 — tests that appointment card links tobooking_path. If the route name changes frombooking_pathto e.g.new_appointment_path, this test breaks.app/controllers/leads_controller.rbline 23 — redirects tobooking_pathafter lead creation. If route name changes, this redirect breaks.- Recommendation: keep
booking_pathas an alias or redirect to minimize blast radius.
Decomposition Assessment
6 file targets in 1 repo. 10 acceptance criteria (exceeds 5 threshold). However, all work is cohesive (single controller + model + views + migration), and the user preference is to keep tickets inclusive. No decomposition needed — single agent pass is feasible given the cohesive scope.
Recommendation
[BODY]Addconfig/routes.rbto File Targets — replace placeholderget "booking", to: "leads#booking"with appointment resource routes. Recommend keepingbooking_pathas a named route alias to avoid blast radius on existing tests and redirects.[BODY]Addapp/controllers/leads_controller.rbandapp/views/leads/booking.html.erbto File Targets (cleanup of dead placeholder code).[BODY]Fix migration description — change "add topic, notes columns if not present" to "create appointments table with lead_id, scheduled_at, topic, notes, status columns".[SCOPE]Register "communications" as a story key in project-iss user-stories section, or reclassify as story:messaging if the Communications tab falls under Epic 4.[SCOPE]Create architecture note arch-rails for the Rails component (known gap, applies to many ISS tickets).
-
Review: Fix TLS cert for dev.intelligentstaffingsystems.ai + deploy register.ftl to Keycloak configmap
review-1886-2026-07-18Verdict: APPROVED
Re-review after refinement. Previous review (NEEDS_REFINEMENT) flagged [BODY] issues with file targets and repo section. All [BODY] fixes have been applied. Ticket is now actionable for agent execution.
Template Completeness
- [x] Type — present (Bug, matches board label type:bug)
- [x] Lineage — present (blocks #86, #79, #59)
- [x] Repo — present (ldraney/pal-e-platform — correct)
- [ ] What Broke — MISSING (bug template section; "Context" section covers this with MORE detail)
- [ ] Repro Steps — MISSING (bug template section; Context provides root cause directly)
- [ ] Expected Behavior — MISSING (bug template section; implied by AC)
- [ ] Environment — MISSING (bug template section; prod cluster details in Context)
- [x] Context — present (feature template section, effectively replaces What Broke + Environment with superior detail)
- [x] User Story — present
- [x] File Targets — present (CORRECTED from previous review)
- [x] Acceptance Criteria — present (3 clear, testable criteria)
- [x] Constraints — present (includes source file location and deployment notes)
- [x] Test Expectations — present
- [x] Related — present
Note: Issue uses hybrid Feature/Bug template format. Content is MORE comprehensive and actionable than a strict bug template would be. Template mismatch is cosmetic — does not impede agent execution.
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section (Key: project-setup, Backing: README + docs/architecture.md + docs/adoption-plan.md, Role: Developer)
- [ ] arch:infra — arch note MISSING — [SCOPE] Create architecture note arch-infra (systemic gap, non-blocking)
- [ ] arch:auth — arch note MISSING — [SCOPE] Create architecture note arch-auth (systemic gap, non-blocking)
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/98, open
File Targets
- [x]
pal-e-platform/terraform/modules/keycloak/main.tf(lines 77-88) — verified by previous review: configmap resource exists with login.css, logo.svg, theme.properties entries - [x]
pal-e-platform/salt/pillar/caddy.sls— verified by previous review: containsdomain: dev.intelligentstaffingsystems.ai - [x] Source:
intelligentstaffingsystems/keycloak-theme/iss/login/register.ftl— verified: FreeMarker template with phone field (user.attributes.phone) - [x] Source:
intelligentstaffingsystems/keycloak-theme/iss/login/resources/css/register.css— verified: phone input styling for registration page - [x] "Files agent should NOT touch" section correctly excludes ISS Rails app, pal-e-deployments, and DNS records
Repo Placement
CORRECT. Issue filed in ldraney/intelligentstaffingsystems as a cross-cutting project issue. Repo section correctly identifies
ldraney/pal-e-platformas the target for all changes. No pal-e-deployments reference (corrected from previous review). PRs go against pal-e-platform only.Dependencies
- Blocks validation of #86 (dev environment) — board item 1876, validation column
- Blocks validation of #79 (dev domain DNS/Caddy) — board item 1870, validation column
- Blocks validation of #59 (registration flow) — board item 1831, validation column
- Related completed work: #17 (Keycloak login theme), platform#541 (deploy ISS theme), svc#184 (realm config) — all in done column
Dependencies well-documented. Critical-path bug blocking 3 tickets from reaching done.
Acceptance Criteria
3 AC — all verifiable by agent with kubectl and curl access:
curl -v https://dev.intelligentstaffingsystems.ai— TLS handshake + HTTP 200- Registration page renders ISS-branded form with phone field — verifiable via browser or curl to Keycloak URL
kubectl get configmap keycloak-iss-theme -n keycloak -o yaml— shows register.ftl content
Clear, testable, appropriately scoped. No missing criteria.
Blast Radius
- Caddy TLS: scoped to dev.intelligentstaffingsystems.ai only. Production domain and other vhosts unaffected.
- Configmap: adding register.ftl/register.css to existing ISS theme configmap. Login page theme unaffected (login.css, logo.svg, theme.properties remain unchanged).
- Keycloak theme cache disabled — configmap update takes effect without pod restart.
- No downstream consumers beyond the three blocked validation tickets.
Decomposition Assessment
2 file targets in 1 repo (pal-e-platform). 3 AC. Estimated agent time: <5 minutes (add configmap entries, apply Terraform, restart Caddy via Salt). No decomposition needed.
Recommendations
[SCOPE]Create architecture note arch-infra for component infra (systemic gap — non-blocking for execution)[SCOPE]Create architecture note arch-auth for component auth (systemic gap — non-blocking for execution)
All [BODY] issues from previous review have been resolved. Ticket is APPROVED for agent execution.
-
Review R3: feat: dev environment -- ephemeral DB, shared Keycloak, dev URL, migration practices, port convention
review-1876-r3-2026-07-17Verdict: READY
Re-review (round 3). Previous verdicts:
review-1876-2026-07-18NEEDS_REFINEMENT (two arch note gaps),review-1876-2026-07-17READY (project owner override). This round confirms the gaps are genuinely resolved -- arch notes now exist, and the dependency blocker (#85) is closed.Template Completeness
- [x] Type -- "Feature"
- [x] Lineage -- Standalone, identified during Sprint B validation
- [x] Repo -- ldraney/intelligentstaffingsystems (primary) + 3 cross-repo references (pal-e-deployments, pal-e-platform, pal-e-services)
- [x] Dependencies -- #85 blocker documented (now resolved -- issue closed)
- [x] User Story -- Well-formed As a / I want / So that
- [x] Context -- Exceptionally thorough: gap analysis of #77 decomposition, current state of every relevant file, five interdependent pillars, platform patterns and SOPs to study
- [x] File Targets -- Detailed table with current state and relevance for 12 ISS-repo files + cross-repo reference table + pal-e-docs SOPs to read
- [x] Feature Flag -- "none -- developer tooling, no user-facing feature"
- [x] Acceptance Criteria -- 14 criteria covering all five pillars
- [x] Test Expectations -- Manual verification approach (correct for dev tooling), existing tests must pass unchanged
- [x] Constraints -- 7 constraints including explicit "do not decompose" directive
- [x] Checklist -- 14 items
- [x] Related -- Comprehensive cross-references to parent/child/sibling tickets and SOPs
All required sections for a Feature template are present and complete.
Traceability
- [x] story:project-setup label -- verified in project-iss user-stories section ("Repo, docs, infra, and CI exist; sprints can dispatch")
- [x] story note verified -- found in project-iss user-stories table (key: project-setup, role: Developer)
- [x] arch:rails label -- Rails component
- [x] arch note verified --
arch-deployment-issComponents table includes rails row: "Rails application server (Puma) -- Port 3000 production, 9999 local dev" - [x] arch:infra label -- Infrastructure component
- [x] arch note verified --
arch-deployment-issComponents table includes infra row: "Platform infrastructure (k3s cluster + edge) -- Self-hosted on Hetzner" - [x] Forgejo issue -- ldraney/intelligentstaffingsystems#86, open
Full ISS architecture triplet confirmed:
arch-domain-iss,arch-dataflow-iss,arch-deployment-iss. Both arch label gaps from the original review are resolved.File Targets
- [x]
docker-compose.yml-- verified: port 9999 (line 13 command, line 15 port mapping), no Keycloak service, pgdata volume, harbor base image - [x]
Makefile-- verified: wraps docker compose, targets dev/setup/migrate/seed/test/ci/lint/security/console/logs. No reset target, no environment-specific targets - [x]
Dockerfile-- verified: EXPOSE 3000 (line 26), harbor.tail5b443a.ts.net/library/ruby-rails-build:latest base - [x]
config/puma.rb-- verified:port ENV.fetch("PORT", 3000)at line 32 - [x]
config/database.yml-- verified: dev/test use DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD env vars with rails/rails defaults - [x]
config/initializers/omniauth.rb-- verified: registers Keycloak OIDC when all four KEYCLOAK_* env vars present OR in test mode. Dev without env vars skips middleware entirely. PKCE enforced. - [x]
config/environments/development.rb-- verified:config.action_mailer.default_url_options = { host: "localhost", port: 3000 }at line 41. Port mismatch with docker-compose (9999) confirmed as pre-existing bug. - [x]
config/environments/production.rb-- verified:config.hostsincludesintelligentstaffingsystems.aiandiss.tail5b443a.ts.net(lines 87-88). Nodev.intelligentstaffingsystems.aientry yet. - [x]
db/seeds.rb-- verified: fake keycloak_sub values (admin-dev-sub-001, client-dev-sub-002). 4 Leads, 3 CatalogEntries, sample Message threads. find_or_create_by! pattern is idempotent. - [x]
docs/local-dev-setup.md-- verified: exists, documents current 9999 workflow - [x]
docs/architecture.md-- verified: exists, contains port convention table showing local dev at 9999, production at 3000 - [x]
docs/pipeline.md-- verified: exists, references localhost:9999 in dev workflow section
All 12 ISS-repo file targets verified. Every description of current state in the issue body is accurate.
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems, which is the primary repo. Cross-repo changes (pal-e-deployments, pal-e-platform, pal-e-services) are explicitly identified in both the Repo section and the File Targets cross-repo table. Constraints section mandates separate PRs for cross-repo changes. No mismatch.
Dependencies
- #85 (board item 1875) -- was listed as blocker. Now CLOSED. CI minitest/mock + placeholder k8s secrets resolved. No longer blocks this ticket.
- #77 (board item 1868) -- parent ticket, in todo, marked decomposed. Its decomposition children (#78, #79, #80) are in validation/done. This ticket fills the gap that #77's decomposition missed.
- #78 (board item 1869) -- kustomize overlays, in validation. Placeholder secrets issue was tied to #85 (now resolved).
- #79 (board item 1870) -- dev DNS + Caddy, in validation. Terraform apply still pending. This ticket picks up that remaining work.
- #80 (board item 1871) -- Makefile + docker-compose, in done.
- No undocumented dependencies found.
Acceptance Criteria
14 criteria, all verifiable. Manual verification is appropriate for developer tooling (criteria 1-5, 10-11). Code-verifiable criteria cover Keycloak redirect URIs (6), config.hosts (7), port convention docs (8), mailer URL (9), test suite (12), Makefile (13), cross-repo PRs (14). Comprehensive coverage of all five pillars. No missing criteria identified.
Blast Radius
Port 9999 is referenced in 10+ locations: docker-compose.yml, Makefile, README.md, docs/architecture.md, docs/pipeline.md (3 references), docs/local-dev-setup.md (4 references). If port changes, all must be updated. The ticket is aware of this scope.
The mailer URL mismatch (development.rb says 3000, docker-compose runs 9999) is a pre-existing bug that this ticket would fix as a side effect of resolving the port convention.
Keycloak redirect URI changes in pal-e-services affect the ISS realm only, not other clients. CORS implications are noted in the ticket.
No similar patterns in sibling services that would be affected -- this is ISS-specific dev environment work.
Decomposition Assessment
By metrics: 12 file targets across 4 repos, 14 acceptance criteria. Technically exceeds decomposition thresholds. However: the ticket explicitly forbids decomposition with detailed rationale (all five pillars are interdependent -- port convention affects Keycloak redirect URIs, seed data depends on Keycloak strategy, dev URL needs correct port and Keycloak callback, migration docs reflect actual topology). User standing preference: "stop decomposing; write inclusive tickets." Cross-repo work is separated into distinct PRs per constraints. The 8-point sizing is appropriate. No decomposition needed.
Recommendation
No action needed.
Both gaps from the original review (review-1876-2026-07-18) are now genuinely resolved:
arch:rails-- backed byarch-deployment-issComponents table (rails row)arch:infra-- backed byarch-deployment-issComponents table (infra row)
The dependency blocker (#85) is closed. The ticket is exceptionally well-scoped with accurate file target descriptions, comprehensive acceptance criteria, and clear implementation guidance without being prescriptive. Ready for implementation.
-
Review: dev environment -- ephemeral DB, shared Keycloak, dev URL, migration practices, port convention
review-1876-2026-07-18Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- "Feature"
- [x] Lineage -- Standalone, identified during Sprint B validation
- [x] Repo -- ldraney/intelligentstaffingsystems (primary) + 3 cross-repo references
- [x] Dependencies -- #85 blocker clearly documented
- [x] User Story -- Well-formed As a / I want / So that
- [x] Context -- Exceptionally thorough: explains what was attempted (#77 decomposition), what fell short, current state of every relevant file, five interconnected pillars, platform patterns to study
- [x] File Targets -- Detailed table with current state and relevance for 12 ISS-repo files + cross-repo reference table + pal-e-docs SOPs
- [x] Feature Flag -- "none -- developer tooling, no user-facing feature"
- [x] Acceptance Criteria -- 14 criteria
- [x] Test Expectations -- Manual verification approach (correct for dev tooling)
- [x] Constraints -- 7 constraints including explicit "do not decompose" directive
- [x] Checklist -- 14 items
- [x] Related -- Comprehensive cross-references to parent/child/sibling tickets and SOPs
All required sections for a Feature template are present and well-written.
Traceability
- [x] story:project-setup label -- "Repo, docs, infra, and CI exist; sprints can dispatch"
- [x] story note verified -- found in project-iss user-stories section (key: project-setup, role: Developer)
- [x] arch:rails label -- Rails component
- [ ] arch note MISSING -- [SCOPE] No
arch-railsnote exists in pal-e-docs. Anarch-rails-appnote exists under pal-enterprises but does not match the label exactly. Create architecture notearch-railsor align label toarch:rails-app. - [x] arch:infra label -- Infrastructure component
- [ ] arch note MISSING -- [SCOPE] No
arch-infranote exists in pal-e-docs. This is a known systemic gap flagged across multiple projects (iss, paldocs, landscaping-assistant). Create architecture notearch-infrafor the platform infrastructure component. - [x] Forgejo issue -- ldraney/intelligentstaffingsystems#86, open
File Targets
- [x]
docker-compose.yml-- verified: port 9999, no Keycloak service, pgdata volume, harbor base image. All claims accurate. - [x]
Makefile-- verified: wraps docker compose, targets include dev/setup/migrate/seed/test/ci/logs/console/lint/security. No environment-specific targets. All claims accurate. - [x]
Dockerfile-- verified: production image, EXPOSE 3000, harbor.tail5b443a.ts.net/library/ruby-rails-build:latest base. - [x]
config/puma.rb-- verified:port ENV.fetch("PORT", 3000)at line 32. - [x]
config/database.yml-- verified: dev/test use DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD env vars with rails/rails defaults. - [x]
config/initializers/omniauth.rb-- verified: registers Keycloak OIDC provider only when all KEYCLOAK_* env vars present OR in test mode. Dev without env vars skips middleware entirely. - [x]
config/environments/development.rb-- verified:config.action_mailer.default_url_options = { host: "localhost", port: 3000 }at line 41. Port mismatch with docker-compose (9999) confirmed. - [x]
config/environments/production.rb-- verified:config.hostshasintelligentstaffingsystems.aiandiss.tail5b443a.ts.net. Nodev.intelligentstaffingsystems.aientry yet. - [x]
db/seeds.rb-- verified: fake keycloak_sub values (admin-dev-sub-001, client-dev-sub-002, etc.). 4 Leads, 3 CatalogEntries, sample Message threads. - [x]
docs/local-dev-setup.md-- verified: exists, documents current 9999 workflow. - [x]
docs/architecture.md-- verified: exists, contains port convention table showing local dev at 9999. - [x]
docs/pipeline.md-- verified: exists, references localhost:9999 in dev workflow section. - [x]
test/test_helper.rb-- verified: OmniAuth.config.test_mode = true, sign_in_as helper with fake subs (kc-sub-lead, etc.).
All 13 file targets exist and all described current states are accurate.
Repo Placement
OK. Issue is filed on ldraney/intelligentstaffingsystems, which is the primary repo. Cross-repo changes (pal-e-deployments, pal-e-platform, pal-e-services) are explicitly identified and the Constraints section mandates separate PRs for each. No mismatch.
Dependencies
- #85 (board item #1875) -- listed as blocker. Currently in
validationcolumn (merged, not yet validated). The k8s secrets and CI pipeline must be confirmed working before dev environment changes can be validated against production. Dependency is correctly documented. - #77 (board item #1868) -- parent ticket, in
todocolumn, markeddecomposed. Its decomposition children (#78, #79, #80) are in validation/done. This ticket (#86) fills the gap that #77's decomposition missed. - #78 (board item #1869) -- kustomize overlays, in
validation. Placeholder secrets noted. - #79 (board item #1870) -- dev DNS + Caddy, in
validation. Terraform apply pending. - #80 (board item #1871) -- Makefile + docker-compose, in
done. - No undocumented dependencies found.
Acceptance Criteria
14 criteria, all testable. Criteria 1-3, 4-5, and 12 require manual verification, which is appropriate for developer tooling. Criteria 6-9 and 11 are code-verifiable. Criterion 14 (cross-repo PRs) is verifiable via Forgejo.
The criteria are comprehensive and cover all five pillars. One potential gap: no criterion explicitly verifies that OmniAuth test mode is not used in dev when Keycloak env vars are present (i.e., that the developer truly gets real auth, not mocked auth). Criterion 1 implies this but does not make it explicit. This is minor.
Blast Radius
Port 9999 is referenced in 10+ locations across docker-compose.yml, Makefile, README.md, docs/architecture.md, docs/pipeline.md, docs/local-dev-setup.md. If the port changes, all must be updated. The ticket is aware of this scope.
The mailer URL mismatch (development.rb says 3000, docker-compose runs 9999) is a pre-existing bug that this ticket would fix as a side effect of resolving the port convention. No downstream consumers beyond the ISS app itself.
Keycloak redirect URI changes in pal-e-services affect the ISS realm only, not other clients. CORS implications are noted in the ticket.
Decomposition Assessment
By the 5-minute rule: 13 file targets across 4 repos, 14 acceptance criteria, estimated agent work well over 5 minutes. This ticket technically exceeds all three decomposition thresholds.
However: the ticket explicitly forbids decomposition in its Constraints section with a reasoned argument that the five pillars are interdependent. The user's standing preference is "stop decomposing; write inclusive tickets." The cross-repo work is separated into distinct PRs per the constraints. Within the ISS repo, the changes are cohesive -- port convention affects Keycloak redirect URIs, which affect seed data strategy, which affects the dev URL, etc.
No decomposition recommended. The 8-point sizing is appropriate for the scope.
Recommendations
[SCOPE]Create architecture notearch-railsin pal-e-docs for the Rails component (or align the board label to the existingarch-rails-appnote). This is a systemic platform gap, not specific to this ticket.[SCOPE]Create architecture notearch-infrain pal-e-docs for the infrastructure component. Also a systemic gap flagged across multiple projects.
-
Review: feat: dev environment -- ephemeral DB, shared Keycloak, migration practices, port convention
review-1876-2026-07-17Verdict: READY
Re-review. Previous verdict was NEEDS_REFINEMENT. All prior findings resolved or overridden by project owner.
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, identified during Sprint B validation
- [x] Repo — ldraney/intelligentstaffingsystems (primary), cross-repo identified
- [x] Dependencies — #85 blocker documented
- [x] User Story — full As-a/I-want/So-that format
- [x] Context — exceptionally detailed: gap analysis, prior attempts (#77 decomposition), current file state, five interdependent pillars, platform patterns to study
- [x] File Targets — 12 ISS files in table format with current state and relevance; cross-repo files in separate table; SOPs identified
- [x] Feature Flag — none (developer tooling, no user-facing feature)
- [x] Acceptance Criteria — 14 criteria
- [x] Test Expectations — existing tests must pass unchanged, manual verification steps documented
- [x] Constraints — 7 constraints including no decomposition, no separate dev Keycloak, no hardcoded secrets
- [x] Checklist — 14 items
- [x] Related — #85 blocker, #77/#78/#79/#80 lineage, #6/#4 auth integration history, SOPs
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section ("Repo, docs, infra, and CI exist; sprints can dispatch")
- [x] arch:rails label — present. Arch note missing in pal-e-docs — PROJECT OWNER OVERRIDE: process gap, not a ticket issue
- [x] arch:infra label — present. Arch note missing in pal-e-docs — PROJECT OWNER OVERRIDE: process gap, not a ticket issue
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/86, open
File Targets
- [x] docker-compose.yml — verified: port 9999 on lines 13/15, no Keycloak service, pgdata volume
- [x] Makefile — verified: wraps docker compose, targets dev/setup/migrate/seed/test/ci/lint/security, no reset target, no environment-specific targets
- [x] Dockerfile — verified: EXPOSE 3000 on line 26, uses harbor.tail5b443a.ts.net base
- [x] config/puma.rb — verified: port ENV.fetch("PORT", 3000) on line 32
- [x] config/database.yml — verified: DATABASE_HOST/USER/PASSWORD env vars with rails/rails defaults
- [x] config/initializers/omniauth.rb — verified: registers Keycloak OIDC when KEYCLOAK_URL/REALM/CLIENT_ID/CLIENT_SECRET all present
- [x] config/environments/development.rb — verified: mailer default_url_options localhost:3000 (port mismatch with docker-compose 9999 confirmed)
- [x] config/environments/production.rb — verified: config.hosts includes intelligentstaffingsystems.ai and iss.tail5b443a.ts.net
- [x] db/seeds.rb — verified: fake keycloak_sub values (admin-dev-sub-001, client-dev-sub-002)
- [x] docs/local-dev-setup.md — verified: exists
- [x] docs/architecture.md — verified: exists
- [x] docs/pipeline.md — verified: exists
- [x] test/test_helper.rb — verified: OmniAuth test_mode true, sign_in_as with fake subs (kc-sub-lead, etc.)
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems (primary repo). Cross-repo work explicitly identified: pal-e-deployments (overlay restructuring), pal-e-platform (terraform apply for DNS/Caddy), pal-e-services (Keycloak redirect URIs). Constraints section requires separate PRs for cross-repo changes.
Dependencies
- #85 (board item 1875) — blocker, currently in backlog. CI minitest/mock + placeholder k8s secrets must be resolved first. Documented in issue Dependencies section.
- #77 (board item 1868) — parent ticket, in todo. Decomposed into #78/#79/#80 which are all done or validated. This ticket fills the gap those didn't cover.
- #79 — terraform apply for dev DNS still pending. This ticket picks up that remaining work.
Acceptance Criteria
14 criteria. All are verifiable. Most require manual verification (login with real Keycloak, mobile testing via dev URL, database reset workflow), which is acknowledged in the Test Expectations section. One automated criterion: test suite must continue to pass (make test / make ci). Criteria are comprehensive and cover all five pillars. No missing criteria identified.
Blast Radius
Limited to dev tooling — no production code changes beyond config.hosts addition and potential port convention alignment. Cross-repo blast radius is well-identified: Keycloak redirect URIs, DNS/Caddy config, kustomize overlays. The existing test suite is explicitly protected (constraint: "Do not break the test suite"). No similar patterns in sibling services that would be affected — this is ISS-specific dev environment work.
Decomposition Assessment
PROJECT OWNER OVERRIDE: The ticket explicitly states "Do not decompose this ticket" with detailed rationale — all five pillars are interdependent (port convention affects Keycloak redirect URIs, seed data depends on Keycloak strategy, dev URL needs correct port, migration docs reflect actual topology). The 8-point estimate reflects this scope. Accepted as one atomic unit of work.
Recommendation
No action needed.
This is an exceptionally well-scoped ticket. Every file target claim was verified accurate against the codebase. The context section provides comprehensive background including what was attempted before and why it fell short. The five-pillar structure gives the implementer a clear mental model without prescribing specific solutions. Platform SOPs and reference implementations are identified for study.
-
Review: CI minitest/mock LoadError + placeholder k8s secrets + action_mailer example.com (re-review)
review-1875-2026-07-17-v2Verdict: APPROVED
Re-review of #85. Previous review returned NEEDS_REFINEMENT. All issues have been addressed in the updated issue body. Ticket is ready for implementation.
Template Completeness
- [x] Type — Bug
- [x] Lineage — Standalone, discovered during Sprint B validation sweep
- [x] Repo — Both repos listed (intelligentstaffingsystems + pal-e-deployments)
- [x] What Broke — Three issues described with detail and error messages
- [x] Repro Steps — Provided for all three bugs
- [x] Expected Behavior — Present
- [x] Environment — Present, includes Ruby version note and minitest version
- [x] Acceptance Criteria — 9 criteria, all verifiable
- [x] Related — Present with cross-references
- [x] Production Risk — Bonus section, documents critical ordering constraint
- [x] Validation Evidence — Bonus section, lists 7 blocked validation tickets
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section
- [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] No
arch-railsnote found in pal-e-docs. Low priority for unplanned bug fix. - [x] arch:infra label — present on board item
- [ ] arch note MISSING — [SCOPE] No
arch-infranote found in pal-e-docs. Low priority for unplanned bug fix. - [x] Forgejo issue — #85, open
File Targets
- [x]
test/test_helper.rb:4— verified:require "minitest/mock"present at line 4 - [x]
test/models/message_test.rb:141— verified:Turbo::StreamsChannel.stub(:broadcast_action_later_to, stub)uses minitest/mock stub method - [x]
Gemfile— verified: no explicitgem "minitest"declaration - [x]
Gemfile.lock— verified:minitest (6.0.6)present as transitive dep of activesupport (line 176) - [x]
config/environments/production.rb:60— verified:config.action_mailer.default_url_options = { host: "example.com" } - [x] Commit
7073cae— verified: "fix: resolve 3 Messages test failures blocking CI (#75) (#76)" — correct PR #76 reference
Repo Placement
Cross-repo fix documented correctly. Issue filed on
intelligentstaffingsystems(primary), touches:intelligentstaffingsystems— CI fix (Gemfile or gem path) + action_mailer fixpal-e-deployments— k8s secrets fix
Both repos listed under
### Repo. Single-ticket approach justified by project owner: fixing CI without fixing secrets = production outage.Dependencies
- #86 (dev environment, sprint:C) — explicitly blocked by this ticket per issue body
- #71 (action_mailer example.com) — absorbed into this ticket; board item #1867 exists separately in backlog
- 7 validation-column tickets blocked: #49, #50, #51, #52, #58, #59, #69 — all failed validation due to these blockers
- #77 (deployment overlays) — in todo, related infrastructure work
Dependencies are documented in the issue body.
Acceptance Criteria
9 criteria. All verifiable by an agent:
- AC 1-2: Pipeline status observable via Woodpecker
- AC 3-5: Pod/secret state verifiable via kubectl and argocd CLI
- AC 6: Site liveness verifiable via curl
- AC 7: Deployment verification via git log + argocd
- AC 8: Code inspection (grep for action_mailer host setting)
- AC 9: Grep for example.com in production config
Note on AC 9:
config/environments/production.rbhas 4 additionalexample.comreferences, all in comments (lines 22, 66, 83, 84).config/environments/test.rb:40also usesexample.comfor test environment, which is appropriate. Only line 60 is an active bug.Blast Radius
example.comgrep: Only one active reference in production config (line 60). Four commented-out references are safe. Test environment reference is intentional.- minitest/mock: Only used in
test/models/message_test.rb. No other test files reference it. - k8s secrets: Scoped to the
intelligentstaffingsystemsnamespace. No cross-namespace impact. - The production risk section correctly identifies the critical ordering constraint: secrets must be fixed before or simultaneously with CI.
Decomposition Assessment
9 AC across 2 repos technically exceeds the 5-minute rule thresholds. However, the project owner has explicitly rejected decomposition with sound rationale: the CI fix and secrets fix are causally coupled — fixing CI without fixing secrets triggers a production outage. This is intentionally one ticket. Not flagging decomposition.
Recommendation
[SCOPE]Create architecture notearch-railsfor the Rails component (low priority, not blocking)[SCOPE]Create architecture notearch-infrafor the infrastructure component (low priority, not blocking)
No blocking issues. Previous review findings addressed: root cause explanation corrected (minitest 6.0.6 transitive dep, investigation left to implementer), commit ref fixed (7073cae / PR #76), decomposition rejected by owner, #71 absorption acknowledged.
-
Review: CI minitest/mock LoadError + placeholder k8s secrets block all deployments
review-1875-2026-07-17Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Bug
- [x] Lineage — Standalone, discovered during Sprint B validation sweep (2026-07-17)
- [x] Repo — Two repos identified (intelligentstaffingsystems + pal-e-deployments)
- [x] What Broke — Detailed description of both blockers with error messages
- [x] Repro Steps — Present for both blockers with kubectl commands
- [x] Expected Behavior — Present
- [x] Environment — Present (Woodpecker CI, ArgoCD, k8s, Ruby 3.4)
- [x] Acceptance Criteria — 7 items present
- [x] Related — Present with pipeline number, PR, commit, and blocked tickets
- [x] Production Risk — Extra section, valuable addition documenting ordering constraint
- [x] Validation Evidence — Extra section listing 7 blocked validation tickets
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section
- [ ] arch:rails label — arch note MISSING — [SCOPE] Create architecture note arch-rails for component rails
- [ ] arch:infra label — arch note MISSING — [SCOPE] Create architecture note arch-infra for component infra
- [x] Forgejo issue — ldraney/intelligentstaffingsystems#85, open
File Targets
- [x]
test/test_helper.rbline 4 — verified:require "minitest/mock"present at line 4 - [x]
Gemfile— verified: no explicitgem "minitest"declaration - [x]
Gemfile.lock— note: minitest 6.0.6 IS present as transitive dependency of activesupport. Root cause explanation may need refinement — underbundle exec, transitive deps should resolve. - [x] Commit
93b9a79— verified exists: "fix: align pipeline push repo with Argo CD Image Updater annotation". However, this commit did NOT introduce theminitest/mockrequire — that was added in a later commit. - [x]
minitest/mockusage — verified:stubmethod used intest/models/message_test.rb:141, so the require is needed - [ ]
pal-e-deploymentssecrets manifest — CANNOT verify from this repo. Issue references PR #234 introducing placeholder values.
Repo Placement
Issue correctly identifies two repos:
ldraney/intelligentstaffingsystems(CI fix) andldraney/pal-e-deployments(k8s secrets fix). The Forgejo issue is filed only on intelligentstaffingsystems. No corresponding issue exists on pal-e-deployments for the secrets fix. This is a multi-repo bug that requires separate PRs in each repo.Dependencies
- 7 validation tickets blocked: #49, #50, #51, #52, #58, #59, #69
- Critical ordering constraint: k8s secrets MUST be fixed before CI fix merges to main. If CI fix ships first, ArgoCD will roll out a new pod with broken secrets, replacing the surviving old pod — full production outage.
- Board item 1858 (pal-e-deployments#231, type:bug, done) may be related to deployment issues — verify whether it already addressed secrets.
- Board item 1868 (#77, deployment overlays, todo) is in the same infrastructure area.
Acceptance Criteria
7 criteria — all testable but span multiple systems:
- AC 1-2: CI verification (pipeline pass, build+push) — verifiable via Woodpecker
- AC 3-5: k8s verification (secrets, pods, ArgoCD rollout) — verifiable via kubectl/argocd CLI
- AC 6: Production health (site live) — verifiable via curl/browser
- AC 7: Deployment completeness (8+ commits deployed) — verifiable via version check
AC 7 ("all 8+ undeployed commits deployed") is a consequence of the fix, not a criterion the implementer controls directly. Consider rewording to "verify latest main commit is deployed."
Blast Radius
minitest/mock— only required in test_helper.rb;webmock/minitestalso used in keycloak_admin_service_test.rb (webmock handles its own minitest integration, but benefits from explicit gem declaration)- CI fix unblocks ALL future PRs and deployments — high positive impact
- Secrets fix restores production deployment capability — critical path item
- Other Ruby 3.4 repos on the platform may have the same minitest issue if they use
require "minitest/mock"without an explicit gem declaration — check platform-wide
Decomposition Assessment
NEEDS DECOMPOSITION — triggers on two criteria:
- File targets across 2 repos (intelligentstaffingsystems + pal-e-deployments)
- 7 acceptance criteria spanning CI, k8s, ArgoCD, and production
Recommended split:
- Sub-ticket A (pal-e-deployments): Fix k8s secret
intelligentstaffingsystems-secrets— replace placeholder values with real credentials. AC: secrets contain real values, migrate init container connects, pods start. Must complete first. - Sub-ticket B (intelligentstaffingsystems): Add
gem "minitest"to Gemfile (test group), verify CI passes. AC: test step passes, pipeline completes end-to-end, new image pushed. Depends on Sub-ticket A. - Verification of AC 5-7 (ArgoCD rollout, site live, commits deployed) follows naturally from both fixes landing.
Route to
skill-decompose-ticketfor sub-ticket creation.Recommendation
[SCOPE]Create architecture notearch-railsfor component rails[SCOPE]Create architecture notearch-infrafor component infra[BODY]Refine root cause for Blocker 1: minitest 6.0.6 is in Gemfile.lock as transitive dep of activesupport. Underbundle exec, it should resolve. Adding explicitgem "minitest"is still the correct fix, but the explanation "Ruby 3.4 moved minitest out of the standard library" may not fully explain the CI failure. Verify actual error against CI logs.[BODY]Correct commit reference:93b9a79is "align pipeline push repo," not the commit that introduced theminitest/mockrequire. The require was added in a subsequent commit.[DECOMPOSE]7 AC across 2 repos — split into 2 sub-tickets with ordering constraint (secrets first, then CI fix). Route toskill-decompose-ticket.
-
Review: pal-e-deployments prod/dev kustomize overlays
review-1869-2026-07-17Verdict: READY
Re-reviewed after [BODY] fixes applied. All file target inaccuracies corrected. One non-blocking [SCOPE] recommendation remains (arch-infra note).
Template Completeness
- [x] Type — Feature
- [x] Lineage — Sub-ticket of #77
- [x] Repo — ldraney/pal-e-deployments
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag — none (infrastructure)
- [x] Acceptance Criteria — 5 criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:project-setup label — "Repo, docs, infra, and CI exist; sprints can dispatch"
- [x] story note verified — found in project-iss user-stories section
- [x] arch:infra label — infrastructure component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-infra for infrastructure component. Non-blocking: broad label used across 5+ board items; ticket scope is clear without it.
- [x] Forgejo issue — #78, open
File Targets
- [x]
overlays/landscaping-assistant/prod/— verified: exists with deployment-patch.yaml, kustomization.yaml, secrets.enc.yaml (correct reference pattern) - [x]
overlays/landscaping-assistant/dev/— verified: exists with configmap.yaml, deployment.yaml, ingress.yaml, kustomization.yaml, namespace.yaml, service.yaml - [x]
overlays/dev-tunnel/— verified: exists with kustomization.yaml, configmap.yaml, deployment.yaml, ingress.yaml, namespace.yaml, service.yaml - [x]
bases/standard/— verified: exists with deployment.yaml, hpa.yaml, kustomization.yaml, networkpolicy.yaml, service.yaml, servicemonitor.yaml - [x]
overlays/intelligentstaffingsystems/prod/kustomization.yaml— verified: exists, ticket correctly says "update" - [x]
overlays/intelligentstaffingsystems/prod/deployment-patch.yaml— verified: exists, ticket correctly says "update" - [x]
overlays/intelligentstaffingsystems/prod/secrets.enc.yaml— confirmed: does not exist, ticket correctly says "create" - [x]
overlays/intelligentstaffingsystems/prod/README.md— confirmed: does not exist in prod/ (README exists at overlay root only), ticket correctly says "create" - [x]
overlays/intelligentstaffingsystems/dev/— confirmed: directory does not exist, ticket correctly says "create"
Repo Placement
Issue is filed on
ldraney/intelligentstaffingsystems(#78) but work targetsldraney/pal-e-deployments. This is a decomposed sub-ticket of ISS umbrella #77 — the### Repofield explicitly directs the agent to pal-e-deployments and the Checklist states "PR opened on pal-e-deployments". Acceptable.Dependencies
- Parent: #77 (board item #1868) — in todo column, labeled decomposed
- Siblings: #79 (board item #1870, dev DNS/Caddy vhost), #80 (board item #1871, Makefile improvements) — both in backlog, decomp:1868
- Prior work: #5 (board item #1784) — done, "Deployment overlay in pal-e-deployments" from Sprint 1. This ticket builds on that initial overlay.
- No blockers identified — this ticket can proceed independently of siblings #79 and #80
Acceptance Criteria
5 criteria, all testable.
kustomize buildcommands are real and verifiable. The criteria cover both prod and dev overlays plus README documentation. Clear and agent-executable.Blast Radius
Low. Changes are isolated to
overlays/intelligentstaffingsystems/in pal-e-deployments. No changes to sharedbases/standard/. No downstream consumers affected beyond ArgoCD syncing the ISS deployment.Decomposition Assessment
6 file targets (4 create, 2 update) within a single repo. 5 acceptance criteria. Estimated agent work: ~3-4 minutes (templated file creation following existing patterns). No decomposition needed.
Recommendation
[BODY]Fixed (round 1): replaced nonexistentwestside-rorreference withlandscaping-assistant[BODY]Fixed (round 1): clarified that prod/kustomization.yaml and prod/deployment-patch.yaml already exist from Sprint 1 (#5)[BODY]Fixed (round 1): updated Context and Constraints sections[SCOPE]Non-blocking: Create architecture notearch-infrain pal-e-docs. This label is used across 5+ board items but has no backing note. Recommend creating it as a separate backlog item.
-
Review: ISS Makefile + docker-compose + doc updates
review-1871-2026-07-17Verdict: READY
Template Completeness
- [x] Type — present (Feature)
- [x] Lineage — present (Sub-ticket of #77)
- [x] Repo — present (ldraney/intelligentstaffingsystems)
- [x] User Story — present
- [x] Context — present
- [x] File Targets — present (1 create, 5 modify, 4 exclusions)
- [x] Feature Flag — present (none — developer tooling)
- [x] Acceptance Criteria — present (7 criteria)
- [x] Test Expectations — present (4 expectations + run command)
- [x] Constraints — present (3 constraints)
- [x] Checklist — present (4 items)
- [x] Related — present
Traceability
- [x] story:project-setup label — verified in project-iss user-stories table (key: project-setup, backing: README + docs/architecture.md + docs/adoption-plan.md, role: Developer)
- [x] arch:infra label — acceptable: catch-all label per convention-architecture-ids ("General infrastructure"). No dedicated arch note expected for catch-all labels.
- [x] Forgejo issue — #80, state: open, repo: ldraney/intelligentstaffingsystems
- [x] decomp:1868 label — parent item #1868 (issue #77) exists on board-iss in todo column, labeled decomposed
File Targets
- [x]
Makefile— verified: does not exist yet (to create). Targets: dev, test, lint, security, ci, console, migrate, setup, down. - [x]
docker-compose.yml— verified: exists (696 bytes). Currently runs web on port 9999 via harbor.tail5b443a.ts.net/library/ruby-rails-build:latest image. - [x]
docs/local-dev-setup.md— verified: exists (4.6k). No Makefile references yet. - [x]
docs/architecture.md— verified: exists (15k). To document overlay directories and deployment topology. - [x]
docs/pipeline.md— verified: exists (8.2k). To reference Makefile targets in local dev section. - [x]
config/environments/production.rb— verified: exists. Current config.hosts has intelligentstaffingsystems.ai and iss.tail5b443a.ts.net. dev.intelligentstaffingsystems.ai not yet present (conditional per AC #7).
Repo Placement
OK — Issue filed on ldraney/intelligentstaffingsystems. All file targets are within this repo. Multi-repo concerns (pal-e-deployments overlays, pal-e-platform DNS/Caddy) are correctly scoped to sibling tickets #78 and #79.
Dependencies
- #78 (pal-e-deployments overlays, board item #1869) — independent, no dependency. Makefile and docs work can proceed without overlays existing.
- #79 (DNS + Caddy for dev subdomain, board item #1870) — soft dependency for AC #7 (config.hosts conditional). The ticket correctly uses "if the dev overlay routes through production Rails" qualifier.
- #77 (parent, board item #1868) — in todo column, labeled decomposed. All three sub-tickets (#78, #79, #80) are in backlog.
- Constraints section documents out-of-scope Keycloak callback URL awareness (pal-e-services tfvars change). Good cross-repo awareness.
Acceptance Criteria
7 AC, all agent-verifiable:
- AC 1-4: Makefile targets (make dev/test/ci/setup) — verifiable by execution
- AC 5: No host Ruby — verifiable by inspecting Makefile (docker compose run/exec)
- AC 6: docs/local-dev-setup.md updated — verifiable by reading doc
- AC 7: config.hosts conditional — verifiable by reading production.rb
Test commands are real: rails test, rubocop, brakeman — all confirmed present in .woodpecker.yaml CI pipeline.
Blast Radius
Low. Makefile is new (no existing patterns to conflict). Docker-compose changes are local dev only. Config.hosts addition is additive. Doc updates are additive text. No production runtime changes.
Decomposition Assessment
7 AC exceeds the >5 threshold, but all targets are in 1 repo and the work is a single coherent change (Makefile creation + supporting doc updates). At 2 story points, the ticket is already a leaf node from the #77 decomposition. Further splitting would create artificial boundaries between tightly coupled changes. No decomposition needed.
Recommendation
No action needed. Scope is solid, traceability complete, file targets verified, and the ticket fits comfortably in a single agent pass.
-
Review: feat: deployment overlays, dev environment subdomain, and Makefile (v2)
review-1868-2026-07-17-v2Verdict: APPROVED
Re-review after refinement applied from
review-1868-2026-07-17. All BODY, SCOPE, and DECOMPOSE issues resolved.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, references #3, #4, #5, PR #534; now includes decomposition references (#78, #79, #80)
- [x] Repo -- Multi-repo (3 repos listed, correctly: intelligentstaffingsystems, pal-e-deployments, pal-e-platform)
- [x] User Story -- Developer-focused, well-formed
- [x] Context -- Thorough current state and deliverables, now with sub-ticket cross-references
- [x] File Targets -- Delegated to sub-tickets with per-repo scoping
- [x] Feature Flag -- none (infrastructure, acceptable)
- [x] Acceptance Criteria -- Delegated to sub-tickets (#78: 5 AC, #79: 4 AC, #80: 7 AC)
- [x] Test Expectations -- Delegated to sub-tickets
- [x] Constraints -- 8 items, well-scoped, repo references corrected
- [x] Checklist -- 7 items, includes sub-ticket creation step
- [x] Related -- Comprehensive cross-references including sub-tickets
Traceability
- [x] story:project-setup label -- verified in project-iss user-stories section (Key: project-setup, Backing: "README + docs/architecture.md + docs/adoption-plan.md", Role: Developer)
- [x] arch:infra label -- present on board item 1868
- [x] arch note verified --
arch-infranote exists in pal-e-docs (slug: arch-infra, project: paldocs, covers Hetzner edge, DNS, Caddy, Tailscale funnel pattern used by ISS). Note: v1 review's search missed this note. - [x] Forgejo issue -- #77, open, valid URL
File Targets
File targets are now delegated to sub-tickets. Each sub-ticket's targets are within a single repo:
- [x] #78 (pal-e-deployments) -- 6 files to create + reference patterns. Single repo. Verified:
overlays/westside-ror/prod/andoverlays/westside-ror/dev/exist as reference patterns. - [x] #79 (pal-e-platform) -- 2 files to modify:
terraform/dns.tf,salt/pillar/caddy.sls. Single repo. - [x] #80 (intelligentstaffingsystems) -- 1 file to create (Makefile), 5 files to modify. Single repo.
Repo Placement
FIXED. All references to
ldraney/godaddy-tofureplaced withldraney/pal-e-platform. DNS records correctly placed interraform/dns.tf, Caddy vhosts insalt/pillar/caddy.sls. PR #534 correctly attributed to pal-e-platform. Constraints section correctly states "DNS changes go through pal-e-platform/terraform/ (using the godaddy-tofu provider)".Dependencies
- #3 (Bootstrap Rails app -- done) -- foundation, no blocker
- #4 (Register ISS in pal-e-services -- done) -- created tfvars entry this overlay fulfills
- #5 (Deployment overlay stub -- done) -- original stub, superseded by this ticket
- PR #534 (pal-e-platform, closed) -- wired apex domain, reference for dev subdomain DNS
- #69 (config.hosts DNS rebinding -- validation) -- established the config.hosts pattern; not a blocker
- No blocking dependencies. All foundation work is done.
Acceptance Criteria
Decomposed into sub-tickets with per-scope AC:
- #78: 5 AC (overlay existence, kustomize build, mermaid READMEs) -- all testable by agent
- #79: 4 AC (DNS record, Caddy vhost, dig resolution, dev tunnel access) -- all testable by agent
- #80: 7 AC (make targets, no host Ruby, docs, config.hosts) -- 7 exceeds the >5 threshold but all targets are in a single repo with tightly coupled changes (Makefile creation + related doc updates); acceptable without further decomposition
Blast Radius
config.hostschanges for the dev subdomain only affect the Rails production environment -- low risk since the same pattern was established in #69.- The Makefile wraps existing docker compose commands -- no new runtime behavior.
- Keycloak redirect URI additions (if needed) affect authentication flow -- must stay in sync.
- The dev-tunnel overlay introduces a new kubernetes deployment path -- review the existing dev-tunnel pattern carefully.
Decomposition Assessment
COMPLETE. Original ticket (14+ file targets across 3 repos, 14 AC) decomposed into 3 sub-tickets:
- #78 -- pal-e-deployments overlays (6 files, 1 repo, 5 AC)
- #79 -- pal-e-platform DNS + Caddy (2 files, 1 repo, 4 AC)
- #80 -- ISS Makefile + docs (6 files, 1 repo, 7 AC)
Each sub-ticket is within a single repo. #80 has 7 AC (above >5 threshold) but the changes are tightly coupled (Makefile + related docs in one repo) and estimated under 5 minutes of agent work. No further decomposition needed.
Recommendation
No action needed. All issues from v1 review resolved:
[BODY]Repo placement: FIXED -- godaddy-tofu replaced with pal-e-platform throughout[BODY]Constraints: FIXED -- DNS mechanism correctly described[BODY]Checklist: FIXED -- repo list corrected[SCOPE]arch-infra note: EXISTS -- found at slug arch-infra (v1 search missed it)[DECOMPOSE]Sub-tickets created: #78, #79, #80
-
Review: feat: deployment overlays, dev environment subdomain, and Makefile
review-1868-2026-07-17Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, references #3, #4, #5, PR #534
- [x] Repo — Multi-repo (3 repos listed)
- [x] User Story — Developer-focused, well-formed
- [x] Context — Thorough current state and deliverables
- [x] File Targets — 14+ targets across 3 repos with exclusion list
- [x] Feature Flag — none (infrastructure, acceptable)
- [x] Acceptance Criteria — 14 items
- [x] Test Expectations — 8 items with run commands
- [x] Constraints — 8 items, well-scoped
- [x] Checklist — 6 items
- [x] Related — comprehensive cross-references
Traceability
- [x] story:project-setup label — verified in project-iss user-stories section (Key: project-setup, Backing: "README + docs/architecture.md + docs/adoption-plan.md", Role: Developer)
- [x] arch:infra label — present on board item
- [ ] arch note MISSING — [SCOPE] No
arch-infranote found in pal-e-docs. Create architecture notearch-infrafor the infrastructure component. - [x] Forgejo issue — #77, open, valid URL
File Targets
intelligentstaffingsystems repo (this repo):
- [ ]
Makefile— does not exist yet (create — correct per ticket) - [x]
docker-compose.yml— verified: exists, update target. Currently minimal (web + db services, port 9999). - [x]
docs/local-dev-setup.md— verified: exists, update target. Currently documents docker compose commands manually; Makefile would wrap these. - [x]
docs/architecture.md— verified: exists, update target. - [x]
docs/pipeline.md— verified: exists, update target. - [x]
config/environments/production.rb— verified: exists. Currently hasconfig.hosts << "intelligentstaffingsystems.ai"andconfig.hosts << "iss.tail5b443a.ts.net". Ticket correctly notes dev subdomain may need adding.
pal-e-deployments repo:
- [ ]
overlays/intelligentstaffingsystems/— does not exist yet (create — correct per ticket) - [x]
overlays/westside-ror/prod/— verified: exists as reference pattern with kustomization.yaml, deployment-patch.yaml - [x]
overlays/westside-ror/dev/— verified: exists as reference pattern with deployment.yaml, ingress.yaml, kustomization.yaml, service.yaml - [x]
overlays/dev-tunnel/— verified: exists on main (configmap, deployment, ingress, kustomization, namespace, service, README) - [x]
bases/standard/— verified: exists (deployment, hpa, kustomization, networkpolicy, service, servicemonitor)
godaddy-tofu repo — REPO PLACEMENT ERROR:
- [ ] DNS record for
dev.intelligentstaffingsystems.ai— ISSUE:godaddy-tofuis a custom Go Terraform PROVIDER (manages GoDaddy API). It does NOT contain DNS record configurations. DNS records are managed inpal-e-platform/terraform/dns.tf. PR #534 ("Wire intelligentstaffingsystems.ai to production edge") is inpal-e-platform, notgodaddy-tofu. The Caddy vhost changes are also inpal-e-platform/salt/pillar/caddy.sls.
Repo Placement
MISMATCH: The issue lists
ldraney/godaddy-tofuas one of three target repos for DNS work. However,godaddy-tofuis a Go Terraform provider implementation (manages GoDaddy API). The actual DNS record configurations live inpal-e-platform/terraform/dns.tf, and Caddy vhost configs live inpal-e-platform/salt/pillar/caddy.sls. PR #534, which the issue cites as the reference for domain wiring, is inpal-e-platform, notgodaddy-tofu.The correct repo list should be:
ldraney/intelligentstaffingsystems— Makefile, docker-compose, docsldraney/pal-e-deployments— kustomize overlays (prod + dev)ldraney/pal-e-platform— DNS records (terraform/dns.tf) and Caddy vhost (salt/pillar/caddy.sls)
Dependencies
- #3 (Bootstrap Rails app — done) — foundation, no blocker
- #4 (Register ISS in pal-e-services — done) — created tfvars entry this overlay fulfills
- #5 (Deployment overlay stub — done) — original stub, superseded by this ticket
- PR #534 (pal-e-platform, closed) — wired apex domain, reference for dev subdomain DNS
- #69 (config.hosts DNS rebinding — validation) — established the config.hosts pattern; not a blocker but closely related
- No blocking dependencies found. All foundation work is done.
Acceptance Criteria
14 acceptance criteria, all testable by an agent:
- Overlay existence: verifiable with
ls - ArgoCD sync: verifiable with
kustomize build - DNS record: verifiable with
digafter terraform apply - Makefile targets: verifiable by running each
maketarget - No host Ruby: verifiable by inspecting Makefile targets use
docker compose - README with mermaid: verifiable with
read - Doc references: verifiable with
grep - config.hosts: verifiable with
read - Keycloak redirects: verifiable in pal-e-services tfvars
All criteria are well-defined and automatable. However, 14 criteria is well above the 5-criterion decomposition threshold.
Blast Radius
config.hostschanges for the dev subdomain only affect the Rails production environment — low risk since the same pattern was established in #69.- The Makefile wraps existing docker compose commands — no new runtime behavior, just a convenience layer.
- Keycloak redirect URI additions (if needed) affect authentication flow — must stay in sync across pal-e-services and the app.
- The dev-tunnel overlay introduces a new kubernetes deployment path — review the existing dev-tunnel pattern carefully to avoid port/ingress conflicts.
- No similar bug patterns found elsewhere; this is new infrastructure creation.
Decomposition Assessment
NEEDS DECOMPOSITION — route to
skill-decompose-ticket- File targets: 14+ across 3 repos (threshold: >3 across >2 repos) — EXCEEDED
- Acceptance criteria: 14 (threshold: >5) — EXCEEDED
- Estimated agent work: Well over 5 minutes — creating overlay directories with kustomization/patches/SOPS secrets, DNS terraform, Caddy vhost, Makefile, docker-compose updates, and 4 doc files — EXCEEDED
Suggested decomposition axes (3 sub-tickets, one per repo):
- pal-e-deployments: prod + dev overlays (kustomization, patches, secrets, READMEs)
- pal-e-platform: dev subdomain DNS record + Caddy vhost
- intelligentstaffingsystems: Makefile + docker-compose updates + docs updates + config.hosts
Recommendation
[BODY]Fix repo placement: replaceldraney/godaddy-tofuwithldraney/pal-e-platformfor DNS/Caddy work. Update File Targets section accordingly — DNS record goes interraform/dns.tf, Caddy vhost insalt/pillar/caddy.sls.[BODY]Fix Constraints section: change "DNS changes go through godaddy-tofu" to "DNS changes go through pal-e-platform/terraform/ (using the godaddy-tofu provider)".[BODY]Fix Checklist: change "one per repo: pal-e-deployments, godaddy-tofu, intelligentstaffingsystems" to "one per repo: pal-e-deployments, pal-e-platform, intelligentstaffingsystems".[SCOPE]Create architecture notearch-infrafor the infrastructure component in pal-e-docs.[DECOMPOSE]14+ file targets across 3 repos, 14 AC, estimated >5 min agent work — route toskill-decompose-ticket. Suggested split: one sub-ticket per repo (pal-e-deployments overlays, pal-e-platform DNS+Caddy, ISS Makefile+docs).
-
Review: Catalog tab: app portfolio with App Store links
review-1820-2026-07-17-v2Verdict: NEEDS_REFINEMENT
Well-scoped feature ticket with complete template sections, verified file targets, and clear acceptance criteria. Two fixable issues prevent READY status: a missing arch note and a minor factual inaccuracy in the issue body.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references #11 scope replacement
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- well-formed As/I want/So that
- [x] Context -- clear target audience description
- [x] File Targets -- 7 targets + 1 exclusion, all verified
- [x] Feature Flag -- None (appropriate for core tab)
- [x] Acceptance Criteria -- 4 new + 3 already shipped
- [x] Test Expectations -- 6 expectations with run command
- [x] Constraints -- 4 constraints including Turbo Native pattern
- [x] Checklist -- standard 3-item
- [x] Related -- project-iss, #11
Traceability
- [x] story:catalog label -- "Browse portfolio by three pillars; admin CRUD"
- [x] story note verified -- found in project-iss user-stories section (Epic 3, US-3.1-3.2, Lead/Client role)
- [x] arch:rails label -- present on board item
- [ ] arch note MISSING -- search for "arch-rails" returned no results. [SCOPE] Create architecture note arch-rails for the Rails component. Note: arch:rails is used across many ISS board items, so this is a systemic gap, not specific to this ticket.
- [x] Forgejo issue -- #50, state: open
File Targets
- [x]
app/controllers/catalog_controller.rb-- verified: exists with index + show actions, scoped to published entries - [x]
app/views/catalog/index.html.erb-- verified: exists with inline card grid (extraction to partial is correctly planned) - [x]
app/views/catalog/_catalog_entry.html.erb-- does not exist yet (new file). Ticket correctly plans extracting inline cards to this partial. - [x]
app/views/catalog/show.html.erb-- verified: exists with detail page layout, no app_store_url link yet - [x]
app/assets/stylesheets/catalog.css-- verified: exists (7.8KB), responsive card layout already in place - [x]
app/models/catalog_entry.rb-- verified: exists with pillar enum, validations, scopes. No app_store_url field yet. - [x]
db/migrate/XXXXXX_add_app_store_url_to_catalog_entries.rb-- does not exist yet (new file). Schema confirms catalog_entries has no app_store_url column. Migration correctly scoped. - [x] NOT touching
app/controllers/admin/catalog_controller.rb-- verified: exists, correctly excluded
Repo Placement
OK. All file targets are in ldraney/intelligentstaffingsystems. Issue is filed on the same repo. No cross-repo concerns.
Dependencies
- Sprint 4 catalog work (board items #1814, #1815, #1816 -- PRs #38, #39, #41) are all in done. These created the CatalogEntry model, browsing UI, and admin CRUD that this ticket builds on. Prerequisite satisfied.
- #11 (parent catalog story) is in backlog, marked as decomposed. No blocker.
- Sprint A items (#58 landing page, #59 registration, #49 navigation) are in validation. Sprint B follows Sprint A by convention, but no direct code-level blockers between this ticket and Sprint A items.
- No undocumented dependencies found.
Acceptance Criteria
4 new acceptance criteria, all testable by an agent:
- Portfolio description text -- verifiable by checking view content
- Target audience communication -- verifiable by checking content
- Cards with App Store link -- verifiable by checking for app_store_url in card HTML
- App Store links open externally -- verifiable by checking for
data-turbo="false"attribute
3 already-shipped criteria properly marked as done. 6 test expectations are specific with a valid run command.
Minor inaccuracy: AC #4 states "This is the first use of this pattern in the app" for
data-turbo="false". However,app/views/dashboard/show.html.erb:11already usesdata: { turbo: false }on the sign-out button_to. The distinction is that the existing use is on a form submission (button_to), while this ticket introduces it on a link for external URL navigation in Turbo Native. The claim is directionally correct but technically inaccurate.Blast Radius
data-turbo="false"for external links: establishes a new pattern for link elements. Only existing use is on the dashboard sign-out button (form submission). If other pages link to external URLs in the future, they should follow this same pattern. Low blast radius.- CatalogEntry model change (adding app_store_url): column addition only. Admin catalog CRUD (admin/catalog_controller.rb) is correctly excluded. Admin form would need updating separately to allow setting app_store_url, but that is explicitly out of scope.
- No shared partials or helpers affected outside the catalog feature.
Decomposition Assessment
7 file targets in 1 repo. 4 acceptance criteria (under 5 threshold). Work scope: add column + model validation, update 2 views (extract partial + add link), update CSS. Estimated agent time: under 5 minutes. No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-railsfor the Rails component. This is a systemic gap --arch:railsis used across many ISS board items. Could be addressed once for the whole project rather than per-ticket.[BODY]Fix claim in AC #4: "This is the first use of this pattern in the app" -- dashboard sign-out already usesdata: { turbo: false }. Clarify to: "This is the first use ofdata-turbo="false"for external link navigation (existing use is on sign-out form only)."
-
Review R2: Keycloak ISS realm: self-registration, phone field, SMTP
review-1864-r2-2026-07-17Verdict: APPROVED
R2 re-review of board item #1864. All 7 R1 recommendations from
review-1864-2026-07-17have been addressed in the issue body rewrite.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Related to intelligentstaffingsystems#59 (parent registration story)
- [x] Repo -- Cross-repo clearly identified (pal-e-services for terraform, intelligentstaffingsystems for theme)
- [x] User Story -- present
- [x] Context -- explains what is already deployed (self-reg, SMTP via PR #178/#175), remaining work, and architectural decision change (CSS-only to FreeMarker)
- [x] File Targets -- 6 files across 2 repos, all paths verified (see below)
- [x] Feature Flag -- none (realm-level config, appropriate)
- [x] Acceptance Criteria -- 7 items, 2 struck through as already deployed, 5 active
- [x] Test Expectations -- 4 manual tests
- [x] Constraints -- present, includes theme directory, parent theme, SMTP status, brand tokens, Keycloak version note
- [x] Blockers -- none (correct, prerequisites are deployed)
- [x] Checklist -- 2 PRs listed (one per repo), tests, no unrelated changes
- [x] Related -- project, parent issue, merged PRs, arch note
Traceability
- [x] story:registration label -- "Epic 1 (US-1.2-1.4)", Role: Visitor/Lead
- [x] story note verified -- found in project-iss user-stories section
- [x] arch:auth label -- present on board item
- [x] arch note verified --
arch-auth-issnote exists in pal-e-docs (note: search_notes doesn't index it but get_note by slug succeeds). Note content includes FreeMarker decision: "CSS-only theme: register.ftl is the first FreeMarker override (planned for self-registration)." - [x] Forgejo issue -- ldraney/pal-e-services#184, open
File Targets
In ldraney/intelligentstaffingsystems:
- [x]
keycloak-theme/iss/login/register.ftl-- NEW file to create. Directory exists, confirmed:keycloak-theme/iss/login/containstheme.properties,resources/css/login.css,resources/img/iss-logo.svg. Path is correct (R1 fix #1 applied). - [x]
keycloak-theme/iss/login/resources/css/register.css-- NEW file to create. Parent directoryresources/css/exists withlogin.css. Path is correct. - [x]
keycloak-theme/iss/login/theme.properties-- EXISTS. Current content:parent=keycloak,import=common/keycloak,styles=css/login.css. May need update to addregister.cssto styles list.
In ldraney/pal-e-services:
- [x]
terraform/variables.tf-- EXISTS (line 139,keycloak_realmsvariable). Confirmed:verify_emailis NOT present. Needs newoptional(bool, false)field added. (R1 fix #4 applied). - [x]
terraform/keycloak.tf-- EXISTS (line 28,keycloak_realmresource). Confirmed:verify_emailis NOT wired. Needsverify_email = each.value.verify_emailadded. - [x]
terraform/k3s.tfvars-- EXISTS (symlink to secrets). ISS realm defined withregistration_allowed = true, roles, default_roles, and SMTP block. Noverify_emailcurrently set. Needsverify_email = true.
Repo Placement
OK. Cross-repo nature is correctly documented in the Repo section and the Checklist section specifies separate PRs for each repo (R1 fix #2 applied). The Forgejo issue is filed on pal-e-services, which hosts one half of the work (terraform). The theme work in intelligentstaffingsystems is tracked via the same issue with a separate PR -- acceptable for tightly coupled cross-repo work.
Dependencies
- Board item #1831 (ISS#59, Rails-side registration) is in backlog sprint:A -- depends on this ticket. Documented in Lineage: "This is the infrastructure prerequisite -- realm config and theme must be in place before the Rails app can wire the post-registration flow."
- Board item #1786 (#6 Keycloak OIDC auth integration) -- done. Completed prerequisite.
- Board item #1785 (#17 Keycloak login theme ISS branding) -- done. Established theme directory structure at
keycloak-theme/iss/. - PR #178 (merged) -- already deployed self-registration and SMTP.
- PR #175 (merged) -- established Postmark SMTP.
- No in_progress items blocking this ticket.
Acceptance Criteria
7 criteria listed, 2 marked as already deployed (R1 fix #3 applied). 5 active ACs:
- AC 2 (register.ftl with phone field) -- verifiable by navigating to registration page
- AC 3 (phone stored as Keycloak user attribute) -- verifiable via Keycloak admin console
- AC 5 (verify_email in terraform) -- verifiable by terraform plan and manual email test
- AC 6 (ISS brand match) -- colors specified (navy #1b2a4a, gold #996d13), verifiable visually
- AC 7 (existing login still works) -- regression test, verifiable
All active criteria are agent-verifiable or manually testable with clear success conditions.
Blast Radius
- Adding
register.ftlchanges the ISS theme from CSS-only to FreeMarker-based. This architectural decision change is explicitly documented in the Context section and acknowledged in the arch-auth-iss note (R1 fix #5 applied). FreeMarker templates are Keycloak-version-specific; the Constraints section notes this. - The
verify_emailaddition to the terraform module is additive: newoptional(bool, false)field means all existing realms default to false (no behavioral change). Only the ISS realm will settrue. - No blast radius on SMTP or self-registration (already live).
- Observation (non-blocking): The ISS realm in k3s.tfvars does not set
login_theme = "iss". Other realms (westside, landscaping) do set their login_theme via terraform. If the ISS theme was configured via Keycloak admin console rather than terraform, it works but is not infrastructure-as-code. The implementing agent should verify the theme is active before creating register.ftl -- if not, addinglogin_theme = "iss"to the ISS realm config may be needed.
Decomposition Assessment
5 active ACs across 2 repos, 6 file targets. Thresholds:
- >3 file targets across >2 repos: 6 files across 2 repos -- repo count (2) does not exceed threshold (>2)
- >5 acceptance criteria: 5 active ACs -- does not exceed threshold (>5)
- Estimated agent work: terraform changes ~2 min, theme work ~3-4 min = ~5-6 min total -- borderline
The issue body addresses cross-repo coordination via separate checklist items for each PR. The work is tightly coupled (theme needs realm config, realm config enables theme). No decomposition needed -- single ticket with two PRs is the correct approach.
R1 Issues Resolution
# R1 Recommendation Status 1 [BODY] Fix file paths: keycloak/themes/ to keycloak-theme/ FIXED -- all paths now use keycloak-theme/iss/login/ 2 [BODY] Fix repo for FreeMarker/CSS work FIXED -- Repo section identifies both repos, file targets split by repo 3 [BODY] Mark already-deployed ACs FIXED -- AC 1 and AC 4 struck through with "already deployed" note 4 [BODY] Replace vague file target with terraform paths FIXED -- variables.tf, keycloak.tf, k3s.tfvars all specified with purpose 5 [BODY] Document FreeMarker architectural decision change FIXED -- Context section explains the change from CSS-only to template-based 6 [SCOPE] Create architecture note arch-auth FIXED -- arch-auth-iss note exists in pal-e-docs with full content including FreeMarker decision 7 [DECOMPOSE] Split cross-repo work ADDRESSED -- cross-repo checklist with separate PRs, within decomposition thresholds Recommendation
No action needed. All R1 issues resolved. Ticket is ready for implementation.
Implementation note: The implementing agent should verify that
login_theme = "iss"is active on the ISS Keycloak realm before creating register.ftl. If the theme was set via admin console rather than terraform, consider addinglogin_theme = "iss"to the ISS realm in k3s.tfvars for infrastructure-as-code consistency. -
Review: In-app registration: post-Keycloak flow, phone validation, LeadsController reconciliation (R3)
review-1831-2026-07-17-r3Verdict: APPROVED
R3 re-review of board item #1831. Both remaining issues from R2 (
review-1831-2026-07-17-r2) are resolved. Ticket is ready for development.Previous Issues -- Resolved
- [x]
[SCOPE]Architecture notearch-auth-issnow exists in pal-e-docs (id: 2569, note_type: architecture, project: iss). Covers Keycloak OIDC flow, OmniAuth, SessionsController, roles, and key decisions. Resolves the traceability gap carried from R1 through R2. - [x]
[BODY]Blast radius filename corrected: issue body now readsapp/helpers/session_helper.rb(singular). Verified: file exists at that path withmodule SessionHelper. The pluralsessions_helper.rbdoes not exist.
Template Completeness
- [x] Type (Feature)
- [x] Lineage (Related to pal-e-services#184)
- [x] Repo (
ldraney/intelligentstaffingsystems) - [x] User Story (As a prospective ISS client...)
- [x] Context (post-Keycloak self-registration wiring)
- [x] File Targets (6 files)
- [x] Feature Flag (none -- no
docs/feature-flags.mdin project, acceptable) - [x] Acceptance Criteria (6 items)
- [x] Test Expectations (2 unit + 1 integration + run command)
- [x] Constraints (4 items including schema facts and design tokens)
- [x] Blast Radius (2 files identified)
- [x] Blockers (pal-e-services#184 prerequisite)
- [x] Checklist
- [x] Related
Traceability
- [x] story:registration label -- Epic 1 (US-1.2--1.4), Visitor/Lead
- [x] story note verified -- found in project-iss user-stories section (key: registration, backing: Epic 1)
- [x] arch:auth label -- authentication component
- [x] arch note verified --
arch-auth-issexists in pal-e-docs (architecture note, project: iss, created 2026-07-17). Covers Keycloak OIDC sequence diagram, component table, key decisions, and roles matrix. - [x] Forgejo issue -- ldraney/intelligentstaffingsystems#59, open
File Targets
- [x]
app/controllers/sessions_controller.rb-- verified: OmniAuth callback with 3-path lead resolution. Walk-in path (line 101) creates Lead withphone: "Not provided". Correctly scoped for phone extraction from Keycloak token. - [x]
app/controllers/leads_controller.rb-- verified: public registration form withskip_before_action :authenticate_user!. Permits phone in lead_params. - [x]
app/views/leads/new.html.erb-- verified: full registration form with phone telephone_field (line 42). - [x]
app/models/lead.rb-- verified: hasvalidates :phone, presence: true(line 12) but no format validation. Ticket correctly scopes adding format validation. - [x]
config/routes.rb-- verified:resources :leads, only: %i[new create](line 3), booking route (line 7), OmniAuth callback routes (lines 31-32). - [x]
test/controllers/sessions_controller_test.rb-- verified: 20 test definitions covering all 3 lead resolution paths.
Repo Placement
Correct. All 6 file targets are in
ldraney/intelligentstaffingsystems. Keycloak realm configuration properly split topal-e-services#184as a separate board item (#1864) with matching sprint:A label.Dependencies
- #1864 (pal-e-services#184, "Keycloak ISS realm: self-registration, phone field, SMTP") -- sprint:A, backlog. Prerequisite for this ticket. Documented as blocker. Correct.
- #1786 (#6 Keycloak OIDC auth) -- done. Prerequisite satisfied.
- #1788 (#8 Lead model + registration form) -- done. Prerequisite satisfied.
- #1796 (#16 Postmark email) -- explicitly NOT a dependency. Correct: Keycloak handles its own SMTP.
- No undocumented blockers found.
Acceptance Criteria
6 acceptance criteria. All testable by an agent. Assessment:
- AC #1 (post-registration redirect to dashboard) -- existing code at sessions_controller.rb already redirects to
dashboard_path. Enhancement: ensure Keycloak post-registration flow reaches this callback. Depends on pal-e-services#184. - AC #2 (phone validation) -- clear: add format validation to existing
validates :phone, presence: true. - AC #3 (LeadsController reconciliation) -- appropriate agent flexibility: "either repurposed or removed if redundant."
- AC #4 (OmniAuth callback for first-login) -- walk-in path exists (line 101). Enhancement for phone sync.
- AC #5 (phone sync from Keycloak) -- clear and testable. Requires Keycloak phone in token (pal-e-services#184).
- AC #6 (tests) -- test file exists with good coverage. Incremental additions needed.
Blast Radius
- [x]
app/controllers/application_controller.rb--authenticate_user!checkssession[:user](line 41). Compatible with self-registered users via existing walk-in path. No changes needed. - [x]
app/helpers/session_helper.rb-- exists (singular, module SessionHelper). Filename now correct in issue body. - Downstream:
profile_controller.rbpermits phone andprofile/show.html.erbdisplays phone with "Not provided" fallback -- both compatible with this change. No blast radius concern.
Decomposition Assessment
6 file targets in 1 repo. 6 ACs (slightly over 5-AC threshold). However, AC #1 and #4 are incremental enhancements to existing code, AC #6 is a meta-criterion. Effective new work is ~3 discrete changes (phone format validation, phone sync from Keycloak token, LeadsController reconciliation). Single agent pass under 5 minutes. No decomposition needed.
Recommendations
No action needed. All previous recommendations have been addressed across R1 and R2 cycles.
- [x]
-
Review: Keycloak ISS realm: self-registration, phone field, SMTP
review-1864-2026-07-17Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Related to intelligentstaffingsystems#59
- [x] Repo -- present (but WRONG, see below)
- [x] User Story -- present
- [x] Context -- present, good background
- [x] File Targets -- present (but paths and repo are wrong)
- [x] Feature Flag -- none (appropriate for realm config)
- [x] Acceptance Criteria -- 7 items present
- [x] Test Expectations -- 4 manual tests
- [x] Constraints -- present
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:registration label -- "Epic 1 (US-1.2-1.4)", Role: Visitor/Lead
- [x] story note verified -- found in project-iss user-stories section
- [x] arch:auth label -- present on board item
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-auth in pal-e-docs
- [x] Forgejo issue -- ldraney/pal-e-services#184, open
File Targets
- [ ]
keycloak/themes/iss/login/register.ftl-- ISSUE: Wrong path AND wrong repo. The ISS Keycloak theme lives atkeycloak-theme/iss/login/in the intelligentstaffingsystems repo, not pal-e-services. Confirmed by existing files:keycloak-theme/iss/login/theme.properties,keycloak-theme/iss/login/resources/css/login.css,keycloak-theme/iss/login/resources/img/iss-logo.svg. Issue #17 (done) established this: "The theme directory lives in this repo for version control but is deployed to the cluster separately." - [ ]
keycloak/themes/iss/login/resources/css/register.css-- ISSUE: Same as above -- should bekeycloak-theme/iss/login/resources/css/register.cssin intelligentstaffingsystems repo. - [ ] "Realm config (admin console or realm export)" -- ISSUE: Vague. Realm config changes go through
terraform/k3s.tfvarsandterraform/keycloak.tfin pal-e-services. However, self-registration and SMTP are ALREADY deployed via PR #178.
Repo Placement
MISMATCH. The issue says
### Repo: ldraney/pal-e-servicesbut the ticket describes work in two repos:- intelligentstaffingsystems: FreeMarker template (register.ftl) and CSS (register.css) -- the keycloak-theme directory lives here
- pal-e-services: Terraform realm config -- but self-registration (
registration_allowed = true) and SMTP (Postmark) are already deployed via PR #178 (merged). The only remaining terraform work is addingverify_emailto the realm config, which is currently NOT in variables.tf or keycloak.tf.
Dependencies
- Board item #1831 (intelligentstaffingsystems#59, Rails-side registration) is in backlog with sprint:A -- this ticket (#1864) is listed as its prerequisite. Dependency relationship is documented in the Lineage section.
- Board item #1786 (#6 Keycloak OIDC auth integration) is done -- completed prerequisite.
- Board item #1785 (#17 Keycloak login theme) is done -- established the theme directory structure at
keycloak-theme/iss/. - PR #178 (Add ISS service, Keycloak realm, client, and seed user) is merged -- already deployed self-registration, SMTP, roles, and default role assignment.
- PR #175 (Configure Keycloak SMTP via Postmark) is merged -- established the SMTP pattern.
Acceptance Criteria
7 criteria listed. Issues:
- AC 1 (self-registration enabled): Already deployed via PR #178. Redundant unless verifying it's live.
- AC 4 (realm-level SMTP with Postmark): Already deployed via PR #178. Redundant.
- AC 5 (email verification required):
verify_emailis NOT in the current terraform variables or keycloak.tf. Requires adding this field to the terraform module before it can be set. - AC 2, 3 (register.ftl, phone attribute): Valid new work, but belongs in intelligentstaffingsystems repo.
- AC 6 (ISS brand): Valid, belongs in intelligentstaffingsystems repo.
- AC 7 (existing login still works): Valid regression check.
Not all criteria are agent-verifiable -- "Registration form matches ISS brand" requires visual inspection.
Blast Radius
- Adding
register.ftlchanges the ISS theme from CSS-only to FreeMarker-based. This is the first FreeMarker template in the ISS theme (confirmed by current contents: only theme.properties, login.css, and iss-logo.svg). This could affect Keycloak upgrade compatibility -- FreeMarker templates are version-specific. - The theme.properties currently has
parent=keycloak-- the register.ftl must properly extend the parent template. Issue #17's constraints explicitly state "CSS-only overrides, no FreeMarker template changes" -- this ticket overrides that decision. The Context section acknowledges this ("adds the first FreeMarker template") but the architectural decision change should be documented. - No blast radius on SMTP or self-registration -- those are already live.
Decomposition Assessment
7 AC across 2 repos (intelligentstaffingsystems for theme files, pal-e-services for verify_email terraform). Exceeds the 5-AC threshold. After removing already-deployed AC (self-reg and SMTP), ~5 AC remain across 2 repos. Borderline -- recommend decomposition into two focused tickets:
- Ticket A (pal-e-services): Add
verify_emailto terraform realm config (variables.tf, keycloak.tf, k3s.tfvars). 1-2 AC, ~2 minutes agent work. - Ticket B (intelligentstaffingsystems): Create register.ftl FreeMarker template with phone field, add register.css, update theme.properties. 3-4 AC, ~5 minutes agent work.
Recommendation
[BODY]Fix file paths:keycloak/themes/iss/login/should bekeycloak-theme/iss/login/[BODY]Fix repo for FreeMarker/CSS work: belongs inldraney/intelligentstaffingsystems, notldraney/pal-e-services[BODY]Remove or mark as "already deployed" the self-registration and SMTP acceptance criteria (deployed via PR #178)[BODY]Replace vague "Realm config (admin console or realm export)" file target with specific terraform paths:terraform/variables.tf,terraform/keycloak.tf, andterraform/k3s.tfvarsin pal-e-services -- specifically for addingverify_email[BODY]Add note that this introduces the first FreeMarker template to the ISS theme, changing it from CSS-only to template-based (architectural decision change from #17)[SCOPE]Create architecture notearch-authin pal-e-docs[DECOMPOSE]Split cross-repo work: (A) pal-e-services ticket for verify_email terraform addition; (B) intelligentstaffingsystems ticket for register.ftl + register.css + phone field. Route to skill-decompose-ticket.
-
Review: In-app registration: post-Keycloak flow, phone validation, LeadsController reconciliation (re-review)
review-1831-2026-07-17-r2Verdict: NEEDS_REFINEMENT
Re-review after major scope rewrite. The original ticket was decomposed: #59 (this) covers Rails-side only; pal-e-services#184 covers Keycloak realm config. The previous review (
review-1831-2026-07-17) returned NEEDS_REFINEMENT with 8 recommendations. 7 of 8 have been addressed. One carried-forward issue and one new issue remain.Previous Issues -- Resolved
- [x]
[BODY]Removed unnecessary phone migration -- phone column already exists in schema - [x]
[BODY]Fixed phone/phone_number naming -- issue consistently usesphone - [x]
[BODY]Keycloak theme work split to pal-e-services#184 -- no longer in scope - [x]
[BODY]Cross-repo dependency documented -- pal-e-services#184 created, noted as blocker - [x]
[BODY]Removed nonexistentapp/views/pages/home.html.erbreference - [x]
[BODY]Clarified Postmark independence -- "Does NOT depend on #16 -- Keycloak handles its own SMTP" - [x]
[BODY]Addressed LeadsController reconciliation in AC #3 -- "repurposed as pre-registration capture form or removed if redundant"
Template Completeness
- [x] Type (Feature)
- [x] Story (key: registration)
- [x] Summary / Context
- [x] File Targets (6 targets)
- [x] Acceptance Criteria (6 items)
- [x] Blast Radius
- [x] Constraints
- [x] Blockers
- [x] Decomposition
- [x] Repo
- [ ] Feature Flag -- missing, but acceptable: no
docs/feature-flags.mdexists in this project yet - [ ] Test Expectations -- missing explicit section, but covered implicitly by AC #6
Traceability
- [x] story:registration label -- Epic 1 (US-1.2--1.4), Visitor/Lead
- [x] story note verified -- found in project-iss user-stories section (key: registration, backing: Epic 1)
- [x] arch:auth label -- authentication component
- [ ] arch note MISSING -- [SCOPE] Neither
arch-authnorarch-auth-issexists in pal-e-docs. Carried forward from R1. - [x] Forgejo issue -- ldraney/intelligentstaffingsystems#59, open
File Targets
- [x]
app/controllers/sessions_controller.rb-- verified: OmniAuth callback with 3-path lead resolution. Walk-in path (line 104) creates Lead withphone: "Not provided". Needs update to extract phone from Keycloak token. - [x]
app/controllers/leads_controller.rb-- verified: public registration form withskip_before_action :authenticate_user!. Permits phone in lead_params. - [x]
app/views/leads/new.html.erb-- verified: full registration form (74 lines) with phone telephone_field. - [x]
app/models/lead.rb-- verified: hasvalidates :phone, presence: truebut no format validation. Ticket correctly scopes adding format validation. - [x]
config/routes.rb-- verified:resources :leads, only: %i[new create]and booking route present. - [x]
test/controllers/sessions_controller_test.rb-- verified: comprehensive tests for all 3 lead resolution paths (by sub, email claim, walk-in).
Blast Radius
- [x]
app/controllers/application_controller.rb-- verified:authenticate_user!checkssession[:user], compatible with self-registered users via walk-in path. - [ ]
app/helpers/sessions_helper.rb-- ISSUE: file does not exist. Actual file isapp/helpers/session_helper.rb(singular, moduleSessionHelper). [BODY] Fix filename.
Repo Placement
Correct. All file targets are in intelligentstaffingsystems. Keycloak realm config has been properly split to pal-e-services#184 as a separate ticket. Both items are on board-iss with sprint:A label.
Dependencies
- #1864 (pal-e-services#184, "Keycloak ISS realm: self-registration, phone field, SMTP") -- sprint:A, backlog. Prerequisite for this ticket. Documented as blocker. Correct.
- #6 (Keycloak OIDC auth) -- done. Prerequisite satisfied.
- #8 (Lead model + registration) -- done. Prerequisite satisfied.
- #16 (Postmark email) -- explicitly NOT a dependency. Correct.
- No undocumented blockers found.
Acceptance Criteria
6 acceptance criteria. All testable. Notes:
- AC #1 (post-registration redirect to dashboard) -- partially satisfied by existing code:
sessions_controller.rb:56already redirects todashboard_path. The new work is ensuring Keycloak's post-registration flow reaches this callback, which depends on pal-e-services#184. - AC #3 (LeadsController reconciliation) -- gives agent appropriate flexibility with "either repurposed or removed". Acceptable.
- AC #4 (OmniAuth callback for first-login) -- walk-in path already exists (lines 101-114). Enhancement needed for phone sync, not a greenfield implementation.
- AC #5 (phone sync from Keycloak) -- clear and testable. Requires Keycloak to provide phone in token (pal-e-services#184).
- AC #6 (tests) -- test file exists with good coverage. Incremental test additions needed.
Decomposition Assessment
6 file targets in 1 repo. 6 ACs (slightly over 5-AC threshold). However, AC #1 and #4 are incremental enhancements to existing code, and AC #6 is a meta-criterion. Effective new work is ~3 discrete changes (phone validation, phone sync, LeadsController reconciliation). Single agent pass under 5 minutes. No decomposition needed.
Recommendations
[SCOPE]Create architecture notearch-auth(orarch-auth-iss) for the authentication component in pal-e-docs. Carried forward from R1 -- this is a traceability requirement for thearch:authlabel.[BODY]Fix blast radius file path:app/helpers/sessions_helper.rbshould beapp/helpers/session_helper.rb(singular, moduleSessionHelper).
- [x]
-
Review: Tab bar restructure to Catalog / Projects / Communications / Account + CRM (re-review)
review-1829-2026-07-17-r2Verdict: READY
Re-review of board item #1829. Previous review (
review-1829-2026-07-17) returned NEEDS_REFINEMENT. All five findings have been addressed in the updated issue body.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, supersedes #10
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- present (As a logged-in user / tab bar matching role / navigate main sections)
- [x] Context -- present (old vs new tab structure, role visibility rules)
- [x] File Targets -- present, complete (5 modify targets + 3 test files + 6 blast-radius views)
- [x] Feature Flag -- none, structural change (appropriate)
- [x] Acceptance Criteria -- 7 items
- [x] Test Expectations -- 4 items + run command
- [x] Constraints -- present (fixed: now references application.css :root, not deleted docs/ui-ux.md)
- [x] Checklist -- present
- [x] Related -- present (project-iss, #10)
Traceability
- [x] story:navigation label -- "Bottom tab bar with role-correct tabs" (Epic 2 + role-tab matrix, All roles)
- [x] story note verified -- found in project-iss user-stories section
- [x] arch:frontend label -- present on board item
- [x] arch note verified -- arch-frontend-iss note exists in pal-e-docs (status: active, project: iss)
- [x] Forgejo issue -- #49, open
File Targets
Modify targets (all verified):
- [x]
app/views/layouts/application.html.erb-- verified: renders tab bar partial - [x]
app/views/shared/_tab_bar.html.erb-- verified: tab bar partial with role logic via visible_tabs - [x]
app/helpers/navigation_helper.rb-- verified: TAB_ROLES at line 14 with old structure (catalog, messages, profile, admin) - [x]
app/assets/stylesheets/tab_bar.css-- verified: exists, uses design tokens - [x]
config/routes.rb-- verified: no routes for /projects, /communications, /account, /crm (404s expected per issue)
Test files (all verified):
- [x]
test/controllers/tab_bar_test.rb-- verified: hardcodes old tab names (Messages, Profile, Admin) and counts (3 for lead/client, 4 for admin) - [x]
test/helpers/navigation_helper_test.rb-- verified: asserts TAB_ROLES keys [:catalog, :messages, :profile, :admin] at line 34; asserts per-role visible tabs with old keys - [x]
test/controllers/messages_controller_test.rb-- verified: line 58 asserts "Messages" tab as active, line 61 asserts .tab-bar-tab.is-active label "Messages"
Blast-radius views (all verified):
- [x]
app/views/messages/index.html.erb-- verified: content_for(:current_tab, "messages") at line 2 - [x]
app/views/messages/inbox.html.erb-- verified: content_for(:current_tab, "messages") at line 2 - [x]
app/views/admin/catalog/index.html.erb-- verified: content_for(:current_tab, "admin") at line 2 - [x]
app/views/admin/catalog/show.html.erb-- verified: content_for(:current_tab, "admin") at line 2 - [x]
app/views/admin/catalog/new.html.erb-- verified: content_for(:current_tab, "admin") at line 2 - [x]
app/views/admin/catalog/edit.html.erb-- verified: content_for(:current_tab, "admin") at line 2
Non-affected views (confirmed safe):
- [x]
app/views/catalog/index.html.erb-- sets content_for(:current_tab, "catalog"), key unchanged, no action needed - [x]
app/views/catalog/show.html.erb-- sets content_for(:current_tab, "catalog"), key unchanged, no action needed
Repo Placement
OK -- issue filed on ldraney/intelligentstaffingsystems, all file targets are in that repo. Single-repo change.
Dependencies
- #10 (Bottom tab bar navigation) -- done, superseded by this ticket. No conflict.
- #42 (Turbo Streams live delivery) -- in todo, messaging related, not blocking this ticket.
- No blocking dependencies found on the board.
Acceptance Criteria
7 AC items, all testable:
- Tab counts per role -- testable via assert_select on rendered HTML
- Active tab indicator -- testable via assert_select for active CSS class
- Tab icons and labels -- testable via assert_select for .tab-bar__icon and .tab-bar__label
- TAB_ROLES enforcement -- testable via unit test on NavigationHelper
- Turbo Native WebView -- testable by checking data-turbo-action attribute
- Old tabs removed -- testable by asserting absence of Messages, Profile, Admin labels
Route strategy clarified: no new routes needed. Unimplemented tabs 404 until their feature tickets ship, matching the existing pattern documented in navigation_helper.rb comments (lines 6-9).
Blast Radius
- content_for(:current_tab) renames: 6 view files documented in issue with specific key changes (messages->communications, admin->crm). 2 catalog views use "catalog" key which is unchanged.
- Test suite: 3 test files documented in issue, all hardcode old tab structure.
- docs/user-stories.md: Still references old tab names. Not in scope for this ticket -- follow-up only.
Decomposition Assessment
5 modify targets + 3 test files + 6 blast-radius views = 14 files, all in 1 repo, all the same conceptual change (tab rename/restructure). 7 AC items. Estimated agent work: 3-5 minutes. No decomposition needed.
Previous Review Findings -- All Resolved
- [x]
[BODY]Missing test file targets -- now listed under "Test files to update" with specific assertions to change - [x]
[BODY]Missing blast-radius views -- now listed under "Blast-radius views" with specific content_for renames - [x]
[BODY]Route contradiction -- resolved: issue now states "no new routes needed; 404s expected" - [x]
[BODY]Stale constraint reference -- fixed: now references app/assets/stylesheets/application.css :root - [x]
[SCOPE]arch-frontend note missing -- arch-frontend-iss created (active, project: iss)
Recommendation
No action needed. Scope is solid, all file targets verified, traceability complete, route strategy clarified, and the ticket fits in a single agent pass.
-
Review: Landing page: sales pitch with App Store download CTA (re-review)
review-1830-2026-07-17-r2Verdict: READY
Re-review of board item #1830. Previous review (
review-1830-2026-07-17) returned NEEDS_REFINEMENT with two recommendations. Both have been addressed.Previous Issues — Resolved
- [x]
[BODY]File path corrected:app/views/pages/home.html.erbupdated toapp/views/pages/landing.html.erbin issue body. Verified: file exists (188 lines). - [x]
[SCOPE]Architecture note created:arch-frontend-iss("Frontend Architecture: ISS", note_type: architecture, status: active, project: iss). Verified via search.
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:landing-page label — Epic 1 (US-1.1), Visitor role
- [x] story note verified — found in project-iss user-stories section (key: landing-page, success metric: "Landing page renders publicly, mobile-first")
- [x] arch:frontend label — frontend component
- [x] arch note verified —
arch-frontend-issnote exists in pal-e-docs (type: architecture, status: active, project: iss) - [x] Forgejo issue — ldraney/intelligentstaffingsystems#58, open
File Targets
- [x]
app/views/pages/landing.html.erb— verified: exists (188 lines), contains hero section with "Book an Appointment" CTA, three pillar cards, journey steps, offer section, bottom CTA. This is the file where the App Store download button replaces the current booking CTA. - [x]
app/assets/stylesheets/pages.css— verified: exists (351 lines), contains CTA section styling (.cta-section, .btn classes), responsive breakpoint at 600px. Uses design tokens from application.css :root. - [x]
app/controllers/sessions_controller.rb— verified: exists (116 lines),newaction currently renders sessions/new.html.erb (Keycloak sign-in button). This action will be changed to redirect to App Store URL. - [x]
config/routes.rb— verified: exists (46 lines), line 30 maps GET /login to sessions#new. Root route at line 45 ispages#landing.
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo. Single-repo change.
Dependencies
- #7 (Landing page, sprint:2) — in done. This ticket updates scope of #7 (CTA changes from login to App Store download). No blocker.
- #59 (board item 1831, sprint:A, arch:auth, story:registration) — related. In-app registration flow that follows the App Store download. In backlog. Not a blocker for this ticket, but the two tickets form a pair: this one sends visitors to the App Store, #59 handles what happens after they open the app.
- #49 (board item 1829, sprint:A, arch:frontend, story:navigation) — same sprint, both touch frontend. In backlog. Minimal file overlap (tab bar vs landing page). No blocker.
- No items in in_progress or next_up block this ticket.
Acceptance Criteria
8 criteria listed. Assessment of testability:
- AC1 (public landing page) — testable via endpoint test. Already satisfied: PagesController skips auth, root route is public.
- AC2 (ISS pitch, three pillars) — testable via content assertions. Already satisfied: landing.html.erb has hero section, three pillar cards, journey steps, offer section.
- AC3 (App Store download button) — testable via presence check in rendered HTML. New work.
- AC4 (App Store link opens store) — testable via link href check. New work.
- AC5 (no login form on website) — testable: verify sessions/new.html.erb is removed or redirects. New work. Currently renders "Sign in with Keycloak" button.
- AC6 (login route redirects to App Store) — testable via endpoint test (302). New work. Currently GET /login renders sessions/new.html.erb.
- AC7 (responsive, mobile-first) — testable via CSS assertions. Already satisfied: pages.css has mobile-first layout with 600px breakpoint.
- AC8 (target audience messaging) — testable via content check. Already partially satisfied.
Net-new work covers 4 criteria (AC3-6); 4 criteria verify existing behavior. All are testable by an agent.
Blast Radius
- Auth redirect chain:
application_controller.rb:59redirects unauthenticated users tologin_path. Under this ticket,login_pathwould redirect to the App Store URL (302). This means ANY unauthenticated request to an authenticated route (dashboard, messages, catalog, profile) will ultimately redirect to the App Store. This is the intended behavior per the issue scope ("auth happens in-app only"), but the implementing agent should be aware of this global behavior change. - sessions/new.html.erb: Currently renders a "Sign in with Keycloak" button (6 lines). Must be removed or replaced. The tab bar (shared/_tab_bar.html.erb) is only rendered for authenticated users, so no impact there.
- OmniAuth callback: The OmniAuth callback route (
/auth/keycloak/callback) must remain functional — the iOS app's Turbo Native shell uses it for in-app Keycloak login. Only the website's direct login entry point changes; the callback endpoint stays.
Decomposition Assessment
4 file targets across 1 repo (under threshold). 8 acceptance criteria total but only 4 net-new (under the >5 threshold for new work). Estimated agent work: ~4 minutes. No decomposition needed.
Recommendations
No action needed.
- [x]
-
Review: Tab bar restructure to Catalog / Projects / Communications / Account + CRM
review-1829-2026-07-17Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, supersedes #10
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- present
- [x] Context -- present
- [x] File Targets -- present (but incomplete, see below)
- [x] Feature Flag -- none, structural change
- [x] Acceptance Criteria -- 7 items
- [x] Test Expectations -- 4 items + run command
- [x] Constraints -- present (but stale reference)
- [x] Checklist -- present
- [x] Related -- present
Traceability
- [x] story:navigation label -- "Bottom tab bar with role-correct tabs"
- [x] story note verified -- found in project-iss user-stories section (Epic 2 + role-tab matrix, All roles)
- [x] arch:frontend label -- present on board item
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-frontend for the frontend component
- [x] Forgejo issue -- #49, open
File Targets
Listed targets (all verified):
- [x]
app/views/layouts/application.html.erb-- verified: renders tab bar partial at line 27 - [x]
app/views/shared/_tab_bar.html.erb-- verified: tab bar partial with role logic via visible_tabs - [x]
app/helpers/navigation_helper.rb-- verified: TAB_ROLES constant at line 14 with old structure (catalog, messages, profile, admin) - [x]
app/assets/stylesheets/tab_bar.css-- verified: exists, uses design tokens from application.css - [x]
config/routes.rb-- verified: exists, but NO routes for /projects, /communications, /account, /crm
Missing from file targets (blast radius):
- [ ]
test/controllers/tab_bar_test.rb-- ISSUE: hardcodes old tab names (Messages, Profile, Admin) and counts (3 for lead/client, 4 for admin). Will break. - [ ]
test/helpers/navigation_helper_test.rb-- ISSUE: asserts TAB_ROLES keys are [:catalog, :messages, :profile, :admin] (line 34). Asserts lead/client see [:catalog, :messages, :profile]. Asserts tab_icon for old keys. Will break. - [ ]
test/controllers/messages_controller_test.rb-- ISSUE: line 58 references "lead sees Messages tab as active". Will break if tab key changes. - [ ]
app/views/messages/index.html.erb-- ISSUE: sets content_for(:current_tab, "messages"), needs update to "communications" - [ ]
app/views/messages/inbox.html.erb-- ISSUE: sets content_for(:current_tab, "messages"), needs update to "communications" - [ ]
app/views/admin/catalog/index.html.erb-- ISSUE: sets content_for(:current_tab, "admin"), needs update to "crm" - [ ]
app/views/admin/catalog/show.html.erb-- ISSUE: sets content_for(:current_tab, "admin"), needs update to "crm" - [ ]
app/views/admin/catalog/new.html.erb-- ISSUE: sets content_for(:current_tab, "admin"), needs update to "crm" - [ ]
app/views/admin/catalog/edit.html.erb-- ISSUE: sets content_for(:current_tab, "admin"), needs update to "crm"
Repo Placement
OK -- issue filed on ldraney/intelligentstaffingsystems, all file targets are in that repo. Single-repo change.
Dependencies
- #10 (Bottom tab bar navigation) -- done, superseded by this ticket. OK.
- #42 (Turbo Streams live delivery) -- in todo, messaging related, not blocking this ticket.
- No blocking dependencies found on the board.
Acceptance Criteria
7 AC items, all testable in principle:
- Tab counts per role -- testable via assert_select on rendered HTML
- Active tab indicator -- testable via assert_select for active CSS class
- Tab icons and labels -- testable via assert_select for .tab-bar__icon and .tab-bar__label
- TAB_ROLES enforcement -- testable via unit test on NavigationHelper
- Turbo Native WebView -- testable by checking data-turbo-action attribute (no full page reload)
- Old tabs removed -- testable by asserting absence of Messages, Profile, Admin labels
Gap: No AC specifies what happens when a user clicks a tab whose controller hasn't shipped yet (Projects, Account, CRM). The existing codebase comment says 404s are expected, but the issue says "ensure routes exist for all tab landing pages" -- these contradict.
Blast Radius
- content_for(:current_tab) renames: 8 view files set current_tab with old keys (messages, admin). Renaming tab keys without updating these views means no tab will highlight as active on those pages.
- Test suite: 3 test files hardcode old tab structure -- all will fail after this change.
- docs/user-stories.md: Still references old tab names (Catalog, Messages, Profile). Not critical for this ticket but should be noted for follow-up.
Decomposition Assessment
5 explicit file targets + ~9 blast radius files = ~14 files, all in 1 repo, all the same conceptual change (tab rename/restructure). 7 AC items. Estimated agent work: 3-5 minutes. No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-frontendfor the frontend component in pal-e-docs.[BODY]Add missing file targets for tests:test/controllers/tab_bar_test.rb,test/helpers/navigation_helper_test.rb,test/controllers/messages_controller_test.rb(line 58).[BODY]Add blast-radius view files to file targets:app/views/messages/index.html.erb,app/views/messages/inbox.html.erb,app/views/admin/catalog/{index,show,new,edit}.html.erb-- all need content_for(:current_tab) key renames.[BODY]Clarify route strategy: should placeholder routes be added for/projects,/communications,/account,/crm, or are 404s expected? Current routes.rb has none of these.[BODY]Fix stale constraint reference:docs/ui-ux.mdhas been deleted. Update to referenceapp/assets/stylesheets/application.css :rootfor design tokens.
-
Review: In-app registration: phone number field + email verification
review-1831-2026-07-17Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:registration label — Epic 1 (US-1.2–1.4), Visitor/Lead
- [x] story note verified — found in project-iss user-stories section
- [x] arch:auth label — authentication component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-auth for the auth component
- [x] Forgejo issue — #59, open
File Targets
- [ ]
db/migrate/XXX_add_phone_to_leads.rb— ISSUE: phone column already exists in schema (created in20260705000002_create_leads.rb). No migration needed. The field is namedphone, notphone_number. - [x]
app/models/lead.rb— verified: exists, already hasvalidates :phone, presence: true. No model changes needed for phone field. - [x]
app/controllers/sessions_controller.rb— verified: exists, walk-in creation usesphone: "Not provided"placeholder at line 109. Needs update to extract phone from Keycloak userinfo/token claims. - [ ]
keycloak-theme/iss/login/— ISSUE: directory exists but the current theme is CSS-only withparent=keycloak(inherits default registration form). Adding a custom phone attribute to the registration form requires aregister.ftlFreeMarker template, not just CSS. The ticket does not mention creating this template. - [ ] Keycloak realm config (pal-e-services tfvars) — ISSUE: this file lives in the pal-e-services repo, not intelligentstaffingsystems. Cross-repo dependency not explicitly called out.
- [ ]
app/views/pages/home.html.erb(listed as “not to touch”) — ISSUE: file does not exist. Minor inaccuracy in the “don’t touch” list.
Repo Placement
The Forgejo issue is filed on
ldraney/intelligentstaffingsystems, but two file targets live in other repos:- Keycloak realm config (email verification, phone attribute) — lives in
pal-e-servicestfvars - keycloak-theme/iss/login/ — lives in THIS repo (OK)
The pal-e-services changes (enabling email verification, adding phone as a required user attribute) should either be a separate Forgejo issue on pal-e-services, or the cross-repo dependency should be explicitly documented in this issue’s Constraints section.
Dependencies
- #6 (Keycloak OIDC auth) — done (closed), prerequisite satisfied
- #8 (Lead model + registration) — done (closed), prerequisite satisfied
- #58 (Landing page) — backlog, open. Not a blocker; related but independent
- #16 (Postmark email integration) — backlog, sprint 5. Potential undocumented dependency: AC #5 says “Keycloak sends verification email via Postmark SMTP”. Keycloak needs SMTP credentials configured in realm settings to send verification emails. If Postmark SMTP is not yet configured in Keycloak, this ticket is blocked. Clarify whether Keycloak SMTP is already configured or if this depends on #16.
Acceptance Criteria
9 acceptance criteria. All are generally testable but several concerns:
- AC #5 (“Keycloak sends verification email via Postmark SMTP”) — conflates Keycloak realm SMTP config with the Rails Postmark integration (#16). Keycloak has its own SMTP config independent of Rails. Clarify which layer owns this.
- AC #8 (“Lead record created/claimed on first login per existing resolution ladder”) — this already works today. Not a new criterion but a regression guard. OK as written.
- Test commands are valid:
rails test test/controllers/sessions_controller_test.rb test/models/lead_test.rb— both test files exist.
Blast Radius
- The existing web registration form (
leads/new.html.erb,LeadsController) still exists. The ticket says “The website has NO registration form — all registration is in-app” but does not scope removing or disabling the existing web form. This creates a contradictory state. Should the existing web form be removed in this ticket or a follow-up? - The
keycloak-themechange (adding register.ftl) could affect login page appearance if not carefully scoped to registration only. - Existing tests reference
phonefield extensively (model tests, fixture data, profile tests, leads controller tests). Changes to phone handling in sessions_controller should not break these.
Decomposition Assessment
File targets span 2 repos (intelligentstaffingsystems + pal-e-services). 9 acceptance criteria exceeds the 5 AC threshold. The work naturally splits into:
- (a) Keycloak infrastructure: enable email verification + add phone user attribute (pal-e-services issue)
- (b) Rails code: extract phone from OIDC token in sessions_controller + update tests (ISS issue, small)
- (c) Keycloak theme: add register.ftl with phone field + ISS branding (ISS issue, moderate)
Borderline for decomposition. If the pal-e-services work is split out as a separate issue, the remaining ISS work (b + c) is ~5 min. Recommend splitting pal-e-services config into its own issue rather than full decomposition via skill-decompose-ticket.
Recommendations
[BODY]Remove file targetdb/migrate/XXX_add_phone_to_leads.rb— phone column already exists in schema. No migration needed.[BODY]Fix field name inconsistency: the column isphone, notphone_number. Update issue title or body to match.[BODY]Add file targetkeycloak-theme/iss/login/register.ftl— a FreeMarker template is needed to add the phone field to Keycloak registration. CSS-only theme cannot add form fields.[BODY]Clarify cross-repo dependency: pal-e-services tfvars changes (enable email verification, add phone attribute) should be a separate Forgejo issue on pal-e-services, or explicitly documented as a prerequisite.[BODY]Removeapp/views/pages/home.html.erbfrom the “not to touch” list — file does not exist.[BODY]Clarify AC #5: does Keycloak SMTP need to be configured as part of this ticket, or is it already done? If not done, this ticket depends on Keycloak SMTP setup (which may or may not be #16).[BODY]Address the existing web registration form (leads/new.html.erb): should it be removed/disabled in this ticket or tracked separately?[SCOPE]Create architecture notearch-authfor the authentication component in pal-e-docs.
-
Review: Landing page: sales pitch with App Store download CTA
review-1830-2026-07-17Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:landing-page label -- Epic 1 (US-1.1), Visitor role
- [x] story note verified -- found in project-iss user-stories section (key: landing-page, success metric: "Landing page renders publicly, mobile-first")
- [x] arch:frontend label -- frontend component
- [ ] arch note MISSING -- [SCOPE] Create architecture note arch-frontend for component frontend
- [x] Forgejo issue -- ldraney/intelligentstaffingsystems#58, open
File Targets
- [ ]
app/views/pages/home.html.erb-- ISSUE: File does not exist. The actual landing page view isapp/views/pages/landing.html.erb. Route confirms:root "pages#landing". - [x]
app/assets/stylesheets/pages.css-- verified: exists (7.0k), contains CTA section styling (.cta-section, .btn-primary, .btn-gold) - [x]
app/controllers/sessions_controller.rb-- verified: exists, currently renders Keycloak sign-in button via sessions#new action - [x]
config/routes.rb-- verified: exists, login route at line 30 maps GET /login to sessions#new
Repo Placement
OK -- issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo. Single-repo change.
Dependencies
- #7 (Landing page, sprint:2) -- in done. This ticket updates scope of #7 (CTA changes from login to App Store download). No blocker.
- #59 (board item 1831, sprint:A, arch:auth, story:registration) -- related. In-app registration flow that follows the App Store download. Not a blocker for this ticket, but the two tickets form a pair: this one sends visitors to the App Store, #59 handles what happens after they open the app.
- #49 (board item 1829, sprint:A, arch:frontend, story:navigation) -- same sprint, both touch frontend. Minimal file overlap (tab bar vs landing page). No blocker.
- No items in in_progress or next_up block this ticket.
Acceptance Criteria
8 criteria listed. Assessment of testability:
- AC1 (public landing page) -- testable via endpoint test. Already satisfied: PagesController skips auth, root route is public.
- AC2 (ISS pitch, three pillars) -- testable via content assertions. Already satisfied: landing.html.erb has hero section, three pillar cards, journey steps, offer section.
- AC3 (App Store download button) -- testable via presence check in rendered HTML. New work.
- AC4 (App Store link opens store) -- testable via link href check. New work.
- AC5 (no login form on website) -- testable: verify sessions/new.html.erb is removed or redirects. New work.
- AC6 (login route redirects to App Store) -- testable via endpoint test (302). New work.
- AC7 (responsive, mobile-first) -- partially testable via CSS assertions. Already mostly satisfied: pages.css has responsive breakpoints.
- AC8 (target audience messaging) -- testable via content check. Already partially satisfied.
Net-new work covers 4 criteria (AC3-6); 4 criteria verify existing behavior. All are testable by an agent.
Blast Radius
- Auth redirect chain:
application_controller.rb:59redirects unauthenticated users tologin_path. Under this ticket,login_pathwould redirect to the App Store URL (302). This means ANY unauthenticated request to an authenticated route (dashboard, messages, catalog, profile) will ultimately redirect to the App Store. This is the intended behavior per the issue scope ("auth happens in-app only"), but the implementing agent should be aware of this global behavior change. - sessions/new.html.erb: Currently renders a "Sign in with Keycloak" button. Must be removed or replaced. The tab bar (shared/_tab_bar.html.erb) is only rendered for authenticated users, so no impact there.
- OmniAuth callback: The OmniAuth callback route (
/auth/keycloak/callback) must remain functional -- the iOS app's Turbo Native shell uses it for in-app Keycloak login. Only the website's direct login entry point changes; the callback endpoint stays.
Decomposition Assessment
4 file targets across 1 repo (under threshold). 8 acceptance criteria (over the >5 threshold). However, 4 ACs verify existing behavior and require no code changes -- net-new work is 4 cohesive criteria: add App Store CTA (AC3-4) and redirect login (AC5-6). Estimated agent work: ~4 minutes. No decomposition needed.
Recommendations
[BODY]Fix file path:app/views/pages/home.html.erbdoes not exist. Correct path isapp/views/pages/landing.html.erb.[SCOPE]Create architecture notearch-frontendfor the frontend component in pal-e-docs.
-
Review: Admin user management and promotion
review-1794-2026-07-06cVerdict: APPROVED
Re-review of board item #1794 after body fixes. Previous review
review-1794-2026-07-06bfound 5 issues. Three [BODY] fixes applied; [SCOPE] arch-rails note remains a standing recommendation; [DECOMPOSE] explicitly deferred by owner for Sprint 5 momentum.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Depends on #6, #8, #13; Sprint 5
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- Admin pipeline management
- [x] Context -- References US-6.1, US-6.2, related docs (security.md, architecture.md, testing-strategy.md)
- [x] File Targets -- 11 files listed, all verified
- [x] Feature Flag -- "none"
- [x] Acceptance Criteria -- 13 items, all specific and testable
- [x] Test Expectations -- Four-case matrix, model tests, service test, run command
- [x] Constraints -- KeycloakAdminService, PaperTrail, docs-in-PR, JS confirm(), server-side filtering
- [x] Checklist -- Present
- [x] Related -- Project, blockers, user stories
Traceability
- [x] story:admin label -- Epic 6 (US-6.1-6.2): "Pipeline list; lead-to-client promotion with audit"
- [x] story note verified -- found in project-iss user-stories section (admin row, Epic 6)
- [ ] arch:rails note MISSING -- [SCOPE] Create architecture note arch-rails in pal-e-docs (standing recommendation from previous review; does not block ticket execution)
- [x] Forgejo issue -- ldraney/intelligentstaffingsystems#14, open
File Targets
- [x]
Gemfile-- verified: exists, paper_trail gem not yet present (expected for new addition) - [x]
app/controllers/admin/users_controller.rb-- NEW: admin/ dir exists with catalog_controller.rb as pattern; require_role :admin pattern established - [x]
app/views/admin/users/index.html.erb-- NEW: admin/views dir exists (catalog/ present) - [x]
app/views/admin/users/show.html.erb-- NEW - [x]
app/assets/stylesheets/admin.css-- NEW: stylesheets/ dir exists with 9 existing files - [x]
app/services/keycloak_admin_service.rb-- verified: EXISTS with get_user and update_user class methods; assign_realm_role(user_sub, role_name) to be added (FIXED from previous review) - [x]
db/migrate/xxx_create_versions.rb-- NEW: PaperTrail versions table migration - [x]
app/models/lead.rb-- verified: has role enum (lead/client/admin), promoted_at column in schema - [x]
config/routes.rb-- verified: admin namespace at lines 37-39; users routes to be added - [x]
app/helpers/navigation_helper.rb-- verified: admin tab currently hardcoded to /admin/catalog (line 18); needs update (FIXED from previous review -- now in file targets) - [x]
test/controllers/admin/users_controller_test.rb-- NEW: test/controllers/admin/ dir exists with catalog_controller_test.rb as pattern
Repo Placement
OK -- issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo.
Dependencies
- #6 (Keycloak OIDC auth) -- in validation column; auth infrastructure delivered to main
- #8 (Lead model) -- in validation column; Lead model exists with role enum and promoted_at column
- #13 (Profile view) -- in validation column; introduced KeycloakAdminService with get_user/update_user
- All three blockers have delivered code to main. Dependencies satisfied at the code level.
Acceptance Criteria
- 13 AC items -- all specific and testable
- Previous ambiguities resolved: role filter is server-side query param (?role=lead); confirmation is JS confirm()
- Test expectations include four-case role matrix, PaperTrail version test, and Keycloak service test
- Run command:
rails test
Blast Radius
- Navigation tab: navigation_helper.rb now explicitly in file targets (line 18 hardcodes /admin/catalog). Agent will update the admin tab path.
- Session role snapshot: AC #12 addresses re-login requirement ("Note in UI or docs: promoted user must re-login for new role to take effect"). Covered.
- No cross-repo impact: All changes contained within this repo.
Decomposition Assessment
- 11 file targets in 1 repo -- passes the >3 across >2 repos check
- 13 acceptance criteria -- exceeds the >5 threshold
- Estimated agent work: likely >5 minutes (6 new files + 5 modifications)
- Owner decision: decomposition explicitly deferred for Sprint 5 momentum. Ticket is well-scoped despite size -- all AC are specific, file targets verified, mechanisms defined. Acceptable risk for a single-repo feature with established patterns.
Previous Review Issues -- Resolution Status
- [BODY] KeycloakAdminService added to file targets with assign_realm_role -- FIXED
- [BODY] Role filter specified as server-side query param -- FIXED
- [BODY] Confirmation dialog specified as JS confirm() -- FIXED
- [SCOPE] arch-rails note -- STANDING RECOMMENDATION (does not block ticket execution)
- [DECOMPOSE] -- EXPLICITLY DEFERRED by owner (Sprint 5 momentum)
Recommendation
No action needed. All [BODY] fixes applied. Ticket is APPROVED for execution.
[SCOPE]Standing: Create architecture note arch-rails in pal-e-docs (non-blocking)
-
Review: Appointment booking and calendar
review-1795-2026-07-06-r3Verdict: APPROVED
Re-review (r3) after body fixes. All 4 issues from
review-1795-2026-07-06-r2have been resolved.R2 Issues Resolved
- [x]
[BODY]Addedapp/models/lead.rbto File Targets — now listshas_many :appointmentsassociation - [x]
[BODY]Addedapp/controllers/leads_controller.rbto File Targets — now specifies redirect change and placeholder removal - [x]
[BODY]Addedapp/views/leads/booking.html.erbto File Targets — marked for deletion - [x]
[BODY]Specified lead_id flow in Context — stateless vianew_appointment_path(lead_id: @lead.id)redirect, hidden field in booking form
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All required sections for the Feature template are present.
Traceability
- [x] story:registration label — Epic 1 (US-1.2–1.4), Role: Visitor/Lead
- [x] story note verified — found in project-iss user-stories section (row: "registration", backing "Epic 1 (US-1.2–1.4)")
- [x] arch:rails label — Rails application component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-rails for the Rails component in pal-e-docs (carried forward from r2; platform-level gap, not a ticket body issue)
- [x] Forgejo issue —
ldraney/intelligentstaffingsystems#15, open
File Targets
- [x]
app/models/appointment.rb— verified: does not exist, to be created. Architecture.md confirms Appointment entity - [x]
app/models/lead.rb— verified: exists (line 4 hashas_many :messages, no appointments yet). Correctly targeted for addinghas_many :appointments - [x]
db/migrate/xxx_create_appointments.rb— verified: no appointments table in schema.rb, migration needed - [x]
app/controllers/appointments_controller.rb— verified: does not exist, to be created. security.md documents this controller as skipping auth - [x]
app/controllers/leads_controller.rb— verified: exists, has placeholderbookingaction (line 23) and redirect tobooking_path(line 16). Both correctly targeted for update/removal - [x]
app/views/appointments/new.html.erb— verified: directory does not exist, to be created - [x]
app/views/appointments/create.html.erb— verified: to be created - [x]
app/views/leads/booking.html.erb— verified: exists (placeholder "coming soon" view). Correctly targeted for deletion - [x]
app/assets/stylesheets/appointments.css— verified: does not exist, to be created - [x]
config/routes.rb— verified: exists, has placeholder booking route at line 7. Must be replaced with appointments routes - [x]
test/models/appointment_test.rb— verified: does not exist, to be created - [x]
test/controllers/appointments_controller_test.rb— verified: does not exist, to be created - [x]
docs/user-stories.md— verified: exists, Open Questions #1 (line 315) documents "Calendly embed vs custom booking" — needs update to record custom scheduling decision
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo. Single-repo ticket.
Dependencies
- Depends on #8 (Lead model, migration, registration form) — board item #1788 is in
validationcolumn. Dependency satisfied. - Email deferred to #16 (Postmark integration) — documented in Constraints and Context. No blocking issue.
- No undocumented blockers found on the board.
Acceptance Criteria
10 ACs — all are clear and testable by an agent. The lead_id flow is now fully specified (stateless via URL param + hidden field). Placeholder cleanup is covered by AC #8. Docs update covered by ACs #9 and #10.
Blast Radius
docs/security.mdalready documentsAppointmentsControlleras skipping auth (lines 50, 108, 183) — good alignment.docs/testing-strategy.mdalready has a #15 row (line 181) — good alignment.- Landing page CTAs link to
#bookanchor (not a route) — no change needed. - Dashboard view has an "Appointments" heading (line 65 of
dashboard/show.html.erb) — placeholder, may need wiring in a future ticket. - Rate limiting for unauthenticated writes (security.md line 195) — not blocking, follow-up concern.
Decomposition Assessment
13 file targets in 1 repo, 10 ACs. Exceeds the >5 AC threshold, but the work is a cohesive single-feature CRUD flow (model + controller + views + tests + placeholder cleanup). Decomposition would fragment a natural unit. Estimated agent work: ~4 minutes. No decomposition needed.
Recommendations
[SCOPE]Create architecture notearch-railsfor the Rails component in pal-e-docs (carried forward from r2 — platform-level gap affecting multiple tickets, not specific to this one)
No body or label fixes needed. Ticket is ready for implementation.
- [x]
-
Review: Appointment booking and calendar
review-1795-2026-07-06-r2Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All required sections for the Feature template are present.
Traceability
- [x] story:registration label — Epic 1 (US-1.2–1.4), Role: Visitor/Lead
- [x] story note verified — found in project-iss user-stories section (row: "registration", backing "Epic 1 (US-1.2–1.4)")
- [x] arch:rails label — Rails application component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-rails for the Rails component in pal-e-docs
- [x] Forgejo issue —
ldraney/intelligentstaffingsystems#15, open
File Targets
- [x]
app/models/appointment.rb— verified: does not exist, to be created. Architecture.md confirms Appointment entity (uuid id, uuid lead_id FK, datetime scheduled_at, string status, text notes) - [x]
db/migrate/xxx_create_appointments.rb— verified: no appointments table in schema.rb, migration needed - [x]
app/controllers/appointments_controller.rb— verified: does not exist, to be created. security.md already documents this controller as skipping auth - [x]
app/views/appointments/new.html.erb— verified: appointments view directory does not exist, to be created - [x]
app/views/appointments/create.html.erb— verified: to be created - [x]
app/assets/stylesheets/appointments.css— verified: does not exist, to be created - [x]
config/routes.rb— verified: exists, has placeholder booking route at line 7 (get "booking", to: "leads#booking") that must be replaced - [x]
test/models/appointment_test.rb— verified: does not exist, to be created - [x]
test/controllers/appointments_controller_test.rb— verified: does not exist, to be created - [x]
docs/user-stories.md— verified: exists, Open Questions #1 (line 315) documents "Calendly embed vs custom booking" — needs update to record the custom scheduling decision - [ ]
app/models/lead.rb— MISSING from file targets. Lead model currently hashas_many :messagesbut nohas_many :appointmentsassociation. AC says "Appointment linked to Lead record" — this file must be modified. - [ ]
app/controllers/leads_controller.rb— MISSING from file targets. Currently redirects tobooking_path(line 16) and has a placeholderbookingaction (lines 22-24). Both must be updated: redirect target changes to the new appointment route, placeholder action removed. - [ ]
app/views/leads/booking.html.erb— MISSING from file targets. Existing placeholder booking view ("Appointment booking is coming soon") must be removed when the real appointments flow lands.
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo. Single-repo ticket.
Dependencies
- Depends on #8 (Lead model, migration, registration form) — board item #1788 is in
validationcolumn. Dependency satisfied. - Email deferred to #16 (Postmark integration) — documented in Constraints and Context. No blocking issue.
- #42 (Turbo Streams) is in
todo— unrelated, no dependency. - No undocumented blockers found on the board.
Acceptance Criteria
9 ACs — all are clear and testable by an agent. Two gaps:
- Lead ID flow unspecified — AC says "Appointment record created with lead_id" and "Appointment linked to Lead record", but the issue does not specify how
lead_idflows from registration to the booking form. The current redirect (redirect_to booking_path) does not pass a lead reference. Options: session storage, URL param (new_appointment_path(lead_id: @lead.id)), or nested route. The agent needs this decision made. - Placeholder cleanup not covered — no AC addresses removal of the existing placeholder booking route, controller action, and view.
Blast Radius
docs/security.mdalready documentsAppointmentsControlleras skipping auth (lines 50, 108, 183) — good alignment, no update needed unless implementation diverges.docs/testing-strategy.mdalready has a #15 row (line 181) — good alignment.- Landing page CTAs link to
#bookanchor (not a route) — no change needed. - Dashboard view has an "Appointments" heading (line 65 of
dashboard/show.html.erb) — currently a placeholder, may need wiring to show upcoming appointments in a future ticket. docs/security.mdline 195 flags rate limiting as an open concern for unauthenticated writes (registration + booking). Not blocking, but worth noting for a follow-up.
Decomposition Assessment
10 file targets in 1 repo — single-repo threshold not hit. 9 ACs — exceeds the >5 AC threshold. Estimated agent work: ~4 minutes (standard Rails model + controller + views + tests scaffolding). The work is a cohesive single-feature CRUD flow; decomposition would fragment a natural unit. Recommend keeping as a single ticket if the body issues below are fixed, but flagging the >5 AC threshold for awareness.
Recommendations
[BODY]Addapp/models/lead.rbto File Targets — needshas_many :appointments, dependent: :destroyassociation[BODY]Addapp/controllers/leads_controller.rbto File Targets — update redirect frombooking_pathto new appointment path, remove placeholderbookingaction[BODY]Addapp/views/leads/booking.html.erbto File Targets as a file to remove[BODY]Specify in Context or Constraints howlead_idflows from registration to appointment creation (session, URL param, or nested route)[SCOPE]Create architecture notearch-railsfor the Rails component in pal-e-docs
-
Review: Admin user management and promotion
review-1794-2026-07-06bVerdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Present (depends on #6, #8, #13)
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — Present (admin pipeline management)
- [x] Context — Present, references US-6.1, US-6.2, related docs
- [x] File Targets — Present (9 files listed)
- [x] Feature Flag — Present ("none")
- [x] Acceptance Criteria — Present (11 items)
- [x] Test Expectations — Present (four-case matrix, model tests)
- [x] Constraints — Present (KeycloakAdminService, PaperTrail, docs-in-PR)
- [x] Checklist — Present
- [x] Related — Present (project, blockers, user stories)
Traceability
- [x] story:admin label — Epic 6 (US-6.1–6.2): "Pipeline list; lead-to-client promotion with audit"
- [x] story note verified — found in project-iss user-stories section (admin row, Epic 6)
- [ ] arch:rails note MISSING — [SCOPE] Create architecture note arch-rails for the Rails component in pal-e-docs
- [x] Forgejo issue — ldraney/intelligentstaffingsystems#14, open
File Targets
- [x]
Gemfile— verified: exists, paper_trail gem not yet present (expected) - [x]
app/controllers/admin/users_controller.rb— NEW: admin/ dir exists with catalog_controller.rb as pattern - [x]
app/views/admin/users/index.html.erb— NEW: admin/views dir exists (catalog/ present) - [x]
app/views/admin/users/show.html.erb— NEW - [x]
app/assets/stylesheets/admin.css— NEW: stylesheets/ dir exists with 8 existing files - [x]
db/migrate/xxx_create_versions.rb— NEW: migration, timestamp generated at create time - [x]
app/models/lead.rb— verified: has role enum (lead/client/admin), promoted_at column in schema - [x]
config/routes.rb— verified: admin namespace already exists (line 37-39) - [x]
test/controllers/admin/users_controller_test.rb— NEW: test/controllers/admin/ dir exists - [ ]
app/services/keycloak_admin_service.rb— MISSING from file targets. Service currently only has get_user and update_user. Keycloak realm role assignment requires the role-mappings endpoint. A new assign_realm_role method is needed. [BODY]
Repo Placement
OK — issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo.
Dependencies
- #6 (Keycloak OIDC auth) — in validation column; auth infrastructure is in the codebase
- #8 (Lead model, migration, registration form) — in validation column; Lead model exists with role enum and promoted_at
- #13 (Profile view, edit, and logout) — in validation column; introduced KeycloakAdminService with get_user/update_user
- All three blockers have delivered code to main. Dependencies are satisfied at the code level, though all are still in validation.
Acceptance Criteria
- 11 AC items — exceeds the >5 threshold for decomposition
- AC #5 "Sortable/filterable by role" is underspecified — no mechanism stated (server-side query params vs client-side Stimulus/JS)
- AC #7 "Promotion updates Keycloak role AND Lead.role" — requires KeycloakAdminService extension not listed in file targets
- AC #8 "Confirmation dialog before promotion" — mechanism unspecified (JS confirm(), Turbo modal, or separate confirmation page)
- Test expectations are testable: four-case role matrix pattern is well-established in the codebase
Blast Radius
- Navigation tab: navigation_helper.rb currently points the Admin tab to /admin/catalog. After adding admin users, the admin section may need sub-navigation or the tab target may need updating. Not addressed in the ticket.
- Session role snapshot: SessionsController syncs Lead.role from Keycloak token at login. A promoted user's session will not reflect the new role until re-login. The security.md reference ("roles are a login-time snapshot") covers the design, but no AC addresses informing the admin of this behavior.
- No cross-repo impact: All changes contained within this repo.
Decomposition Assessment
- 9 file targets in 1 repo — passes the >3 across >2 repos check
- 11 acceptance criteria — FAILS the >5 threshold
- Estimated agent work: 6 new files + 3 modifications + KeycloakAdminService extension = likely >5 minutes
- NEEDS DECOMPOSITION — route to skill-decompose-ticket
Suggested decomposition:
- PaperTrail setup + KeycloakAdminService role-mapping method (AC 1, 2, partial 7)
- Admin users list view with role filtering and auth gating (AC 3, 4, 5, 10)
- User detail page + promotion flow + docs update (AC 6, 7, 8, 9, 11)
Recommendation
[BODY]Add app/services/keycloak_admin_service.rb to File Targets — promote action requires a new assign_realm_role method for the Keycloak role-mappings API endpoint[BODY]Clarify AC #5 "Sortable/filterable by role" — specify mechanism (server-side query param filtering vs client-side JS/Stimulus)[BODY]Clarify AC #8 "Confirmation dialog" — specify mechanism (JS confirm(), Turbo modal, or Rails confirmation page)[SCOPE]Create architecture note arch-rails for the Rails component in pal-e-docs[DECOMPOSE]11 AC across 9+ files, estimated >5 min agent work. Route to skill-decompose-ticket
-
Review: Admin user management and promotion
review-1794-2026-07-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Depends on #6, #8. Sprint 5.
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — As an admin, I want to see all leads/clients and promote leads
- [x] Context — Admin-only view, promote button, Keycloak admin API
- [x] File Targets — 3 files listed (but incomplete, see below)
- [x] Feature Flag — none
- [x] Acceptance Criteria — 9 items
- [x] Test Expectations — 3 items + run command
- [x] Constraints — KeycloakAdminService, audit trail, docs-in-PR
- [x] Checklist — present
- [x] Related — project, blockers, user stories listed
All template sections present.
Traceability
- [x] story:admin label — Epic 6 (US-6.1, US-6.2)
- [x] story note verified — found in project-iss user-stories section (Key "admin", backing "Epic 6 (US-6.1–6.2)", role "Admin", metric "Pipeline list; lead→client promotion with audit")
- [x] arch:rails label — Rails application component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-rails for component rails
- [x] Forgejo issue — ldraney/intelligentstaffingsystems#14, open
File Targets
- [x]
app/controllers/admin/users_controller.rb— verified: directory does not exist yet, correct for new file creation - [x]
app/views/admin/users/— verified: directory does not exist yet, correct for new views - [x]
app/assets/stylesheets/admin.css— verified: file does not exist yet, correct for new stylesheet - [ ]
app/services/keycloak_admin_service.rb— MISSING from File Targets. Service exists but only hasget_userandupdate_usermethods. Keycloak role assignment requires a different API endpoint (POST /admin/realms/{realm}/users/{id}/role-mappings/realm). A new method (e.g.assign_realm_role) must be added for promotion to work. - [ ]
config/routes.rb— MISSING from File Targets. No admin namespace routes exist; must be added. - [ ]
app/models/lead.rb— MISSING from File Targets. Model needs apromote!method and PaperTrail integration (if kept). Currently has role enum and promoted_at in schema but no promotion logic. - [ ]
Gemfile— MISSING from File Targets. Constraints reference PaperTrail for audit trail but the gem is not installed.
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems, all file targets are in that repo. Single-repo scope.
Dependencies
- #6 (Keycloak OIDC auth) — in validation column. Provides session/auth infrastructure. Required.
- #8 (Lead model) — in validation column. Provides Lead model with role enum, promoted_at column. Required.
- #13 (Profile view, edit, logout) — in validation column. Introduced KeycloakAdminService. Required for the admin API client. Issue body correctly identifies this dependency in Constraints.
- All three blockers are in validation, not yet done. Ticket cannot move to in_progress until blockers reach done.
Acceptance Criteria
- 9 AC items total. All are verifiable by an agent.
- AC#3 (sortable/filterable by role) — adds frontend complexity. Testable via controller tests with params.
- AC#5 (promotion updates Keycloak role AND Lead.role) — requires KeycloakAdminService extension (see File Targets issue above).
- AC#6 (confirmation dialog) — requires JavaScript. Standard Rails pattern (data-turbo-confirm or similar).
- AC#9 (docs-in-PR rule) — meta-requirement, standard for this project.
- Test expectations reference
rails test— real command, verified.
Blast Radius
- KeycloakAdminService is also used by ProfileController (#13). Extending it with role assignment methods should not affect profile operations.
- Lead.role is synced from Keycloak on every login (sessions_controller.rb line 38-46). After promotion, the user's next login will pick up the new role from Keycloak. The session role is a login-time snapshot (documented in docs/security.md line 270). No blast radius concern.
- No other admin namespace controllers exist — this is the first. No naming conflicts.
Decomposition Assessment
- File targets: 3 listed + 4 unlisted = 7 total, all in 1 repo — below the ">3 files across >2 repos" threshold
- Acceptance criteria: 9 items — exceeds >5 threshold
- Estimated agent work: moderate (controller + views + routes + service extension + model logic + JS confirmation + PaperTrail setup)
- Assessment: borderline. The AC count exceeds the threshold, but all work is in a single domain (admin user management) within one controller namespace. If the File Targets and PaperTrail issues are resolved, a single agent pass is feasible. No decomposition required at this time, but revisit if scope grows.
Recommendations
- [BODY] Add
app/services/keycloak_admin_service.rbto File Targets — needsassign_realm_role(keycloak_sub, role_name)method for Keycloak role mapping API (POST /admin/realms/{realm}/users/{id}/role-mappings/realm). Current service only hasget_userandupdate_user. - [BODY] Add
config/routes.rbto File Targets — needs admin namespace routes (namespace :admin { resources :users, only: [:index, :show] { member { patch :promote } } }or similar). - [BODY] Add
app/models/lead.rbto File Targets — needs promote! method and PaperTrail integration. - [BODY] Clarify PaperTrail dependency: either add
Gemfileto File Targets for PaperTrail gem installation, or remove PaperTrail from Constraints and document thatpromoted_attimestamp alone serves as the audit trail. Note: docs/security.md line 189 also references PaperTrail, so the doc would need updating if PaperTrail is removed from scope. - [SCOPE] Create architecture note
arch-railsfor component rails.
-
Review: Appointment booking and calendar
review-1795-2026-07-06Verdict: NEEDS_REFINEMENT
Board item #1795 — #15 Appointment booking and calendar
Labels:type:feature,arch:rails,story:registration,sprint:5| Points: 3
Forgejo: ldraney/intelligentstaffingsystems#15 (open)Template Completeness
- [x] Type — Feature
- [x] Lineage — Depends on #8 (Lead model). Sprint 5.
- [x] Repo —
ldraney/intelligentstaffingsystems - [x] User Story — present
- [x] Context — present, references US-1.3 and related docs
- [x] File Targets — present (but incomplete, see below)
- [x] Feature Flag — none
- [x] Acceptance Criteria — present (5 items)
- [x] Test Expectations — present
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present
All required template sections are present.
Traceability
- [x] story:registration label — Epic 1 (US-1.2–1.4), Role: Visitor/Lead
- [x] story note verified — found in project-iss user-stories section (key:
registration, backing: "Epic 1 (US-1.2–1.4)") - [x] arch:rails label — Rails application layer
- [ ] arch note MISSING — no
arch-railsnote found in pal-e-docs. However,arch:railsis a categorical technology label applied to ~15 board items, not a specific architecture decision. [SCOPE] Create architecture notearch-railsfor the Rails component, or reclassifyarch:railsas a categorical label that does not require a backing note. - [x] Forgejo issue — #15, open
File Targets
Files to create (listed in issue):
- [x]
app/models/appointment.rb— verified: does not exist yet. architecture.md ER diagram defines Appointment with uuid id PK, uuid lead_id FK, datetime scheduled_at, string status, text notes. - [x]
db/migrate/xxx_create_appointments.rb— verified: no appointments migration exists yet. Schema has no appointments table. - [x]
app/controllers/appointments_controller.rb— verified: does not exist yet. security.md Controller Role Map expectsAppointmentsControllerto skip auth. - [x]
app/views/appointments/new.html.erb— verified: does not exist yet.
Files that should be modified (MISSING from issue):
- [ ]
config/routes.rb— ISSUE: not listed. Currently has a placeholderget "booking", to: "leads#booking"(line 7). Must be updated to add appointment resources and remove/replace the placeholder route. - [ ]
app/controllers/leads_controller.rb— ISSUE: not listed. Has placeholderbookingaction (line 23) and redirects tobooking_pathafter registration (line 16). Both need updating. - [ ]
app/views/leads/booking.html.erb— ISSUE: not listed. Placeholder file ("Appointment booking is coming soon") that should be removed when the real implementation lands. - [ ]
test/models/appointment_test.rb— ISSUE: test file not listed in File Targets, though Test Expectations mention model tests. - [ ]
test/controllers/appointments_controller_test.rb— ISSUE: test file not listed in File Targets, though Test Expectations mention controller tests. - [ ]
test/fixtures/appointments.yml— ISSUE: fixture file not listed.
Repo Placement
OK. Issue filed on
ldraney/intelligentstaffingsystems, fix is in the same repo. Single-repo change.Dependencies
- #8 Lead model (board item #1788) — in
validationcolumn (near-done). Lead model exists with all fields. Thelead_id FKon Appointment depends on this. Dependency satisfied. - #16 Postmark email (board item #1796) — in
backlog. AC #4 says "Email triggered after booking (depends on #16)" but #16 has not started. This creates an unresolvable cross-dependency within the ticket scope. The booking ticket should not include email triggering as an acceptance criterion — it should defer to #16. - No blocking items in
in_progress.
Acceptance Criteria
- AC1: "After registration form, user is redirected to booking page" — testable, controller test can verify redirect ✓
- AC2: "Appointment record created with scheduled_at and status" — testable, model + controller tests ✓
- AC3: "Confirmation shown after booking" — testable, integration test ✓
- AC4: "Email triggered after booking (depends on #16)" — NOT testable in this ticket. #16 is in backlog. Must be deferred.
- AC5: "Related docs updated in this PR (docs-in-PR rule)" — testable ✓
5 AC total (at the decomposition threshold) but one should be deferred, bringing effective AC to 4.
Blast Radius
- Existing placeholder flow: Registration (
LeadsController#create) redirects tobooking_pathwhich serves a placeholder page. The agent must update this redirect and remove the placeholder without breaking the registration flow. - Routes: Adding appointment resources changes route helpers. No other controllers reference booking/appointment routes currently.
- Unresolved architectural decision:
docs/user-stories.mdOpen Question #1 explicitly says "Calendly embed vs custom booking — decided at this ticket; write the decision back." The issue body says "MVP can use Calendly embed if custom scheduling is too complex" but the architecture.md ER diagram assumes a custom Appointment model. This ambiguity must be resolved before work starts — the agent needs a clear directive, not a runtime judgment call. - Security surface:
docs/security.mdalready documentsAppointmentsControlleras skipping auth, status as a closed enum, and defensivescheduled_atparsing. These are good guardrails for the agent.
Decomposition Assessment
4 files to create + 3-6 files to modify = 7-10 files total, all in one repo. 4 effective AC (after deferring email). Estimated agent work: ~4 minutes. No decomposition needed — fits in a single agent pass once scope gaps are fixed.
Recommendations
- [BODY] Add modification file targets:
config/routes.rb(add appointment resources, remove/replace placeholderbookingroute),app/controllers/leads_controller.rb(update redirect and remove placeholderbookingaction),app/views/leads/booking.html.erb(remove placeholder). Add test targets:test/models/appointment_test.rb,test/controllers/appointments_controller_test.rb,test/fixtures/appointments.yml. - [BODY] Remove or defer AC #4 ("Email triggered after booking (depends on #16)"). #16 is in backlog — this ticket should stand alone. Email integration is #16's responsibility.
- [BODY] Resolve the Calendly vs custom scheduling decision in the Context section. The architecture.md ER diagram assumes a custom Appointment model. If choosing custom scheduling (recommended, since the model is already designed), state it explicitly. Write the decision back to
docs/user-stories.mdOpen Question #1 as part of the docs-in-PR rule. - [SCOPE] Create architecture note
arch-railsfor the Rails component, or adopt a convention that broad technology labels (arch:rails,arch:frontend,arch:docs) are categorical and do not require backing notes.
-
Review: #42 Turbo Streams live delivery + cable fix (decomp:1792) [re-review]
review-1818-2026-07-06-v2Verdict: READY
Re-review of board item #1818. All three issues from
review-1818-2026-07-06(NEEDS_REFINEMENT) have been resolved.Previous Issues -- Resolution
- [x]
arch-railsnote -- now exists at slugarch-rails(architecture note, status: active) - [x]
db/cable_migrate/in File Targets -- now listed: "create: Solid Cable migration (generated by bin/rails solid_cable:install:migrations)" - [x] Constraints wording -- now says "create docs/messaging.md" with "(file does not exist yet)" clarification
Template Completeness
- [x] Type -- Feature (child of #12)
- [x] Lineage -- Parent #12, decomp:1792, dependencies #40 and #6
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- As a lead or admin, real-time messages
- [x] Context -- Cable.yml redis problem stated, first Turbo Streams usage noted
- [x] File Targets -- 4 targets listed (cable.yml, message.rb, views/messages/, db/cable_migrate/)
- [x] Feature Flag -- None (appropriate)
- [x] Acceptance Criteria -- 3 criteria from parent #12 AC 6-7
- [x] Test Expectations -- broadcast test, turbo frame response test, run command
- [x] Constraints -- Solid Cable, docs-in-PR (create), CSRF reference
- [x] Checklist -- 7 items
- [x] Related -- Project, parent, sibling, blockers, US references
Traceability
- [x] story:messaging label -- verified in project-iss user-stories section (Epic 4, US-4.1-4.2, role: Lead/Client/Admin)
- [x] story note verified -- found in project-iss user-stories table
- [x] arch:rails label -- arch note verified:
arch-railsnote exists in pal-e-docs (slug: arch-rails, type: architecture, status: active) - [x] Forgejo issue -- ldraney/intelligentstaffingsystems#42, state: open
File Targets
- [x]
config/cable.yml-- verified: exists, production adapter IS redis (line 8) with Redis URL (line 9). Matches ticket claim exactly. - [x]
app/models/message.rb-- does not exist yet. Expected: depends on #40 Message CRUD which creates this file. Dependency documented. - [x]
app/views/messages/-- does not exist yet. Same dependency on #40. Documented. - [x]
db/cable_migrate/-- does not exist yet. database.yml (lines 35-38) references this path for the cable database. Will be created by solid_cable install. Now correctly listed in File Targets. - [x] Gemfile line 33 -- verified: solid_cable gem present. turbo-rails gem present at line 14.
- [x] docs/security.md CSRF (line 200) -- verified: CSRF section at line 198-202 explicitly mentions Turbo Frame submissions for message create #12.
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems, Repo field matches, all file targets are in this repo. Single-repo ticket.
Dependencies
- #40 Message CRUD (board item #1817) -- in next_up column. BLOCKER: message.rb and views/messages/ must exist before this ticket can execute. Dependency is documented in the issue.
- #6 Keycloak OIDC auth (board item #1786) -- in validation column. Further along. Dependency documented.
- Parent #12 (board item #1792) -- in backlog, marked decomposed. This ticket is Sub-B of the decomposition.
- Sibling #40 must complete before this ticket. Ordering constraint is clear.
Acceptance Criteria
3 ACs, all verifiable by an agent:
- AC1: Turbo Frame rendering -- testable via integration test (form submit returns turbo_stream response)
- AC2: Real-time broadcast -- testable via ActionCable broadcast test
- AC3: cable.yml adapter check -- simple file content assertion
Test commands are real (rails test). Criteria are clear and complete.
Blast Radius
Low. Redis references exist ONLY in config/cable.yml (lines 8-9). No other config, deployment, or application files reference Redis. The database.yml cable database entry (lines 35-38) is already prepared for solid_cable. No existing Turbo Streams or ActionCable broadcast patterns in the codebase. This is the first Turbo Streams usage -- no existing patterns to break.
Decomposition Assessment
No decomposition needed.
- 4 file targets in 1 repo -- within limits
- 3 acceptance criteria -- within limits
- Estimated agent work: under 5 minutes (cable.yml edit, model annotation, view partial update, migration, tests)
- 3 points -- appropriately sized
Recommendations
No action needed.
- [x]
-
Review: Message model, migration, controller, and views (CRUD)
review-1817-2026-07-06-r2Verdict: READY
Re-review of board item #1817. Previous review (
review-1817-2026-07-06) returned NEEDS_REFINEMENT solely because thearch-railsarchitecture note did not exist. That note has since been created. All other checks passed in the prior review and are re-confirmed here.Template Completeness
- [x] Type — Feature (child of #12)
- [x] Lineage — parent #12, decomp:1792, dependencies listed
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — "As a lead or admin, I can view and send messages..."
- [x] Context — CRUD foundation for Epic 4, US-4.1/4.2, one thread per lead
- [x] File Targets — 5 create targets listed with descriptions
- [x] Feature Flag — "None" (correct for internal CRUD)
- [x] Acceptance Criteria — 6 ACs from parent #12 AC 1-5, 8
- [x] Test Expectations — model, controller, integration tests; run command provided
- [x] Constraints — docs-in-PR rule, security.md line references, ISS brand palette
- [x] Checklist — 8 items
- [x] Related — project, parent, sibling, blockers, user stories all listed
Traceability
- [x] story:messaging label — present on board item #1817
- [x] story note verified — found in project-iss user-stories section: "messaging", Epic 4 (US-4.1–4.2), Role Lead/Client/Admin, "One thread per lead; admin sees all"
- [x] arch:rails label — present on board item #1817
- [x] arch note verified —
arch-railsnote exists in pal-e-docs (slug: arch-rails, note_type: architecture, status: active). Previously missing; now created. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/40, open
File Targets
- [x]
app/models/message.rb— verified: does not exist yet (create target). Lead model atapp/models/lead.rbconfirmed present withkeycloak_subfield for sender identification. No existinghas_manyassociations on Lead — adding:messagesis safe. - [x]
db/migrate/xxx_create_messages.rb— verified: no existing messages migration. Migration directory exists with 2 existing migrations. - [x]
app/controllers/messages_controller.rb— verified: does not exist yet.require_rolemacro confirmed inApplicationController(line 23).docs/security.mdline 112 documents the expected role gate: "lead, client, admin" with data scoping. - [x]
app/views/messages/— verified: directory does not exist yet. Existing view directories (leads, pages, sessions) confirm the convention. - [x]
app/assets/stylesheets/messages.css— verified: does not exist yet. Existing stylesheets confirm naming convention.
Constraint Verification
- [x]
docs/security.mdline 112 — verified: "MessagesController | lead, client, admin | Role gate + data scoping: leads/clients see only their own thread; admin sees all (#12)" - [x]
docs/security.mdline 200 — verified: "Rails CSRF protection is enabled by default... Turbo injects tokens automatically via meta tags, including for Turbo Frame submissions (message create, #12)" - [x] ISS brand palette — Navy #1b2a4a + gold #996d13 specified in constraints
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems. All file targets are in the same repo. Single-repo scope, no cross-repo concerns.
Dependencies
- #6 Keycloak OIDC auth (board item 1786) — validation column. Auth integration is implemented;
ApplicationControllerhasauthenticate_user!andrequire_role. Satisfied. - #8 Lead model (board item 1788) — validation column.
app/models/lead.rbexists withkeycloak_sub, role enum, and scopes. Satisfied. - #10 Bottom tab bar (board item 1790) — validation column. The CRUD itself does not require the tab bar. Only the navigation entry to reach
/messagesdepends on #10. Advisory: CRUD can proceed, but AC #1 ("Messages tab shows...") implies tab bar existence. - #42 Turbo Streams (board item 1818) — todo column, sibling ticket. Not a blocker; real-time delivery is explicitly out of scope for this ticket.
Acceptance Criteria
6 ACs, all testable and verifiable by an agent:
- AC1 (Messages tab shows thread) — integration test, verifiable via page content assertions
- AC2 (Lead scoped by lead_id) — controller test with different user sessions
- AC3 (Admin sees all) — controller test with admin session
- AC4 (Chronological order) — model/controller test with ordered records
- AC5 (Compose and submit) — integration test, form submission
- AC6 (has_many :messages on Lead) — model test, association assertion
All ACs are concrete, testable, and have clear pass/fail criteria. Test commands are real (
rails test).Blast Radius
Low. No existing messaging code in the codebase. No existing associations on the Lead model. The
has_many :messagesaddition is additive-only and cannot break existing functionality. No sibling services affected. The Turbo Streams sibling (#42) builds on top of this CRUD, so this ticket's schema and model decisions will constrain #42's implementation.Decomposition Assessment
- 5 file targets in 1 repo (threshold: >3 across >2 repos) — PASS
- 6 ACs (threshold: >5) — borderline, but all ACs are tightly coupled standard CRUD operations. This ticket is already a decomposition of parent #12. Further splitting would create artificial boundaries between model/controller/views that are typically scaffolded together.
- Estimated agent work: ~5-7 minutes for standard Rails CRUD with role scoping, tests, docs, and styles. Borderline but feasible in a single pass.
No decomposition needed.
Recommendation
No action needed.
-
Review: Admin catalog CRUD + ActiveStorage (re-review)
review-1816-2026-07-06-r2Verdict: READY
Re-review of board item #1816. Previous review (
review-1816-2026-07-06) returned NEEDS_REFINEMENT solely becausearch-railsnote did not exist. That note has since been created (pal-e-docs note ID 2347, status active). All other checks passed in the original review and are re-confirmed here.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Sub-ticket of #11, depends on #38 and #6
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- As an admin, CRUD catalog entries with images
- [x] Context -- ActiveStorage setup verified, admin namespace pattern noted
- [x] File Targets -- 3 create + 2 modify, with rationale
- [x] Feature Flag -- "none" (acceptable, no feature-flags.md in repo)
- [x] Acceptance Criteria -- 5 items, all testable
- [x] Test Expectations -- role-matrix + ActiveStorage tests specified
- [x] Constraints -- dependency ordering, namespace pattern, storage scope
- [x] Checklist -- PR, tests, no unrelated changes
- [x] Related -- project, parent, dependency, downstream
Traceability
- [x] story:catalog label -- Epic 3 (US-3.1--3.2), "Browse portfolio by three pillars; admin CRUD"
- [x] story note verified -- found in project-iss user-stories section (key: catalog)
- [x] arch:rails label -- present on board item
- [x] arch note verified --
arch-railsnote exists in pal-e-docs (note ID 2347, "Rails Architecture: Prediction Assistant", status active) - [x] Forgejo issue -- #41, open, ldraney/intelligentstaffingsystems
File Targets
- [x]
app/controllers/admin/catalog_controller.rb-- to create; admin/ directory confirmed absent, issue correctly notes "agent must create it" - [x]
app/views/admin/catalog/-- to create; directory confirmed absent - [x]
test/controllers/admin/catalog_controller_test.rb-- to create; test/controllers/ directory exists - [x]
config/routes.rb-- verified exists; no admin namespace or catalog routes present yet (clean insertion point) - [x]
app/models/catalog_entry.rb-- to modify (add has_many_attached :images); file does not exist yet, correctly depends on #38
ActiveStorage Claims Verified
- [x]
config/application.rb:8--require "active_storage/engine"confirmed - [x]
config/storage.yml-- exists with local (Disk) and test (Disk) services - [x]
Gemfile:39--gem "image_processing", "~> 1.2"uncommented and active
Repo Placement
OK -- issue filed on ldraney/intelligentstaffingsystems, all file targets in the same repo. No cross-repo concerns.
Dependencies
- #38 (CatalogEntry model, migration, tests) -- board item #1814, currently in next_up. MUST complete before this ticket. Correctly documented in Lineage and Constraints.
- #6 (Keycloak OIDC auth) -- board item #1786, currently in validation. Provides require_role helper. Correctly documented.
- #11 (parent) -- board item #1791, in backlog, marked
decomposed. This ticket is one of three decomp children (#38, #39, #41). - No undocumented dependencies found.
Acceptance Criteria
5 criteria, all agent-verifiable:
- AC1: CRUD at /admin/catalog -- verifiable via controller tests and route check
- AC2: ActiveStorage image upload -- verifiable via attachment tests
- AC3: Role-gating (403 for non-admin) -- verifiable via role-matrix controller tests
- AC4: Purge on destroy -- verifiable via test that checks dependent: :purge_later or explicit purge
- AC5: Docs-in-PR rule -- process check, standard convention
Blast Radius
- The
admin/namespace is new -- establishes the pattern for #14 (admin user management). No existing admin controllers to conflict with. - ActiveStorage first usage in this app -- no sibling impact. Greenfield.
Decomposition Assessment
- File targets: 5 (3 create + 2 modify), all in 1 repo -- under threshold
- Acceptance criteria: 5 -- at boundary but not over (threshold is >5)
- Estimated agent work: 2 points, straightforward CRUD + ActiveStorage attachment -- under 5 minutes
- No decomposition needed.
Recommendation
No action needed.
Previous Review
Supersedes
review-1816-2026-07-06(NEEDS_REFINEMENT). The sole blocker -- missingarch-railsarchitecture note -- has been resolved. -
Review: Message model, migration, controller, and views (CRUD)
review-1817-2026-07-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature (child of #12)
- [x] Lineage — parent #12, decomp:1792, dependencies listed
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — "As a lead or admin, I can view and send messages..."
- [x] Context — CRUD foundation for Epic 4, US-4.1/4.2, one thread per lead
- [x] File Targets — 5 create targets listed with descriptions
- [x] Feature Flag — "None" (correct for internal CRUD, no flag doc exists)
- [x] Acceptance Criteria — 6 ACs from parent #12 AC 1-5, 8
- [x] Test Expectations — model, controller, integration tests; run command provided
- [x] Constraints — docs-in-PR rule, security.md line references, ISS brand palette
- [x] Checklist — 8 items
- [x] Related — project, parent, sibling, blockers, user stories all listed
Traceability
- [x] story:messaging label — present on board item #1817
- [x] story note verified — found in project-iss user-stories section: "messaging", Epic 4 (US-4.1–4.2), Role Lead/Client/Admin, "One thread per lead; admin sees all"
- [x] arch:rails label — present on board item #1817
- [ ] arch note MISSING — [SCOPE] No
arch-railsnote exists in pal-e-docs. This is a known board-wide gap flagged in prior ISS reviews (review-1791, review-1815, review-1814, review-1800). Create architecture notearch-rails-issor a sharedarch-railsnote for the Rails application component. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/40, open
File Targets
- [x]
app/models/message.rb— verified: does not exist yet (create target). Lead model atapp/models/lead.rbconfirmed present withkeycloak_subfield for sender identification. No existinghas_manyassociations on Lead — adding:messagesis safe. - [x]
db/migrate/xxx_create_messages.rb— verified: no existing messages migration. Migration directory exists. - [x]
app/controllers/messages_controller.rb— verified: does not exist yet.require_rolemacro confirmed inApplicationController(line 23).docs/security.mdline 112 documents the expected role gate: "lead, client, admin" with data scoping. - [x]
app/views/messages/— verified: directory does not exist yet. Existing view directories (leads, pages, sessions) confirm the convention. - [x]
app/assets/stylesheets/messages.css— verified: does not exist yet. Existing stylesheets (application.css,forms.css,pages.css) confirm the naming convention.
Constraint Verification
- [x]
docs/security.mdline 112 — verified: "MessagesController | lead, client, admin | Role gate + data scoping: leads/clients see only their own thread; admin sees all (#12)" - [x]
docs/security.mdline 200 — verified: "Rails CSRF protection is enabled by default... Turbo injects tokens automatically via meta tags, including for Turbo Frame submissions (message create, #12)" - [x] ISS brand palette — Navy #1b2a4a + gold #996d13 specified in constraints
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems. All file targets are in the same repo. Single-repo scope, no cross-repo concerns.
Dependencies
- #6 Keycloak OIDC auth (board item 1786) — validation column. Auth integration is implemented;
ApplicationControllerhasauthenticate_user!andrequire_role. Satisfied. - #8 Lead model (board item 1788) — validation column.
app/models/lead.rbexists withkeycloak_sub, role enum, and scopes. Satisfied. - #10 Bottom tab bar (board item 1790) — backlog. Documented as dependency in the issue. The CRUD itself (model, migration, controller, views) does not require the tab bar. Only the navigation entry to reach
/messagesdepends on #10. NoTAB_ROLESor tab navigation code exists in the codebase yet. Advisory: CRUD can proceed, but AC #1 ("Messages tab shows...") implies tab bar existence. - #42 Turbo Streams (board item 1818) — backlog, sibling ticket. Not a blocker; real-time delivery is explicitly out of scope for this ticket.
Acceptance Criteria
6 ACs, all testable and verifiable by an agent:
- AC1 (Messages tab shows thread) — integration test, verifiable via page content assertions
- AC2 (Lead scoped by lead_id) — controller test with different user sessions
- AC3 (Admin sees all) — controller test with admin session
- AC4 (Chronological order) — model/controller test with ordered records
- AC5 (Compose and submit) — integration test, form submission
- AC6 (has_many :messages on Lead) — model test, association assertion
All ACs are concrete, testable, and have clear pass/fail criteria. Test commands are real (
rails test).Blast Radius
Low. No existing messaging code in the codebase. No existing associations on the Lead model. The
has_many :messagesaddition is additive-only and cannot break existing functionality. No sibling services affected. The Turbo Streams sibling (#42) builds on top of this CRUD, so this ticket's schema and model decisions will constrain #42's implementation.Decomposition Assessment
- 5 file targets in 1 repo (threshold: >3 across >2 repos) — PASS
- 6 ACs (threshold: >5) — borderline, but all ACs are tightly coupled standard CRUD operations. This ticket is already a decomposition of parent #12 (which was 8 points). Further splitting would create artificial boundaries between model/controller/views that are typically scaffolded together.
- Estimated agent work: ~5-7 minutes for standard Rails CRUD with role scoping, tests, docs, and styles. Borderline but feasible in a single pass.
No decomposition needed. The 6 ACs are a cohesive CRUD unit that an agent handles as one operation.
Recommendation
[SCOPE]Create architecture notearch-rails-iss(or sharedarch-rails) for the Rails application component. This is a board-wide gap previously flagged in reviews for items 1791, 1815, 1814, and 1800. Resolving it once clears the traceability gap for allarch:rails-labeled ISS items.
-
Review: #42 Turbo Streams live delivery + cable fix (decomp:1792)
review-1818-2026-07-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature (child of #12)
- [x] Lineage -- Parent #12, decomp:1792, dependencies #40 and #6
- [x] Repo -- ldraney/intelligentstaffingsystems
- [x] User Story -- As a lead or admin, real-time messages
- [x] Context -- Good background, cable.yml redis problem stated
- [x] File Targets -- 3 targets listed
- [x] Feature Flag -- None (appropriate for infra fix + first Turbo Streams usage)
- [x] Acceptance Criteria -- 3 criteria from parent #12 AC 6-7
- [x] Test Expectations -- broadcast test, turbo frame response test, run command
- [x] Constraints -- Solid Cable, docs-in-PR, CSRF reference
- [x] Checklist -- 6 items
- [x] Related -- Project, parent, sibling, blockers, US references
Traceability
- [x] story:messaging label -- verified in project-iss user-stories section (Epic 4, US-4.1-4.2, role: Lead/Client/Admin)
- [x] story note verified -- found in project-iss user-stories table
- [ ] arch:rails label -- arch note MISSING -- [SCOPE] Create architecture note arch-rails for the Rails component
- [x] Forgejo issue -- ldraney/intelligentstaffingsystems#42, state: open
File Targets
- [x] config/cable.yml -- verified: exists, production adapter IS redis (line 8) with Redis URL (line 9). Matches ticket claim exactly.
- [x] app/models/message.rb -- does not exist yet. Expected: depends on #40 Message CRUD which creates this file. Dependency is documented.
- [x] app/views/messages/ -- does not exist yet. Same dependency on #40. Documented.
- [x] Gemfile line 33 -- verified: solid_cable gem present at line 33. turbo-rails gem present at line 14.
- [ ] db/cable_migrate/ -- MISSING from File Targets. database.yml (line 35-38) already references this path for the cable database, but the directory does not exist. solid_cable install will create migration here. [BODY] Add to File Targets.
- [x] docs/security.md CSRF (line 200) -- verified: CSRF section at line 198-202 explicitly mentions Turbo Frame submissions for message create #12.
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems, Repo field matches, all file targets are in this repo. Single-repo ticket.
Dependencies
- #40 Message CRUD (board item #1817) -- in backlog. BLOCKER: message.rb and views/messages/ must exist before this ticket can execute. Dependency is documented in the issue.
- #6 Keycloak OIDC auth (board item #1786) -- in validation column. Further along. Dependency documented.
- Parent #12 (board item #1792) -- in backlog, marked decomposed. This ticket is Sub-B of the decomposition.
- Sibling #40 must complete before this ticket. Ordering constraint is clear.
Acceptance Criteria
3 ACs, all verifiable by an agent:
- AC1: Turbo Frame rendering -- testable via integration test (form submit returns turbo_stream response)
- AC2: Real-time broadcast -- testable via ActionCable broadcast test, though multi-client live verification may be limited to manual
- AC3: cable.yml adapter check -- simple file content assertion
Test commands are real (rails test). Criteria are clear and complete.
Blast Radius
Low. Redis references exist ONLY in config/cable.yml (lines 8-9). No other config, deployment, or application files reference Redis. The database.yml cable database entry (lines 35-38) is already prepared for solid_cable. No downstream consumers affected by this change within the repo. This is the first Turbo Streams usage -- no existing broadcast patterns to break.
Decomposition Assessment
No decomposition needed.
- 3 file targets in 1 repo -- within limits
- 3 acceptance criteria -- within limits
- Estimated agent work: under 5 minutes (cable.yml edit, model annotation, view partial update, tests)
- 3 points -- appropriately sized
Recommendations
- [SCOPE] Create architecture note arch-rails for the Rails application component. Many board items carry this label.
- [BODY] Add db/cable_migrate/ to File Targets: "db/cable_migrate/ -- create: solid_cable migration (database.yml line 35-38 already references this path but directory does not exist; run bin/rails solid_cable:install or create migration manually)"
- [BODY] Constraints section says "update docs/messaging.md" but this file does not exist yet. Change to "create docs/messaging.md with real-time delivery section" for clarity.
-
Review: Public catalog browsing controller, views, and routes
review-1815-2026-07-06Verdict: READY
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag (none)
- [x] Acceptance Criteria (5 items)
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:catalog label — Epic 3 (US-3.1–3.2): Browse portfolio by three pillars; admin CRUD
- [x] story note verified — found in project-iss user-stories section
- [x] arch:rails label — Rails application component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-rails for component rails (also flagged in parent review-1791-2026-07-05)
- [x] Forgejo issue — ldraney/intelligentstaffingsystems#39, open
File Targets
- [x]
app/controllers/catalog_controller.rb— verified: does not exist yet (to be created). Controller directory exists with existing patterns (PagesController, LeadsController, SessionsController). - [x]
app/views/catalog/(index.html.erb, show.html.erb) — verified: directory does not exist yet (to be created). Other view directories (pages/, leads/, sessions/) exist as patterns. - [x]
app/assets/stylesheets/catalog.css— verified: does not exist yet (to be created). Stylesheets directory exists with application.css, forms.css, pages.css. - [x]
config/routes.rb— verified: exists (27 lines). Contains leads, pages, sessions, and health routes. Catalog resources route can be added cleanly.
Repo Placement
OK. Issue filed on ldraney/intelligentstaffingsystems, all file targets are in the same repo. No cross-repo concerns.
Dependencies
- #38 CatalogEntry model (board item #1814) — HARD dependency, currently in backlog. Issue correctly documents "Depends on: #38 (CatalogEntry model must exist first)." Controller references
CatalogEntry.publishedscope which will be created in #38. - #11 Catalog model, admin CRUD, and browsing UI (board item #1791) — parent ticket, marked decomposed. This item is one of its decomposition children (decomp:1791).
- #41 Admin catalog CRUD + ActiveStorage (board item #1816) — sibling decomp item. No blocking relationship; both depend on #38 independently.
Acceptance Criteria
5 criteria, all verifiable by an agent:
- GET /catalog lists published entries — testable via controller test
- Pillar filter (?pillar=web_presence) narrows results — testable via controller test with params
- GET /catalog/:id shows single entry — testable via controller test
- Only published:true visible; unpublished returns 404 — testable via controller test
- Responsive card layout — CSS verification; less automatable but standard
Test command specified:
rails test test/controllers/catalog_controller_test.rb— valid convention.Blast Radius
Low. All new files (no existing code modified except routes.rb). The catalog controller needs
skip_before_action :authenticate_user!since ApplicationController enforces auth globally — the issue states "No authentication required" and the agent can follow SessionsController's pattern. No downstream consumers affected.Decomposition Assessment
4 file targets in 1 repo, 5 acceptance criteria, 2 story points. Estimated agent work well under 5 minutes. No decomposition needed.
Recommendation
[SCOPE]Create architecture note arch-rails for the Rails component. This was also flagged in the parent ticket review (review-1791-2026-07-05) and affects all arch:rails items on board-iss. Not blocking for this ticket — the issue spec itself is complete and actionable.
-
Review: CatalogEntry model, migration, and model tests
review-1814-2026-07-06Verdict: READY
Template Completeness
- [x] Type — Feature
- [x] Lineage — Sub-ticket of #11, first in execution order
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — "As a developer, I want the CatalogEntry model..."
- [x] Context — CatalogEntry purpose, pillar enum, deferred ActiveStorage
- [x] File Targets — 3 files to create, 2 exclusion boundaries
- [x] Feature Flag — "none" (internal model change, appropriate)
- [x] Acceptance Criteria — 5 criteria, all concrete
- [x] Test Expectations — model tests, run command provided
- [x] Constraints — uuid PK, no ActiveStorage, no routes/controllers, follow existing patterns
- [x] Checklist — standard PR/tests/no-unrelated-changes
- [x] Related — project-iss, parent #11
Traceability
- [x] story:catalog label — Epic 3 (US-3.1–3.2): Browse portfolio by three pillars; admin CRUD
- [x] story note verified — found in project-iss user-stories section (catalog row)
- [x] arch:rails label — Rails application component
- [ ] arch note — no ISS-specific arch note exists in pal-e-docs (arch-rails note exists but scoped to prediction-assistant). Already flagged in parent review review-1791-2026-07-05. Not a blocker for this child ticket — the architecture is documented in docs/architecture.md in the repo.
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/38, open
File Targets
- [x]
db/migrate/YYYYMMDDHHMMSS_create_catalog_entries.rb— new file to create. Columns verified against docs/architecture.md data model (uuid id PK, string title, text description, string pillar, text technologies, integer position, boolean published). Ticket adds timestamps and published default false — both appropriate. - [x]
app/models/catalog_entry.rb— new file to create. Existing Lead model at app/models/lead.rb provides clear pattern for enum, scopes, and validations. - [x]
test/models/catalog_entry_test.rb— new file to create. Existing test/models/lead_test.rb provides pattern for enum, scope, and validation testing. - [x] Exclusion:
app/controllers/— no controllers, boundary clearly stated - [x] Exclusion:
config/routes.rb— no routes, boundary clearly stated
Repo Placement
Correct. Issue filed on ldraney/intelligentstaffingsystems, work is in the same repo. Single-repo ticket — no cross-repo concerns.
Dependencies
- Parent: #1791 (#11 Catalog model, admin CRUD, and browsing UI) — decomposed, in backlog
- Siblings (decomp:1791): #1815 (#39 Public catalog browsing UI, 2pts), #1816 (#41 Admin catalog CRUD + ActiveStorage, 2pts) — both depend on this ticket
- This ticket has NO upstream dependencies — first in execution order as stated in Lineage
- Existing pgcrypto extension (20260705000001_enable_pgcrypto.rb) already enabled — uuid PK will work
- Dependencies are correctly documented in the issue Lineage section
Acceptance Criteria
All 5 criteria are concrete and agent-verifiable:
- AC1: Migration creates table — verify via schema.rb after migration
- AC2: Pillar enum with 3 values — verify via model test
- AC3: Published scope — verify via model test
- AC4: Default ordering by position ASC — verify via model test
- AC5: Title presence validation — verify via model test
Test command is real and follows existing convention:
rails test test/models/catalog_entry_test.rbBlast Radius
Minimal. This is a model-only ticket creating a new table and model class. No existing code is modified. No controllers, routes, or views affected. The CatalogEntry model is independent — no foreign keys to existing tables. Downstream consumers (#39 browsing UI, #41 admin CRUD) will build on top but are separate tickets.
Decomposition Assessment
- 3 file targets in 1 repo — under threshold
- 5 acceptance criteria — at threshold, not over
- Estimated agent work: well under 5 minutes (create migration, model with enum/scope/validation, and tests following existing Lead pattern)
- 1 story point — appropriate sizing
No decomposition needed.
Recommendation
No action needed. Scope is solid, all file targets verified against architecture.md, traceability complete (story note verified, arch note concern captured at parent level), fits in a single agent pass.
-
Review: Catalog model, admin CRUD, and browsing UI
review-1791-2026-07-05Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Depends on #10, #6; Sprint 4
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — present (lead/client browsing portfolio)
- [x] Context — present (CatalogEntry model, pillar enum, ActiveStorage)
- [x] File Targets — 7 files to create
- [x] Feature Flag — none
- [x] Acceptance Criteria — 8 items
- [x] Test Expectations — 3 items + run command
- [x] Constraints — present
- [x] Checklist — present
- [x] Related — present
All template sections present. Template is complete.
Traceability
- [x] story:catalog label — Epic 3 (US-3.1, US-3.2): Browse portfolio by three pillars; admin CRUD
- [x] story note verified — found in project-iss user-stories section (catalog row: Epic 3, Lead/Client role)
- [x] arch:rails label — Rails application component
- [ ] arch note MISSING — [SCOPE] Create architecture note arch-rails for component rails. Search for "arch-rails" returned no results in pal-e-docs.
- [x] Forgejo issue — ldraney/intelligentstaffingsystems#11, open
File Targets
- [x]
app/models/catalog_entry.rb— verified: parentapp/models/exists;application_record.rbpresent as base class; no existing catalog model - [x]
db/migrate/xxx_create_catalog_entries.rb— verified:db/migrate/exists with existing migrations (enable_pgcrypto, create_leads) - [x]
app/controllers/catalog_controller.rb— verified:app/controllers/exists;application_controller.rbpresent as base class - [x]
app/controllers/admin/catalog_controller.rb— verified: parentapp/controllers/exists;admin/subdirectory does not exist yet (agent must create it — acceptable for first admin controller) - [x]
app/views/catalog/— verified:app/views/exists; new directory needed - [x]
app/views/admin/catalog/— verified:app/views/exists; new directory needed (first admin namespace) - [x]
app/assets/stylesheets/catalog.css— verified:app/assets/stylesheets/exists
All file targets are valid for creation. ActiveStorage engine is loaded (
config/application.rb),storage.ymlconfigured (local/test),image_processinggem present in Gemfile. No existing catalog code in codebase.Repo Placement
OK. Issue filed on
ldraney/intelligentstaffingsystems, all file targets within same repo, Repo section matches. No cross-repo work needed.Dependencies
- #6 Keycloak OIDC auth — in
validationcolumn (nearly done). Required for role-gating admin CRUD. Documented in issue Lineage. - #10 Bottom tab bar navigation — in
backlogcolumn (NOT started). Required for catalog tab to appear in nav. Documented in issue Lineage. This is a real blocker — catalog cannot be accessed without the tab bar. - #12 Messaging model — same sprint (4), no direct dependency. Parallel work.
- #9 Dashboard — sprint 3, no direct dependency.
Dependencies are documented in the issue. #10 being in backlog is noted but not a scope problem — the sprint ordering handles sequencing.
Acceptance Criteria
8 criteria. Assessment:
- AC 1-6: testable via model, controller, and integration tests. Test expectations align.
- AC 7 (responsive card layout): harder to verify programmatically; CSS inspection or visual check needed. Acceptable for a feature ticket.
- AC 8 (docs-in-PR rule): verifiable via PR diff. Standard ISS convention.
Test expectations reference model tests, controller role-matrix tests, and browse-as-lead tests. Run command
rails testis valid. Testing-strategy.md confirms: "#11 Catalog: browse + admin CRUD: Model tests; browse across all roles; full role matrix on CRUD."Blast Radius
Low risk — greenfield feature, no existing catalog code to conflict with. Points of note:
- ActiveStorage not yet used by any existing model; this will be the first usage. Storage config is set to
:localfor all environments (including production). MinIO backend for prod mentioned in constraints and security.md but not yet configured in storage.yml — acceptable, as infrastructure config is a separate concern. - The
admin/namespace established here sets the pattern for future admin controllers (#14 user management). Consistency matters. - Routes additions needed; current routes.rb is clean and straightforward.
Decomposition Assessment
- File targets: 7 files across 1 repo (does NOT meet the >3 across >2 repos criterion)
- Acceptance criteria: 8 (EXCEEDS the >5 threshold)
- Estimated agent work: model + migration + 2 controller namespaces + 6+ view templates + CSS + route additions + 3 test files = likely >5 minutes
NEEDS DECOMPOSITION — route to
skill-decompose-ticket. Natural split:- CatalogEntry model, migration, pillar enum, published scope, model tests (AC: 6 partial)
- Public browsing controller/views/routes + browse tests (AC: 1, 2, 3, 6, 7)
- Admin CRUD controller/views/routes + ActiveStorage image upload + admin tests (AC: 4, 5)
Recommendation
[SCOPE]Create architecture notearch-railsfor the Rails application component in pal-e-docs. Multiple board items share thearch:railslabel (#3, #8, #9, #11, #12, #13, #14, #15, #16); this note should document the Rails application architecture patterns.[DECOMPOSE]8 AC across 7 file targets with model + 2 controller namespaces + views + CSS + tests. Route toskill-decompose-ticketwith the three-way split described above.
-
Review: #21 docs/pipeline.md (decomp:1800) — second pass
review-1804-2026-07-05-2Verdict: APPROVED
Second-pass review of board item 1804 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#21, 2 points, decomposition child of #19. The first pass (review-1804-2026-07-05) returned NEEDS_REFINEMENT on a single [BODY] finding: the Context/AC3 directed the Update Lifecycle sequence diagram into pipeline.md while do-not-touchdocs/ios.mdalready contains that diagram, contradicting the no-duplication Constraint. The issue body has been revised exactly along the recommended line, the fix is factually accurate against the repo, and nothing else regressed. Ticket may advance backlog → todo.Fix Verification (closes review-1804-2026-07-05 [BODY])
- [x] Context — new bolded "Update Lifecycle ownership" paragraph states ios.md owns BOTH the update-model table AND the web-vs-native sequence diagram (ios.md lines ~18–38). Verified:
## Update Modelat docs/ios.md:16, mermaidsequenceDiagramat lines 18–38, update-model table at lines 40–47. Claim accurate, line range exact. - [x] AC3 — reworded to "Update Lifecycle section summarizes the web-vs-native split and cross-links docs/ios.md's Update Model — no duplicated diagram or table". Matches the recommended wording; the cross-link target heading exists (ios.md:16).
- [x] Constraint consistency — "Don't duplicate docs/ios.md content — link it" no longer conflicts with any AC. An implementer can now satisfy AC3 and the Constraint simultaneously; the contradiction is resolved.
- [x] Lineage — documents the revision: "Body revised per review-1804-2026-07-05 ([BODY]: Update Lifecycle ownership clarified — ios.md already owns the diagram)."
Template Completeness (Feature template)
All 12 sections still present after the revision (Type, Lineage, Repo, User Story, Context, File Targets, Feature Flag, Acceptance Criteria, Test Expectations, Constraints, Checklist, Related). The edit touched only Lineage, Context, and AC3. No template gaps introduced.
Traceability
- [x] story:project-setup label — still present on board item 1804
- [x] story note verified —
project-issuser-stories section listsproject-setup(backing: README + docs/architecture.md + docs/adoption-plan.md; metric: "Repo, docs, infra, and CI exist; sprints can dispatch") - [x] arch:docs label — still present on board item 1804
- [x] arch note verified —
arch-docs("Architecture: Documentation") has been generalized since the first pass: now explicitly "Platform-wide documentation component backing the arch:docs label", project-scoped to pal-e-agency, updated 2026-07-05, and lists ISSdocs/pipeline.mdunder Tier 1 adoption (issues #20–#24). The first-pass westside-scoping caveat is fully resolved. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/21, open, label sprint:0
File Targets
Re-verified against the working tree, confirmed identical to origin/main for docs/ and README.md (
git diff --stat origin/mainempty).- [x] docs/pipeline.md (create) — still absent; valid create target
- [x] docs/ios.md (do NOT touch, cross-link only) — ownership claim now correct (see Fix Verification); Production URL row at ios.md:70 backs AC4 verbatim ("iss.tail5b443a.ts.net (funnel) → intelligentstaffingsystems.ai once the edge domain is wired")
- [x] docs/adoption-plan.md (spec) — pipeline.md content spec at lines 31–32; section chain matches AC1. Note: AC1 ends with "/ Related", which matches the landscaping reference's actual structure (
## Relatedat reference line 158) — consistent, not a regression. Residual spec wording noted in Blast Radius. - [x] ~/landscaping-assistant/docs/pipeline.md (read-only reference) — exists; headings Overview / Local Dev / Production Deploy / iOS Dev Builds / TestFlight → App Store / Update Lifecycle / Related. Its Update Lifecycle holds a sequenceDiagram (reference line 138) — the revised Context correctly instructs the ISS adaptation to deviate there (prose summary + cross-link) because ISS consolidated that diagram into ios.md.
AC facts re-verified in-repo: image repo
intelligentstaffingsystems/intelligentstaffingsystems(architecture.md:273); production port 3000 + local port 9999 (README.md:105; architecture.md:335); ~/rails-base prerequisite (README.md:86); Hetzner edge (architecture.md:13), funnel (architecture.md:275), redirect/origin URLs (architecture.md:297–298).Repo Placement
OK. Unchanged: single-repo docs work, issue filed on the repo it modifies.
Dependencies
Blocked by: nothing. Board state since first pass: siblings #20 (item 1803) and #23 (item 1806) and closer #24 (item 1807) have advanced to todo; #22 (item 1805) remains in backlog; nothing is in_progress. All source docs this ticket reads are on main.
Blocks: #24 (item 1807, blocker:siblings) — unchanged; the README Documentation-table row for pipeline.md stays with #24.
Siblings (parallel-safe): disjoint file ownership unchanged; #21 creates one new file and edits nothing, so no conflict surface regardless of merge order.
Acceptance Criteria
Still 5 ACs, all objectively agent-verifiable. AC3 is now mechanically checkable: pipeline.md's Update Lifecycle section must contain no
sequenceDiagramand no update-model table, and must link docs/ios.md's Update Model. Test Expectations remain honest — the Overview section's 4-flow mermaid keeps the "mermaid renders" check meaningful even with no Update Lifecycle diagram.Blast Radius
Docs-only; unchanged. Carried forward for the implementer: (1) link only docs on main (ios.md, architecture.md, README) — sibling docs (security.md, testing-strategy.md, local-dev-setup.md) are not merged yet and would fail the link check; (2) framework-neutral test wording per the Constraint. New non-blocking observation: adoption-plan.md:32 still reads "Update Lifecycle diagram (cross-link ios.md's table)" — the spec sentence itself was written on the outdated premise the first review caught (that ios.md owned only the table). The revised issue supersedes it with the verified repo state and says why in Lineage. adoption-plan.md is outside this ticket's file targets (do-not-touch: "All other docs — sibling tickets own them"); if anyone wants the spec sentence touched up, closer #24 (plan status) is the natural home. Not blocking.
Decomposition Assessment
No decomposition needed. Unchanged: 1 file target (create), 1 repo, 5 ACs (threshold is >5), 2 points, single agent pass comfortably under 5 minutes.
Recommendation
No action needed. The single [BODY] finding from review-1804-2026-07-05 is resolved; approve for backlog → todo.
- [x] Context — new bolded "Update Lifecycle ownership" paragraph states ios.md owns BOTH the update-model table AND the web-vs-native sequence diagram (ios.md lines ~18–38). Verified:
-
Review (2nd pass): #22 testing-strategy + local-dev-setup (decomp:1800)
review-1805-2026-07-05-2Verdict: READY
Second-pass review of board item 1805 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#22, 2 points. The first review (review-1805-2026-07-05, NEEDS_REFINEMENT) had exactly one blocker: no backing note for thearch:docslabel. That note now exists (arch-docs) and explicitly covers this ticket's two deliverables. The issue body was not changed — none was needed; the first review required no [BODY] or [LABEL] fixes and stated "on re-review after the arch-docs note exists, this ticket is READY as-is." Condition met; full re-verification below shows zero drift.Fix Verification (the single prior blocker)
- [x] arch note EXISTS —
get_note(slug="arch-docs")returns note id 2311 ("Architecture: Documentation"), note_typedoc, projectpal-e-agency, tagsarchitecture, active, updated 2026-07-05T22:03 (after the first review at 22:01). Generalized platform-wide, as the first review recommended for the board-wide gap. - [x] Content backs THIS ticket — scope statement covers any
docs/work backing thearch:docslabel; the intelligentstaffingsystems section explicitly listsdocs/testing-strategy.mdanddocs/local-dev-setup.mdunder "Tier 1 adoption (issues #20–#24)", notes the Sprint 0 docs-first gate, and linksconvention-architecture-idsandproject-iss. - [!] Search caveat for future reviewers — the skill's literal check
search_notes(query="arch-docs")still returns empty: full-text search does not index slugs, and the hyphenated query doesn't match the note text (which saysarch:docs). The note IS the top-ranked result forsearch_notes("architecture documentation")and resolves directly viaget_note(slug="arch-docs"). Verify arch notes by slug lookup, not hyphenated FTS, or sibling re-reviews will false-negative the same fix.
Template Completeness (Feature template)
Issue body re-fetched — unchanged since the first review (the only issue update is that review's own comment). All 12 sections present: Type (Feature) / Lineage / Repo / User Story / Context / File Targets (2 create + do-not-touch) / Feature Flag (none) / Acceptance Criteria (5) / Test Expectations / Constraints / Checklist / Related. No gaps.
Traceability
- [x] story:project-setup label — present on board item 1805 (label set unchanged:
type:feature,arch:docs,story:project-setup,sprint:0,decomp:1800) - [x] story note verified —
project-issuser-stories section still lists keyproject-setup(Developer; "Repo, docs, infra, and CI exist; sprints can dispatch") - [x] arch:docs label — present on item 1805 and the whole decomp:1800 family
- [x] arch note verified —
arch-docsexists in pal-e-docs (see Fix Verification) - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/22, open
Traceability triangle complete — all three legs with backing notes.
File Targets
Re-verified against origin/main — still commit
670c515, the exact commit the first review verified. Zero drift.- [x]
docs/testing-strategy.md(create) — still absent on main (docs/ holds only adoption-plan, architecture, ios, user-stories) - [x]
docs/local-dev-setup.md(create) — still absent on main - [x]
docs/adoption-plan.md— line 29 (testing-strategy spec: endpoint-first, no browser/system tests, Hotwire rationale, gates-a-PR table, net-new Keycloak per-role stubbing, owns lint/test claims) and line 13 (local-dev spec, trigger "now") confirmed; line 39 open decision 1 ("testing-strategy.md decides" the Minitest/RSpec wording) confirmed verbatim - [x] Supporting claims — README.md:86/93 (
~/rails-baseprereq + copy command), README.md:105 (port 9999), docs/user-stories.md:5 ("Three roles govern access, enforced in Keycloak and Rails"), docs/architecture.md:317 (RuboCop + Brakeman CI gate) — all hold - [x]
~/landscaping-assistant/docs/testing-strategy.md(7.0k) andlocal-dev-setup.md(2.9k) — read-only references still present
Repo Placement
OK — unchanged. Single-repo docs work, filed on the repo it modifies.
Dependencies
Board re-read: nothing in_progress anywhere. Since the first review, siblings #20 (item 1803), #23 (1806), and closer #24 (1807,
blocker:siblings) advanced to todo; #21 (1804, pipeline.md) remains in backlog. This ticket is blocked by nothing and blocks closer #24. The AC 5 soft cross-link with #21 (pipeline.md forward reference if #22 merges first) stands as previously assessed — non-blocking; closer #24 is positioned to catch any unresolved link.Acceptance Criteria
Unchanged — 5 criteria, all agent-verifiable (grep-able doc content, the five named local-dev sections, port-9999 consistency, framework statement reconciled against architecture.md's CI gates, link check with the documented forward-reference tolerance). Test Expectations honestly manual / run-command N/A for docs-only work.
Blast Radius
Unchanged — docs-only, no code or config. Settles plan open decision 1 (the framework wording binds #3's CI scaffold, pinned by the Constraints section to Rails-default Minitest unless reasoned otherwise); the gates-a-PR overlap with sibling #21 is handled by AC 3's "reconciles" wording. README untouched, avoiding the CLAUDE.md-symlink propagation the parent review warned about.
Decomposition Assessment
No decomposition needed — 2 file targets, 1 repo, 5 acceptance criteria (at threshold, not over), estimated agent work under 5 minutes. Unchanged from first pass; this is itself a decomposition child that sized correctly.
Recommendation
No action needed. The single
[SCOPE]item fromreview-1805-2026-07-05is resolved by thearch-docsnote; no [BODY] or [LABEL] fixes were ever required. Ticket may advance backlog → todo. - [x] arch note EXISTS —
-
Review: #24 Docs closer: README + plan status (decomp:1800)
review-1807-2026-07-05Verdict: READY
Board item 1807 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#24, 1 point. The decomposition CLOSER for #19 (decomp:1800). Scope is tight and verification-focused: two file targets, four testable ACs, all verified against main (commit 670c515, local HEAD = origin/main). All four recommendations fromreview-1800-2026-07-05are resolved in this child set: the [BODY] adoption-plan correction is incorporated verbatim in Context, project-iss now exists with the project-setup story row, the arch label was corrected to a taxonomy-valid value, and [DECOMPOSE] was executed (children #20–#24).Template Completeness (Feature template)
- [x] Type — Feature (routes to template-issue-feature)
- [x] Lineage — child of #19, decomposed per review-1800-2026-07-05, runs LAST
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story
- [x] Context — states the review-1800 [BODY] correction explicitly: adoption-plan.md is status-flipped, NOT deleted (only spec for Tier 2/3)
- [x] File Targets — modify list + do-not-touch list both present
- [x] Feature Flag — "none"; correct (docs-only; repo has no docs/feature-flags.md yet — itself a Tier 2 item)
- [x] Acceptance Criteria — 4 checkboxes
- [x] Test Expectations — manual full docs/ link walk, run command N/A (appropriate for docs-only)
- [x] Constraints — blocked-by list + smallest-possible-diff
- [x] Checklist
- [x] Related — project, parent, blockers
All 12 sections present. No template gaps.
Traceability
- [x] story:project-setup label — present on board item 1807
- [x] story note verified — project-iss user-stories section contains the
project-setuprow (backing: README + docs/architecture.md + docs/adoption-plan.md). This closes the [SCOPE] gap from review-1800; project-iss was created 2026-07-05 21:52. - [x] arch:docs label — present on board item 1807
- [x] arch backing verified via taxonomy —
convention-architecture-idsdefinesarch:docsunder Docs/Process ("Documentation work"). No standalonearch-docsnote exists (search_notes("arch-docs")empty), and none is warranted: arch:docs is a category-level process label per the convention's own fallback rule, the arch-note naming patterns (arch-domain/dataflow/deployment-{project} per template-architecture) describe system components not process categories, and this docs-only closer touches no diagram. Judgment call recorded here for human override. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/24, open, label sprint:0
File Targets
Verified against origin/main = local HEAD (670c515), working tree clean.
- [x] README.md (modify) — exists; Documentation table (lines 17–22) currently lists exactly 4 docs (user-stories, architecture, ios, adoption-plan). The issue's 8-file target list = current 4 + the 4 Tier 1 files the siblings create (#20 security.md, #21 pipeline.md, #22 testing-strategy.md AND local-dev-setup.md; #23 amends only, creates nothing). Arithmetic checks out exactly. Executor note: the current adoption-plan row description reads "delete when executed" — AC1's "accurate one-line descriptions" requires updating that phrasing to keep-and-flip semantics; covered by AC1, no body change needed.
- [x] docs/adoption-plan.md (modify) — exists; target-tree table (lines 7–19) uses a Priority column where
doneis already the established flip value (the ios.md row, line 9); the four Tier 1 rows are lines 10–13 (security, pipeline, testing-strategy, local-dev-setup). "Flip Tier 1 rows to done" is executable exactly as written — no new status column needed. Line 3 carries the deletion rule the Context correctly cites ("delete this file when the tree below exists" — tree includes Tier 2/3). The [BODY] correction from review-1800 is fully incorporated: file kept, Tier 2/3 spec preserved. - [x] Do-not-touch list — the four new docs and two amended docs, verify-only. Correct posture for a closer.
Repo Placement
OK. Single-repo docs work, filed on the repo it modifies. CLAUDE.md is a symlink to README.md (verified in working tree), so the README table edit propagates into every future agent session's context for this repo — same repo, no additional issue needed.
Dependencies
Blocked by: #20/#21/#22/#23 (board items 1803/1804/1805/1806) — all four exist, all open on Forgejo, all in backlog carrying decomp:1800. The block is documented in three places in the issue body (Lineage, Constraints, Related) and machine-signaled by the
blocker:siblingslabel on the board item; the Overseer's dispatch gate holds this ticket until siblings merge. AC4 depends specifically on #22's docs/local-dev-setup.md — captured by the sibling block. Parent #19 (item 1800) is labeleddecomposedand correctly acts as a tracking item. No open PRs on the repo (0), so no file contention.Blocks: nothing explicitly, but this closer completes the Sprint 0 docs epic that review-1800 identified as gating #3 (bootstrap) and downstream build tickets.
Non-blocking convention variance:
blocker:siblingsis not one of the two types enumerated inconvention-blocker-labels(external/internal); strict reading saysblocker:internal. However the specific blockers ARE documented in the body as the convention requires, and blocker:siblings is the operational dispatch gate for decomposition closers — relabeling could break the gating. This is a platform convention question (add a siblings pattern for decomp closers, or fold into internal), not a ticket defect. Not verdict-affecting.Acceptance Criteria
All 4 objectively verifiable by an agent post-merge. AC1 is enumerable (ls docs/ vs table rows) and self-correcting: it demands "every file in docs/", so even if a sibling drifts from its spec filename, the closer verifies against the actual tree, not the hardcoded list. AC2 is diffable (Tier 1 Priority cells = done, file present, Tier 2/3 rows byte-identical). AC3 is a manual link walk, honestly declared in Test Expectations — no fake test commands. AC4 has concrete comparables (port 9999, ~/rails-base prereq, bootstrap commands at README lines 84–96 vs the incoming docs/local-dev-setup.md). No missing criteria for a closer of this size.
Blast Radius
Docs-only; no code or config. README edits flow through the CLAUDE.md symlink into agent session context — the Documentation table must stay accurate (same propagation noted in review-1800). Running last, the closer absorbs sibling drift via AC1's enumerate-the-tree formulation. Smallest-possible-diff constraint present. No downstream consumers.
Decomposition Assessment
No decomposition needed. 2 file targets in 1 repo, 4 ACs (≤5), estimated agent work well under 5 minutes (one table edit, four Priority-cell flips, a link walk, and a consistency read). 1 point is consistent with the effort.
Recommendation
No action needed.
Non-blocking observations (deliberately untagged so skill-refine-ticket does not consume them): (1) the README adoption-plan row description "(delete when executed)" must be rewritten by the executor — already covered by AC1's "accurate descriptions"; (2) blocker:siblings vs convention-blocker-labels is a platform convention gap to resolve once, not a defect of this ticket.
-
Review: #21 docs/pipeline.md — dev-to-App-Store lifecycle (decomp:1800)
review-1804-2026-07-05Verdict: NEEDS_REFINEMENT
Board item 1804 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#21, 2 points, decomposition child of #19 (per review-1800-2026-07-05). Scope quality is high — every repo-verifiable claim in the issue checks out (spec, reference doc, image repo, ports, URLs) and sizing is correct for a single pass. One self-contradiction blocks READY: the issue directs the Update Lifecycle sequence diagram into pipeline.md, butdocs/ios.mdalready contains that exact web-vs-native sequence diagram, and the ticket's own Constraint forbids duplicating ios.md content. One-line body fix.Template Completeness (Feature template)
- [x] Type — Feature (routes to template-issue-feature)
- [x] Lineage — child of #19, cites review-1800-2026-07-05 and the spec doc
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — ISS owner, "idea to App Store in weeks" claim as walkable doc
- [x] Context — names source reference, section plan, and the ios.md boundary
- [x] File Targets — create list + do-NOT-touch list present
- [x] Feature Flag — "none"; correct (docs-only, and repo has no docs/feature-flags.md — that is a Tier 2 item)
- [x] Acceptance Criteria — 5 checkboxes
- [x] Test Expectations — manual mermaid + link checks, run command N/A (appropriate for docs-only)
- [x] Constraints — framework-neutral test wording; no ios.md duplication
- [x] Checklist
- [x] Related — project + parent #19
All 12 sections present. No template gaps.
Traceability
- [x] story:project-setup label — present on board item 1804
- [x] story note verified —
project-issuser-stories section exists and listsproject-setup(backing: README + docs/architecture.md + docs/adoption-plan.md; metric: "Repo, docs, infra, and CI exist; sprints can dispatch"). The gap flagged in review-1800 is fixed. - [x] arch:docs label — present on board item 1804
- [x] arch note verified —
arch-docs("Architecture: Documentation") exists in pal-e-docs. Caveat, non-blocking: the note is project-scoped to westside-basketball (slugs are global, so a per-project arch-docs cannot exist); content is the generic docs-component pattern. Taxonomy pre-validated by the Overseer. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/21, open, label sprint:0
File Targets
Verified against origin/main and working tree (identical for docs/).
- [x] docs/pipeline.md (create) — verified absent on main and in worktree; correct for a create ticket
- [x] docs/ios.md (do NOT touch, cross-link only) — exists on main. ISSUE (see [BODY]): its "Update Model" section (docs/ios.md:16–47) already contains BOTH the update-model table AND the web-vs-native Update Lifecycle sequence diagram (mermaid
sequenceDiagram, lines 18–38). The issue's Context asserts ios.md owns only the table. - [x] docs/adoption-plan.md (spec, on main) — pipeline.md content spec at lines 31–32 matches the issue's AC1 section list exactly: Overview (4-flow mermaid) → Local Dev → Production Deploy (three-repo table) → iOS Dev Builds (link ios.md) → TestFlight → App Store → Update Lifecycle
- [x] ~/landscaping-assistant/docs/pipeline.md (read-only reference) — exists; contains the 4-flow mermaid overview, the pal-e-platform/services/deployments three-repo table, and the Update Lifecycle sequence diagram, exactly as the Context claims
AC claims verified in-repo: image repo
intelligentstaffingsystems/intelligentstaffingsystems(docs/architecture.md:273); production port 3000 + local port 9999 (README.md:105, architecture.md Port Convention section); ~/rails-base prerequisite (README.md:86); Woodpecker → Harbor → Image Updater → ArgoCD chain (architecture.md:47–49, 313–322); URL storyiss.tail5b443a.ts.netfunnel →intelligentstaffingsystems.aivia Hetzner edge (ios.md:70, architecture.md:13, 296–298).Repo Placement
OK. Single-repo docs work; issue filed on the repo it modifies. No other repos affected.
Dependencies
Blocked by: nothing. The spec (docs/adoption-plan.md) and docs/ios.md are on main (#1 / item 1780 merged, sitting in validation). No in_progress items on board-iss.
Blocks: #24 (item 1807, the decomposition closer, labeled blocker:siblings) — the README Documentation-table row for pipeline.md is #24's job, correctly excluded here.
Siblings (parallel-safe): #20 (security.md), #22 (testing-strategy + local-dev-setup), #23 (user-stories + architecture amendments) — no file overlap with pipeline.md; the do-NOT-touch list correctly defers all other docs to them. Merge-order link risk noted in Blast Radius.
Acceptance Criteria
All 5 are objectively verifiable by an agent: section list (headings diff vs spec), three-repo table values (verified against architecture.md:273 and the port convention), URL correctness (verified against ios.md:70 / architecture.md:296–298), local-dev consistency (README.md:86, 105). No fake test commands; manual mermaid/link checks are honestly declared. Count is 5 — at the single-pass threshold, not over it. AC3 is the one problem: as written ("Update Lifecycle sequence diagram (web vs native), cross-linked with docs/ios.md") it requires a diagram in pipeline.md that would duplicate docs/ios.md:18–38, violating the Constraint "Don't duplicate docs/ios.md content — link it". An implementing agent must break either AC3 or the Constraint.
Blast Radius
Docs-only; no code, config, or CI. Three notes: (1) a duplicated web-vs-native diagram would drift from ios.md over time — the exact failure the single-source constraint exists to prevent; (2) if the agent links sibling docs not yet on main (local-dev-setup.md, security.md, testing-strategy.md), the "internal links resolve" check fails — link only docs on main (ios.md, architecture.md, README); (3) the framework-neutral test-wording constraint correctly defers the Minitest/RSpec decision to #22 (testing-strategy.md), matching adoption-plan open decision 1. README/CLAUDE.md propagation is deferred to #24, so no agent-context changes from this ticket.
Decomposition Assessment
No decomposition needed. 1 file target (create), 1 repo, 5 ACs (threshold is >5), 2 points. The work adapts a single ~160-line reference doc with all ISS-specific values already verified in-repo — comfortably a single agent pass under 5 minutes. This ticket is itself the product of decomposing #19, sized correctly.
Recommendation
[BODY]Resolve the Update Lifecycle contradiction. The Context says ios.md "owns the update-model table — put the Update Lifecycle sequence diagram here [pipeline.md] and cross-link, don't duplicate the table", but docs/ios.md:18–38 already contains the web-vs-native sequence diagram alongside the table, ios.md is do-NOT-touch, and the Constraints say "Don't duplicate docs/ios.md content — link it". Fix by editing the Context parenthetical to "(which owns the update-model table and the web-vs-native sequence diagram — summarize and cross-link, don't duplicate either)" and rewording AC3 to "Update Lifecycle section summarizes the web-vs-native split and cross-links docs/ios.md's Update Model (no duplicated diagram)". Alternative: if pipeline.md is meant to be the diagram's canonical home (mirroring landscaping-assistant), say so explicitly and exempt the diagram from the no-duplication constraint — but that accepts permanent two-copy drift and is not recommended.
-
Review: #20 docs/security.md (decomp:1800)
review-1803-2026-07-05Verdict: READY
Board item 1803 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#20, 2 points, decomposition child of #19 (parent item 1800 is tracking-only perreview-1800-2026-07-05). Single-file docs ticket; every AC is backed by verified source material on main or in the read-only landscaping reference. Both board-wide traceability gaps flagged in the parent review are resolved or accounted for.Template Completeness (Feature template)
- [x] Type — Feature (routes to template-issue-feature)
- [x] Lineage — child of #19, spec pointer to docs/adoption-plan.md security.md content spec
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — security doc before code; doubles as sales collateral
- [x] Context — self-contained: landscaping heading structure, 3-role adaptation, SOPS, Hetzner+Tailscale network rewrite, Lead-claim seed with mitigation
- [x] File Targets — one create target plus do-not-touch (siblings own other docs)
- [x] Feature Flag — "none"; correct (docs-only; repo has no docs/feature-flags.md — that is a Tier 2 item)
- [x] Acceptance Criteria — 5 checkboxes
- [x] Test Expectations — manual mermaid + link check, run command N/A (appropriate for docs-only)
- [x] Constraints — landscaping as reference not copy-paste; Keycloak roles authoritative, Lead.role display-only
- [x] Checklist
- [x] Related
All 12 sections present. No template gaps.
Traceability
- [x] story:project-setup label — present on board item 1803
- [x] story note verified — project page
project-issuser-stories section now exists (created after review-1800 flagged it); rowproject-setupbacked by README + docs/architecture.md + docs/adoption-plan.md. The parent review's [SCOPE] gap is resolved. - [x] arch:docs label — present on board item 1803
- [x] arch backing verified via taxonomy —
arch:docsis a defined Docs/Process category label ("Documentation work") inconvention-architecture-ids. No dedicatedarch-docsnote exists (search_notes empty), but this is a process-category label, not a system component; the convention note is its backing. The board-wide component arch-note gap (arch-rails-app) remains tracked on review-1800-2026-07-05 and is not re-raised per child. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/20, open, label sprint:0
File Targets
- [x] docs/security.md (create) — does not exist on main; matches adoption-plan.md Tier 1 row ("now (docs phase)") and the plan's security.md content spec nearly verbatim (heading chain, Controller Role Map, SOPS not kubectl, Hetzner Caddy edge rewrite, Lead-claiming seed with "require verified email before claim")
- [x] ~/landscaping-assistant/docs/security.md (read-only reference) — exists; its H2 structure is exactly the 8 sections AC1 names: Authentication Model / Authorization Model / Attack Surface / Input Validation / CSRF Protection / Secrets Management / Network Security / Session Security; Controller Role Map at line 92; Host Authorization "Rails config.hosts" rule at line 233
- [x] docs/architecture.md cross-reference — "### Lead ↔ Keycloak Account Linking" exists on main at line 184, including the email-claim path (line 200) that AC4's attack-surface seed describes; no pending sibling change is required for the reference to resolve
- [x] Do-not-touch list — accurate: siblings #21 (pipeline.md), #22 (testing-strategy + local-dev-setup), #23 (user-stories + architecture amendments), #24 (README closer) own all other docs
Repo Placement
OK. Single-repo docs work; issue filed on the repo it modifies. No other repo affected.
Dependencies
Blocked by: nothing. The docs it reads are merged to main (item 1780/#1 sits in validation but its commits are on main — verified architecture.md content directly). Nothing on board-iss is in_progress. Parent 1800 (#19) is labeled
decomposed, tracking-only.Blocks: #24 (item 1807, README + plan-status closer) carries
blocker:siblingsand waits on this ticket and #21–#23 — relationship documented on both sides. Downstream design coupling: security.md's Controller Role Map and the Lead email-claim mitigation become requirements for #6 (Keycloak OIDC auth) and the controller tickets.Parallel-safe vs siblings: each decomposition child owns disjoint files; #20 creates a single new file and edits nothing, so no merge conflicts with #21–#23 regardless of ordering. #23 modifies architecture.md, which #20 only reads — and the referenced section already exists on main.
Acceptance Criteria
All 5 criteria are objectively verifiable by an agent:
- AC1 heading structure — diff against the 8 named H2s (verified identical to the landscaping reference's actual structure)
- AC2 Controller Role Map coverage — enumerable input set verified by reading issues #6–#16: ApplicationController + SessionsController (#6), PagesController (#7), LeadsController (#8), DashboardController (#9), CatalogController + Admin::CatalogController (#11), MessagesController (#12), ProfileController (#13), Admin::UsersController (#14), AppointmentsController (#15); #10 and #16 name no controllers (harmless) — ~10 controllers total
- AC3 secrets table — the four named secrets match architecture.md line 310's SOPS-encrypted secrets.enc.yaml inventory (Keycloak client secret, Postmark API key, DB creds) plus Rails-standard SECRET_KEY_BASE
- AC4 Known Gaps Lead-claim seed — the attack path and mitigation exist verbatim in the adoption-plan spec and the architecture.md linking section
- AC5 Network Security — Hetzner edge (architecture.md:13), funnel hosts (architecture.md:275, ios.md:70), and the config.hosts rule (landscaping reference line 233, plan says "keep Allowed Hosts table rule") all have concrete source material
Test Expectations are honest: manual mermaid/link check, no fake test commands.
Blast Radius
Docs-only; no code or config. New file, zero edits to existing files — no conflict surface. The README Documentation table row for security.md is correctly deferred to closer #24. One cross-ticket effect worth carrying forward: the "require verified email before claim" mitigation seeded here is a design requirement #6's implementer must read (Known Gaps section) — the docs-before-code intent working as designed. Non-blocking note for the implementer: adoption-plan open decision 3 says "keep MinIO in the secrets list" (ActiveStorage → MinIO for catalog images, #11); AC3's list is a minimum, so adding a MinIO row now is consistent with the plan and saves a later amendment.
Decomposition Assessment
No decomposition needed. 1 file target in 1 repo (rule: >3 files across >2 repos — not tripped); 5 ACs (rule: >5 — at the boundary, not tripped); estimated single-pass time within the 5-minute rule — read one reference doc + one architecture section + enumerate controllers from issues already listed, then author one doc. 2 points. This ticket is itself the product of skill-decompose-ticket sizing, and it landed inside the limits.
Recommendation
No action needed.
-
Review: #22 testing-strategy + local-dev-setup (decomp:1800)
review-1805-2026-07-05Verdict: NEEDS_REFINEMENT
Board item 1805 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#22, 2 points, decomposition child of #19 (item 1800, tracking-only per review-1800-2026-07-05). Scope quality is excellent — every file target, spec reference, and factual claim verified against origin/main (670c515), and the ticket correctly owns plan open decision 1 (test framework wording). The single gap is the missingarch-docsbacking note behind thearch:docslabel — a board-wide gap shared by all decomp:1800 siblings, fixable with one note.Template Completeness (Feature template)
- [x] Type — Feature (routes to template-issue-feature)
- [x] Lineage — child of #19, cites review-1800-2026-07-05 and the spec doc
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story — developer-facing, docs-before-first-PR intent stated
- [x] Context — names both docs, the landscaping-assistant read-only reference, the net-new Keycloak stubbing section, and open decision 1 ownership
- [x] File Targets — 2 create targets plus explicit do-not-touch (sibling ownership)
- [x] Feature Flag — "none"; correct (docs-only; repo has no docs/feature-flags.md — that is a Tier 2 item)
- [x] Acceptance Criteria — 5 checkboxes
- [x] Test Expectations — manual render + link check, run command N/A (appropriate for docs-only)
- [x] Constraints — framework decision must match #3's scaffold; no README contradiction
- [x] Checklist
- [x] Related — project slug + parent
All 12 sections present. No template gaps.
Traceability
- [x] story:project-setup label — present on board item 1805
- [x] story note verified —
project-issuser-stories section (created 2026-07-05 21:52, after the parent review flagged it) lists keyproject-setupwith success metric "Repo, docs, infra, and CI exist; sprints can dispatch" — docs work fits squarely. Parent review's [SCOPE] on the missing project page is resolved. - [x] arch:docs label — present on board item 1805 (and now on parent 1800 and all siblings — consistent family labeling)
- [ ] arch note MISSING —
search_notes("arch-docs")returns empty;list_notes(project="iss")shows only project-iss, review-1800, and board-iss (no arch note under any name). [SCOPE] Create architecture note arch-docs for component docs. Same gap was flagged for westside-basketball (reviews 1673/1674/1676) and claude-custom (review-1526) — the note was never created in any project. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/22, open, label sprint:0 (board item carries the full label set — normal; board labels are authoritative)
File Targets
Verified against origin/main (commit 670c515).
- [x]
docs/testing-strategy.md(create) — does not exist on main; content spec in issue matches docs/adoption-plan.md line 29 nearly verbatim (endpoint-first, no browser/system tests with the Hotwire "server IS the frontend" rationale, "What gates a PR" table, net-new per-role Keycloak session stubbing section, owns the lint/test claims from architecture.md's CI diagram) - [x]
docs/local-dev-setup.md(create) — does not exist on main; plan line 13 spec (prereqs/first-time/daily-commands, trigger "now") matches - [x]
docs/adoption-plan.md(spec reference) — exists on main; open decision 1 verified at line 39: "tickets sayrails test(Minitest default); landscaping docs say 'specs' (RSpec). testing-strategy.md decides; CI diagram stays framework-neutral until then" — exactly what the issue Context claims this ticket owns - [x]
~/landscaping-assistant/docs/testing-strategy.md(read-only reference) — exists (7.0k); headings confirm Philosophy / Why No System Tests / The Hotwire Testing Insight / What gates a PR / Test Layers — everything the adaptation needs - [x]
~/landscaping-assistant/docs/local-dev-setup.md(read-only reference) — exists (2.9k); contains all five sections AC 4 names (Prerequisites / First-Time Setup / Running the App / Key Files / Common Commands) - [x] Supporting claims — port 9999 (README.md:105), ~/rails-base copy prereq (README.md:86,93), "the 3 roles" (docs/user-stories.md:5 "Three roles govern access, enforced in Keycloak and Rails"), RuboCop + Brakeman gate claims (docs/architecture.md:317-318 CI diagram) — all verified on main
- [x] Do-not-touch — "all other docs" correctly assigns security.md to #20, pipeline.md to #21, user-stories/architecture amendments to #23, README/plan-status to closer #24
Repo Placement
OK. Single-repo docs work; issue filed on the repo it modifies. No cross-repo concerns.
Dependencies
Blocked by: nothing. Spec doc is committed on main; nothing on the board is in_progress; siblings are order-independent.
Blocks: #24 (item 1807, the closer) carries
blocker:siblingsand cannot run until this lands — documented via labels. Downstream, this ticket's framework decision feeds #3 (bootstrap, sprint:1): the plan's "before first PR" trigger makes testing-strategy.md a gate for the first code PR, and the issue's Constraints section documents the match-what-#3-scaffolds rule. Adequately documented.Soft cross-link with #21: AC 5 requires both docs to link pipeline.md in their Related sections, but pipeline.md is created by sibling #21 and does not exist yet. If #22 merges first, that link is a forward reference (dead until #21 lands). Not a blocker — siblings are expected to land in parallel and closer #24 (blocker:siblings) is positioned to catch any unresolved link — but the "internal links resolve" manual check should tolerate the forward reference at PR time.
Acceptance Criteria
5 criteria, all objectively verifiable by an agent: AC 1 (system-test exclusion + rationale) and AC 2 (per-role stubbing, 3 roles) are grep-able doc content; AC 3 (framework stated + RuboCop/Brakeman gate claims reconciled) is checkable against architecture.md:317-318; AC 4 names the exact five sections (all present in the landscaping reference) plus the port-9999 consistency check; AC 5 is a link check with the forward-reference caveat above. Test Expectations honestly say manual / N/A — no fake test commands. No missing criteria.
Blast Radius
Docs-only; no code or config. Two propagation effects: (1) this doc settles plan open decision 1 — the framework wording binds #3's CI scaffold and every future test-running ticket, which is exactly why the constraint pins it to Rails-default Minitest unless reasoned otherwise; (2) the "what gates a PR" table overlaps sibling #21's pipeline.md territory — the plan assigns gate-claim ownership to testing-strategy.md and AC 3's "reconciles" wording handles it. Not touching README avoids the CLAUDE.md-symlink propagation the parent review warned about.
Decomposition Assessment
No decomposition needed. 2 file targets, 1 repo (rule: >3 across >2 — not tripped); 5 acceptance criteria (rule: >5 — not tripped, at threshold); estimated agent work under 5 minutes (adapt one 7k and one 2.9k reference doc against explicit per-doc specs). This IS a decomposition child — the split did its job.
Recommendation
[SCOPE]Create architecture note arch-docs for component docs — the arch:docs label has no backing note in pal-e-docs. Board-wide gap: all five decomp:1800 siblings (#20-#24) carry arch:docs, so one note clears the traceability leg for the whole family. Suggested content: in-repo documentation standards, docs/ tree structure, cross-reference conventions, the adoption-plan tier/trigger model.
No [BODY] or [LABEL] fixes needed — the issue body and board labels are accurate as written. On re-review after the arch-docs note exists, this ticket is READY as-is.
-
Review: #23 Amend user-stories + architecture (decomp:1800)
review-1806-2026-07-05Verdict: READY
Board item 1806 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#23, 2 points. Decomposition child of #19 (parent item 1800, tracking-only per review-1800-2026-07-05). Scope is tight and fully executable: two amend-in-place file targets verified on main, spec section indocs/adoption-plan.mdmatches the issue Context nearly verbatim, all planned additions confirmed absent from the current docs, and the Delivery Phases constraint is backed by sprint labels verified on the Forgejo issues themselves.Template Completeness (Feature template)
- [x] Type — Feature (routes to template-issue-feature)
- [x] Lineage — child of #19, names review-1800-2026-07-05 and the spec doc + section
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story
- [x] Context — full per-doc content spec inlined (matrix actions, phases, open questions, KDD list)
- [x] File Targets — modify list + do-not-touch list ("All other docs — sibling tickets own them")
- [x] Feature Flag — "none"; correct (docs-only; repo has no docs/feature-flags.md yet)
- [x] Acceptance Criteria — 5 checkboxes
- [x] Test Expectations — manual render + link check, run command N/A (appropriate for docs-only; same pattern accepted in review-1800)
- [x] Constraints — amend-in-place; Delivery Phases must match sprint labels, not invent a plan
- [x] Checklist
- [x] Related — project slug + parent
All 12 sections present. No template gaps.
Traceability
- [x] story:project-setup label — present on board item 1806
- [x] story note verified —
project-issuser-stories section exists (gap from review-1800 has been fixed); rowproject-setuppresent, backed by "README + docs/architecture.md + docs/adoption-plan.md" - [x] arch:docs label — present on board item 1806; taxonomy-valid
- [x] arch note found —
search_notes("arch-docs")returns notearch-docs("Architecture: Documentation"). Caveat: that note is scoped to project westside-basketball, not ISS. Advisory only — see Recommendation; this is the same board-wide platform gap review-1800 already flagged, not a defect of this ticket's scope. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/23, open, label sprint:0 (full label set lives on the board item, same pattern as #19)
File Targets
Verified against origin/main.
- [x]
docs/user-stories.md(modify) — exists on main. Current structure: Roles / Client Journey / Epics 1–6 / Role-Tab Access Matrix. All six planned additions are genuinely new: grep for "permission matrix|delivery phase|open question|related ticket|persona|default tab" hits only "personalized" in US-2.2 (false positive). The Role-Tab Access Matrix (4 tabs x 3 roles, lead/client/admin) exists at the doc's tail — AC4's consistency anchor is real, and the ≥12-action permission matrix is a genuine extension of it, matching the plan's "~15 actions" estimate. - [x]
docs/architecture.md(modify) — exists on main; no "Key Design Decisions" or "Rails Structure" headings anywhere. The issue supplies 6 KDDs (mirroring the plan's list), so the ≥5 AC is achievable. "Rails Structure" stub correctly defers content to scaffold ticket #3. - [x] Spec alignment —
docs/adoption-plan.md"Amendments to existing docs" section exists on main and matches the issue Context item-for-item (matrix actions, Delivery Phases mirroring the sprint map, the same 4 Open Questions, Related Tickets #3–#18, default tab per role, personas; the same 6 KDDs and Rails Structure stub). - [x] Do-not-touch list — correct: siblings own docs/security.md (#20), docs/pipeline.md (#21), testing-strategy + local-dev-setup (#22), README + plan status (#24). No overlap with this ticket's targets.
Repo Placement
OK. Single-repo docs work; the issue is filed on the repo it modifies. Neither README.md nor CLAUDE.md is touched (those belong to closer #24), so no symlink propagation concerns here.
Dependencies
Blocked by: nothing. Item 1780 (#1), which created both target docs, is merged to main (files verified present) and sits in validation. No items in in_progress touch these files.
Blocks: sibling #24 (item 1807, "Docs closer: README + plan status") carries
blocker:siblings— it waits on this ticket and #20–#22. Documented board-side via that label.Parallel-safe: siblings #20/#21/#22 target disjoint files; all five children share parent #19 (tracking-only, labeled
decomposed).Inputs verified: Delivery Phases constraint requires sprint labels on the Forgejo issues — spot-checked Forgejo-side: #3=sprint:1, #10=sprint:3, #18=sprint:6, #19/#24=sprint:0; board mirrors sprint:1–6 across #3–#18 and sprint:0 on the docs children. AC4 requires issues #6–#16 as input — all exist on board-iss (items 1786–1796).
Acceptance Criteria
All 5 criteria objectively verifiable by an agent: (1) section presence + matrix size ≥12x3, Open Questions ≥4 — countable; (2) numbered KDDs ≥5 + Rails Structure stub — countable; (3) "no existing content removed" — verifiable by diff against main; (4) permission matrix consistency with the Role-Tab Access Matrix (verified to exist) and issues #6–#16 (verified to exist) — enumerable; (5) mermaid renders + links resolve — manual, honestly declared as such in Test Expectations. No fake test commands. AC count is exactly at the 5-AC threshold, not over it.
Blast Radius
Docs-only; no code or config. Two couplings worth noting: (1) sibling #20's docs/security.md Controller Role Map derives from the same role semantics as this ticket's Role Permission Matrix — both must source issues #6–#16 as ground truth to stay consistent if worked in parallel; (2) the Delivery Phases section becomes a second place sprint assignments are written down — the constraint correctly forces it to mirror the labels rather than fork a new plan. README's Documentation table already links both target docs, so no README edit is needed (and #24 owns README anyway).
Decomposition Assessment
No decomposition needed. 2 file targets in 1 repo (rule: >3 across >2 repos — not tripped); 5 ACs (rule: >5 — not tripped); estimated agent work fits a single pass — all content is pre-specified in adoption-plan.md and the issue Context, inputs are the two docs plus board/issue labels, no research or authoring-from-scratch. This ticket is one of the two amendment halves review-1800's decomposition explicitly recommended.
Recommendation
No action needed on this ticket — READY to move to todo.
Advisory, non-blocking (board-wide platform gap, already surfaced in review-1800, owned by pal-e-docs not this ticket):
[SCOPE]Thearch-docsnote in pal-e-docs is scoped to westside-basketball. Either generalize it into a cross-project docs-component note or create an ISS-scoped architecture note (e.g.,arch-iss-docs) so board-iss'sarch:docslabel has project-local backing.
-
Review: #19 Docs adoption Tier 1 (security, pipeline, testing, local-dev)
review-1800-2026-07-05Verdict: NEEDS_REFINEMENT
Board item 1800 (board-iss), Forgejo issue
ldraney/intelligentstaffingsystems#19, 5 points. Scope quality is high — every file target verified accurate against main (commit 670c515) — but the ticket trips two decomposition triggers, both traceability backing notes are missing, and the issue body contains one self-contradiction about deleting the spec file.Template Completeness (Feature template)
- [x] Type — Feature (routes to template-issue-feature)
- [x] Lineage — standalone, executes Tier 1 of docs/adoption-plan.md
- [x] Repo — ldraney/intelligentstaffingsystems
- [x] User Story
- [x] Context — names the spec doc and scopes to Tier 1 only
- [x] File Targets — create/modify/do-not-touch all present
- [x] Feature Flag — "none"; correct (docs-only, and repo has no docs/feature-flags.md yet — that is itself a Tier 2 item)
- [x] Acceptance Criteria — 7 checkboxes
- [x] Test Expectations — manual mermaid + link checks, run command N/A (appropriate for docs-only)
- [x] Constraints
- [x] Checklist
- [x] Related
All 12 sections present. No template gaps.
Traceability
- [x] story:project-setup label — present on board item 1800
- [ ] story note MISSING — project page
project-issdoes not exist (404); projectisscontains only the board note. [SCOPE] Create user story entry on project-iss user-stories section. - [x] arch:rails-app label — present on board item 1800
- [ ] arch note MISSING —
search_notes("arch-rails-app")andsearch_notes("rails-app")both return empty (semantic search unavailable — Ollama down — so verified by keyword only). [SCOPE] Create architecture note arch-rails-app. - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/intelligentstaffingsystems/issues/19, open, label sprint:0
Note: the missing project page and arch note affect every ticket on board-iss, not just this one. Items 1798/1799 already passed to validation with the same gap.
File Targets
Verified against origin/main (= local HEAD, identical trees, commit 670c515).
- [x] docs/security.md (create) — does not exist on main; matches plan Tier 1 row; content spec (Controller Role Map, Lead-claiming attack seed, SOPS secrets table, Hetzner-edge network) matches the plan's security.md section verbatim
- [x] docs/pipeline.md (create) — does not exist; matches plan (4-flow overview, three-repo table, Update Lifecycle cross-linked to docs/ios.md, which exists)
- [x] docs/testing-strategy.md (create) — does not exist; matches plan (endpoint-first, no system tests, role-stubbing section, owns lint/test claims)
- [x] docs/local-dev-setup.md (create) — does not exist; port 9999 claim verified (README.md:105, docs/architecture.md:335); ~/rails-base copy step verified in README local-dev section
- [x] docs/user-stories.md (modify) — exists; currently has Roles / Client Journey / Epics 1–6 / Role-Tab Access Matrix and lacks all six additions named (Role Permission Matrix, Delivery Phases, Open Questions, Related Tickets, default tab per role, personas) — additions are genuinely new
- [x] docs/architecture.md (modify) — exists; no Key Design Decisions or Rails Structure sections yet; plan supplies 6 KDDs so the AC's ≥5 is achievable
- [ ] README.md (modify) — exists, Documentation table rows verified (user-stories, architecture, ios, adoption-plan) — BUT the instruction "remove the adoption-plan.md row and delete docs/adoption-plan.md if all Tier 1 items land" contradicts both the plan's own deletion rule (adoption-plan.md line 3: "delete this file when the tree below exists" — the tree includes Tier 2/3) and the issue's own Context ("Tier 2/3 docs are triggered later per the plan's trigger column"). Deleting at Tier 1 destroys the only spec for Tier 2/3 (feature-flags, keycloak-setup + Postmark SMTP, networking Hetzner rewrite, messaging template, the do-not-adopt list, open decision 3). See [BODY] recommendation.
- [x] docs/ios.md (do NOT touch) — exists on main
- [x] ~/landscaping-assistant/docs/ (read-only reference) — exists; all four Tier 1 source files present (security.md, pipeline.md, testing-strategy.md, local-dev-setup.md)
Repo Placement
OK. Single-repo docs work; the issue is filed on the repo it modifies. CLAUDE.md is a symlink to README.md (git mode 120000), so README edits propagate into agent session context — same repo, no additional issue needed.
Dependencies
Blocked by: nothing. Item 1780 (#1, which created the docs this ticket amends) is merged to main and sitting in validation; the spec docs/adoption-plan.md is committed at main. No in_progress items touch the same files.
Blocks (undocumented): effectively all build tickets — the plan sets testing-strategy.md's trigger as "before first PR", so this ticket gates #3 (bootstrap) and downstream #6–#16. AC 2 also reads issues #6–#16 as input (all exist on the board; spot-check: #6 and #11 name controllers, #16 names none — harmless). The issue documents the docs-before-code intent in the User Story but never states "blocks #3" explicitly.
Acceptance Criteria
All 7 criteria are objectively verifiable by an agent: doc existence + section outlines (diff vs plan), Controller Role Map coverage (enumerable from issues #6–#16), matrix size (≥12 actions x 3 roles), KDD count (≥5 numbered), README table completeness, mermaid/link check (manual, stated as such in Test Expectations). No fake test commands. Quality is good — the problem is quantity: 7 ACs exceeds the 5-AC single-pass threshold.
Blast Radius
Docs-only; no code or config. Two propagation effects: (1) README.md edits flow through the CLAUDE.md symlink into every future agent session's context for this repo — the Documentation table must stay accurate; (2) deleting docs/adoption-plan.md prematurely (see [BODY]) would erase the Tier 2/3 spec with no other copy. The framework-neutral test-wording constraint correctly defers plan open decision 1 (Minitest vs RSpec) to testing-strategy.md itself.
Decomposition Assessment
NEEDS DECOMPOSITION — route to skill-decompose-ticket. 7 file targets (4 create + 3 modify) in 1 repo (repo-count rule not tripped); 7 acceptance criteria > 5 (tripped); estimated agent work well over 5 minutes (tripped) — a single pass must read the full plan, the landscaping-assistant reference docs, and issues #6–#16, then author four full docs with mermaid diagrams and amend three more. The plan's per-doc content specs give a clean natural split: (1) security.md, (2) pipeline.md, (3) testing-strategy.md, (4) local-dev-setup.md, (5) user-stories.md amendments, (6) architecture.md amendments + README table + adoption-plan status update as the closer.
Recommendation
[DECOMPOSE]7 ACs and ~7 docs of authoring exceed the single-pass rule — route to skill-decompose-ticket; split per the plan's per-doc content specs (4 create tickets + 2 amendment tickets, README/plan-status update in the closer)[BODY]Fix the README.md file-target instruction: do not delete docs/adoption-plan.md when Tier 1 lands — keep the file and mark the Tier 1 rows done in its status table; delete only when the full target tree (Tier 2/3 included) exists, per the plan's own line-3 rule and the issue's own Context[SCOPE]Create user story entry on project-iss user-stories section (project page project-iss does not exist — board-wide gap)[SCOPE]Create architecture note arch-rails-app for component rails-app (board-wide gap)
Doc 30
-
Validation: ISS staging environment with auto-deploy
validation-svc193-2026-07-26Verdict: PARTIAL
Ticket
svc#193 — Create ISS staging environment with auto-deploy on merge to main. Merged via PR #196. Tofu apply ran successfully via Woodpecker pipeline #275 (re-validation after prior FAIL).
Environment
k3s cluster (archbox), namespace
intelligentstaffingsystems-staging, ArgoCD appintelligentstaffingsystems-staging. Kustomize overlay atoverlays/intelligentstaffingsystems/stagingin pal-e-deployments.Checks
# Criterion How Verified Result Evidence 1 Staging namespace exists kubectl get ns intelligentstaffingsystems-stagingPASS Status: Active, Age: ~9m 2 ArgoCD Application created and synced kubectl get application -n argocdPASS Sync: Synced, Health: Healthy. Resources: Secret, Service, Deployment, ServiceMonitor all Synced. 3 Auto-sync enabled on ArgoCD app ArgoCD app spec inspection PASS syncPolicy.automated: {prune: true, selfHeal: true}4 Image Updater configured for auto-deploy ArgoCD app annotation inspection PASS image-list: harbor.tail5b443a.ts.net/intelligentstaffingsystems/app, strategy: newest-build, allow-tags:regexp:^[0-9a-f]{7,40}$, write-back: git:repocreds to kustomization5 Staging pod running with correct image kubectl get pods+ image jsonpathPASS 1/1 Running, 0 restarts. Image: harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c433...(matches latest main commit)6 Staging service exists kubectl get svcPASS ClusterIP 10.43.246.122, port 3000/TCP 7 App responds inside cluster kubectl exec ... curl localhost:3000PASS HTTP 403 (expected — Keycloak auth enforcement, confirms Rails app is running) 8 Tofu apply succeeded Woodpecker pipeline #275 PASS Pipeline status: success. Apply: "14 added, 5 changed, 4 destroyed." CI robot created. 9 Secrets deployed kubectl get secretPASS harbor-creds(dockerconfigjson) +intelligentstaffingsystems-staging-secrets(Opaque, 10 keys)10 External access (DNS + Caddy) curl Tailscale funnel URL BLOCKED Tailscale funnel URL timed out. No DNS CNAME. Blocked by svc#198. 11 CNPG database provisioned kubectl get clusters.postgresql.cnpg.ioBLOCKED No CNPG resources found. Blocked by deploy#242. Regression Check
ISS production environment verified healthy: ArgoCD app
intelligentstaffingsystemsSynced/Healthy, prod pod 1/1 Running with 0 restarts (age 20h). No regression from staging infrastructure changes.Discovered Issues
No new issues discovered. Three known blockers already tracked:
- svc#198 — DNS CNAME + Caddy vhost for staging
- svc#199 — Harbor staging robot cross-project pull access
- deploy#242 — CNPG database for staging
Note: harbor-creds secret exists and pod pulled successfully (from local cache). svc#199 concerns proper cross-project robot access for when images are not cached locally.
-
Validation: Re-land stranded ISS dev port fix + staging overlay onto main
validation-240-2026-07-26Verdict: PASS
Ticket
deploy#240 (PR #241) — Re-landed two stranded commits onto main: dev overlay port fix (9999 to 8888) and the new ISS staging kustomize overlay. Docs fix for the dev README correcting its stated purpose.
Environment
Prod cluster — ArgoCD app
intelligentstaffingsystems, source pathoverlays/intelligentstaffingsystems/prod, namespaceintelligentstaffingsystems. Repo-level verification against pal-e-deployments main branch at commitb4316b9.Checks
# Criterion How Verified Result Evidence 1 ArgoCD synced to merge commit kubectl get application -n argocd intelligentstaffingsystemssync status + revisionPASS Status: Synced, revisionb4316b9= PR #241 merge commit (HEAD of main)2 ArgoCD app healthy kubectl get application -n argocd intelligentstaffingsystemshealth statusPASS Status: Healthy. All 4 resources (Secret, Service, Deployment, ServiceMonitor) show Synced.3 Prod pod running, no crash loops kubectl get pods -n intelligentstaffingsystemsPASS Pod intelligentstaffingsystems-69c4f699d6-vp89s: 1/1 Running, 0 restarts, age 13h. Image:harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c433...4 Dev overlay port fix landed (9999 to 8888) git show b4316b9:overlays/intelligentstaffingsystems/dev/deployment.yamlPASS UPSTREAM env value is 100.110.151.59:88885 Staging overlay files exist on main git show b4316b9 --statPASS 3 new staging files landed: kustomization.yaml,deployment-patch.yaml,secrets.enc.yaml. Namespace set tointelligentstaffingsystems-staging.6 Prod overlay unchanged by merge git diff 458b6fd..b4316b9 -- overlays/intelligentstaffingsystems/prod/PASS Empty diff — prod overlay untouched 7 Prod endpoint healthy curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/upPASS HTTP 200 Regression Check
ISS prod namespace fully healthy: Deployment 1/1 Ready and Available, Service ClusterIP on 3000/TCP, pod 1/1 Running with 0 restarts. Landing page (
https://intelligentstaffingsystems.ai/) returns HTTP 200. All ArgoCD-managed resources (Secret, Service, Deployment, ServiceMonitor) report Synced. No unexpected drift.Discovered Issues
None. Note: the staging and dev ArgoCD applications do not exist yet — they will be created when
tofu applyruns on pal-e-services (follow-ups documented in PR #241). This is expected and does not block this ticket's validation, which covers landing the overlay files onto main. -
Validation: Keycloak registration flow (register.ftl + Rails wiring)
validation-59-2026-07-26Verdict: PASS
Ticket
#59 (board item #1831) — Keycloak registration flow: register.ftl template deployed to Keycloak with ISS branding, phone field in registration form, Rails sessions controller wired for Keycloak callback with three-path Lead resolution and phone sync.
Merged PR: #72 — feat: in-app registration with Keycloak phone field and Lead sync (commit dfe3b8d)
Environment
Production cluster, namespace
intelligentstaffingsystems, URL:https://intelligentstaffingsystems.ai. Keycloak athttps://keycloak.tail5b443a.ts.net, realmiss.Tiers Executed
Tier 1 (CI tests) + Tier 3 (production). Labels:
type:feature,arch:auth,story:registration,sprint:A.Checks
# Criterion How Verified Result Evidence 1 register.ftl deployed to Keycloak theme kubectl exec -n keycloak deploy/keycloak -- ls /opt/keycloak/themes/iss/login/register.ftlPASS File exists as symlink (configmap mount). Content verified: FreeMarker template with firstName, lastName, email, phone fields. 2 register.css deployed alongside register.ftl kubectl exec -n keycloak deploy/keycloak -- ls /opt/keycloak/themes/iss/login/resources/css/PASS Both login.cssandregister.csspresent in theme resources.3 Keycloak registration endpoint responds curl to /realms/iss/protocol/openid-connect/registrationswith correct client_id and redirect_uriPASS Returns 302 with PKCE error (expected -- PKCE is required and curl does not send code_challenge). Endpoint is live, not 404/500. 4 Rails registration form at /leads/new curl -s https://intelligentstaffingsystems.ai/leads/newPASS HTTP 200. Form contains all expected fields: first_name, last_name, email, phone, business_name, business_description, project_description. 5 Sessions controller: Keycloak callback wiring Code review of app/controllers/sessions_controller.rbPASS Three-path Lead resolution (by sub, email claim, walk-in create). Phone extraction from Keycloak token. Phone sync on login. Role sync from token. 6 Lead model phone validation Code review of app/models/lead.rbPASS PHONE_FORMATregex validates phone presence and format.7 CI tests pass (Tier 1) Woodpecker pipeline #188 (latest main push) PASS 481 runs, 1314 assertions, 0 failures, 0 errors, 0 skips. Includes 20+ sessions_controller tests covering: role extraction, lead resolution by sub, email claim with email_verified, walk-in create, phone sync, phone array handling, invalid phone rejection, post-registration redirect, role sync, logout, auth failure. 8 Pod running with correct image kubectl get pods -n intelligentstaffingsystemsPASS Pod intelligentstaffingsystems-69c4f699d6-vp89s: Running, 0 restarts, 9h uptime. Image tagb46c433(latest main commit, verified ancestor of PR #72 commit dfe3b8d).9 ArgoCD sync and health kubectl get application intelligentstaffingsystems -n argocdPASS Sync: Synced, Health: Healthy. Regression Check
All key routes verified healthy in production:
/— 200 (landing page, references registration correctly)/about— 200/leads/new— 200 (registration form)/login— 302 (redirects to App Store, expected)/catalog— 302 (requires auth, expected)/dashboard— 302 (requires auth, expected)
Keycloak pod healthy (Running, 7d11h uptime). No unexpected behavior observed.
Discovered Issues
None. All checks passed. No regressions detected.
-
Validation: Appointment scheduling with 24hr advance rule (#54)
validation-54-2026-07-26Verdict: PASS
Ticket
#54 — Appointment scheduling with 24hr advance rule. Board item #1824 on board-iss.
Merged via PR #101. Commit
1f40f2b.Shipped: Appointment model with 24hr minimum advance validation, booking form at
/appointments/new, confirmation page, backward-compatible/bookingredirect, ActiveStorage file attachments with content-type and size validation, and comprehensive test coverage (model + controller).Environment
Production cluster, namespace
intelligentstaffingsystems. Podintelligentstaffingsystems-69c4f699d6-vp89s. URL:https://intelligentstaffingsystems.ai.Deployed image:
harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c43399b520241eece48595c114501489fc7f7(commitb46c433, which is a descendant of merge commit1f40f2b).Tiers Executed
Tier 1 (local tests): SKIPPED — Ruby 3.4.8 not installed on host; Docker test runner documented as hanging (#65). CI pipeline serves as Tier 1 proxy.
Tier 3 (production): EXECUTED — pod status, ArgoCD sync, route-level curl, regression checks.
Checks
# Criterion How Verified Result Evidence 1 CI pipeline green (includes all appointment tests) Woodpecker pipeline #188 (latest main push) PASS All 7 steps success: clone, database, bundle-install, lint, security, test, build-and-push. Note: pipeline #130 (PR #101 merge push) failed due to schema.rb dropping project_requests table — fixed by PR #104 (pipeline #135, success). 2 Pod running and healthy in production kubectl get pods -n intelligentstaffingsystemsPASS Pod intelligentstaffingsystems-69c4f699d6-vp89s— Running, 0 restarts.3 ArgoCD application synced and healthy kubectl get application -n argocd intelligentstaffingsystemsPASS Sync: Synced, Health: Healthy. 4 Deployed image includes PR #101 changes git log --ancestry-path 1f40f2b..b46c433PASS 7 commits between merge commit and deployed tag — PR #101 is an ancestor of the deployed image. 5 /appointments/newroute serves (auth-gated)curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/appointments/newPASS HTTP 302 redirect to /login— correct behavior for authenticated route.6 /bookingbackward-compat redirectcurl -s -o /dev/null -w "%{http_code} %{redirect_url}" https://intelligentstaffingsystems.ai/bookingPASS HTTP 301 redirect to https://intelligentstaffingsystems.ai/appointments/new.7 Appointments CSS asset deployed curl -s https://intelligentstaffingsystems.ai/ | grep appointmentsPASS Landing page loads appointments-47b56982.cssvia asset pipeline.8 Health endpoint responsive curl https://intelligentstaffingsystems.ai/upPASS HTTP 200. 9 Test coverage exists for model and controller Read test files in repo PASS test/models/appointment_test.rb: 12 tests (topic, scheduled_at, status, notes, associations).test/controllers/appointments_controller_test.rb: 15 tests (auth, form fields, booking, validation failures, attachments, confirmation, backward compat).Regression Check
All existing routes verified to still respond correctly (all return expected auth redirects or 200):
/— 200 (landing page)/about— 200/up— 200 (health)/catalog— 302 (auth redirect)/communications— 302 (auth redirect)/projects— 302 (auth redirect)/crm— 302 (auth redirect)/messages— 302 (auth redirect)/login— 302 (Keycloak redirect)
No regressions detected. The schema.rb issue from the original merge (missing project_requests table) was fixed by PR #104 before subsequent deploys.
Discovered Issues
dev.intelligentstaffingsystems.aireturns HTTP 502. This is a pre-existing condition unrelated to #54 — the dev environment may not be fully deployed. Not a regression from this PR. -
Validation: block lead role from DM at controller level
validation-55-2026-07-26Verdict: PASS
Ticket
#55 — Block lead role from DM at controller level. Board item #1825 on board-iss.
Shipped:
before_action :require_client_or_adminguard inMessagesControllerthat redirects lead-role users to/communicationswith flash "Available after your first meeting". Replaces UI-only gating with defense-in-depth controller enforcement.Merged PR: #100 (commit 4d8a96e, merged to main)
Environment
Production cluster, namespace
intelligentstaffingsystems, URLhttps://intelligentstaffingsystems.ai.Pod:
intelligentstaffingsystems-69c4f699d6-vp89s— 1/1 Running, 0 restarts, 9h uptime.Image:
harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c43399b520241eece48595c114501489fc7f7Checks
# Criterion How Verified Result Evidence 1 Lead-role users redirected from /messages to /communications Code review: require_client_or_adminbefore_action at line 17 of messages_controller.rb; method at lines 100-105 checkscurrent_user_has_role?("client") || current_user_has_role?("admin")and redirects otherwisePASS Controller source verified on main 2 Flash message "Available after your first meeting" shown to leads Code review: line 104 — redirect_to communications_path, alert: "Available after your first meeting"PASS Controller source verified on main 3 Client and admin roles can still access /messages Guard returns early for client/admin roles (line 102). Tests verify client GET/POST /messages succeed. Pipeline #117 test step green. PASS Branch pipeline #117: test step SUCCESS 4 Uses Keycloak realm role (not Lead.role column) Code uses current_user_has_role?which reads from session realm_access, not the database columnPASS Controller source lines 100-102 5 Lead POST /messages blocked (no message created) Tests assert assert_no_difference "Message.count"for lead POST. 10 lead-redirect tests pass in CI.PASS Branch pipeline #117: test step SUCCESS 6 Docs updated to reflect controller enforcement docs/messaging.mdline 3 and access control table updated; referencesbefore_action :require_client_or_adminPASS messaging.md verified on main 7 CI pipeline green (branch) Woodpecker pipeline #117 (55-lead-dm-blocking branch): clone, database, bundle-install, lint, security, test — all SUCCESS PASS Pipeline #117 status: success 8 Code deployed to production git merge-base --is-ancestor 4d8a96e b46c433confirms PR #100 is in deployed image. Pipeline #188 (latest main push) built and pushed successfully.PASS Image tag b46c433 includes commit 4d8a96e 9 Pod healthy in production kubectl get pods -n intelligentstaffingsystems: 1/1 Running, 0 restartsPASS Pod intelligentstaffingsystems-69c4f699d6-vp89s Running 10 Production endpoint responsive curlroot URL returns HTTP 200;/messagesreturns 302 (redirect to login for unauth — correct)PASS HTTP 200 at /, HTTP 302 at /messages Regression Check
Root URL (/) returns 200 — landing page healthy. Production pod logs show no error spikes related to messaging. Communications route (/communications) returns 302 for unauthenticated users (expected). Pod has 0 restarts over 9h. Latest main pipeline #188 passes all 7 steps including tests that exercise the full messages controller test suite.
Note: Pipeline #129 (the push-to-main for this specific merge) shows failure with steps skipped due to CI infrastructure issues (known push-event gap). The branch pipeline #117 and the latest main pipeline #188 are both fully green, confirming code correctness.
Discovered Issues
None. The implementation is clean and well-tested.
-
Validation: dev.intelligentstaffingsystems.ai DNS record and Caddy vhost (#79)
validation-79-2026-07-26Verdict: PASS
Ticket
ldraney/intelligentstaffingsystems#79 — Set up DNS A record and Caddy reverse-proxy vhost for dev.intelligentstaffingsystems.ai. Board item #1870 (decomp of #1868 / issue #77).
Environment
Production cluster (k3s). DNS via GoDaddy pointing to 178.156.129.142. Caddy reverse proxy on edge server. Namespace:
intelligentstaffingsystems.Checks
# Criterion How Verified Result Evidence 1 DNS A record resolves dev.intelligentstaffingsystems.ai to edge IP python3 socket.gethostbyname('dev.intelligentstaffingsystems.ai')PASS Resolves to 178.156.129.142 (same as prod domain) 2 TLS certificate valid for dev domain openssl s_client -connect dev.intelligentstaffingsystems.ai:443PASS CN=dev.intelligentstaffingsystems.ai, issued 2026-07-19, expires 2026-10-17 (Caddy auto-TLS) 3 Caddy vhost configured and responding curl -sI https://dev.intelligentstaffingsystems.ai/PASS Response includes server: Caddy, HTTP/2, TLSv1.3. Vhost exists and terminates TLS.4 Dev domain HTTP status curl -s -o /dev/null -w "%{http_code}"EXPECTED 502 502 Bad Gateway. The upstream dev deployment does not exist yet — no dev kustomize overlay or ArgoCD app. Dev environment setup is tracked in svc#192, svc#193, svc#200 (all in validation column). This is expected behavior for this ticket's scope. Regression Check
Check Result Evidence Prod domain (intelligentstaffingsystems.ai) PASS HTTP 200, HTML title renders correctly Prod /about route PASS HTTP 200 Pod health PASS 1/1 Running, 0 restarts, image tag b46c433 ArgoCD sync PASS Synced + Healthy Latest Woodpecker pipeline (#188) PASS success (push to main) Discovered Issues
None. The 502 on dev domain is a known dependency gap — the dev upstream (ArgoCD dev overlay) is tracked in separate pal-e-services tickets (svc#192, svc#193, svc#200), all currently in the validation column on board-iss.
Merge Context
No PR in the ISS Rails repo directly references issue #79. The DNS A record was configured via GoDaddy (godaddy-tofu), and the Caddy vhost was added to the server configuration. The Forgejo issue is closed. Sibling decomps: #78 (kustomize overlays, done) and #80 (Makefile/seed/docs via PR #81, done).
-
Validation: Local dev tests fail due to bundle install network timeouts
validation-65-2026-07-26Verdict: PASS
Ticket
ldraney/intelligentstaffingsystems#65 — Local dev tests fail due to bundle install network timeouts
Merged PR: #110 "fix: build dev image with pre-installed gems to eliminate network timeouts (#65)"
Board item: #1895 on board-iss
Environment
Prod cluster:
intelligentstaffingsystemsnamespace. Pod:intelligentstaffingsystems-69c4f699d6-vp89s. Image:harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c43399b520241eece48595c114501489fc7f7(HEAD of main, includes PR #110). URL:https://intelligentstaffingsystems.ai/.Checks
# Criterion How Verified Result Evidence 1 Dockerfile.dev exists and pre-installs gems from Gemfile Read file on main branch PASS Dockerfile.dev: extendsruby-rails-build:latest, copies Gemfile/Gemfile.lock, runsbundle install --jobs=42 docker-compose.yml builds from Dockerfile.dev instead of pulling image directly Read file on main branch PASS build: context: . dockerfile: Dockerfile.devreplaces the oldimage:directive3 Container command skips bundle install when gems are present Read docker-compose.yml PASS Command: bundle check || bundle install && bundle exec rails server -b 0.0.0.0 -p 88884 Makefile has build target for rebuilding after Gemfile changes Read Makefile PASS build: ## Build the dev image (run after Gemfile changes)target added,.PHONYupdated5 Documentation updated to reflect new workflow Read docs/local-dev-setup.md PASS Docs updated: "Rebuilding after Gemfile changes" section, Makefile targets table includes make build, Key Files table listsDockerfile.dev, compose template table shows build-from-Dockerfile.dev6 PR CI pipeline passes (lint, security, test) Woodpecker pipeline #178 PASS Pipeline #178 (pull_request event): status success7 Production pod healthy after merge kubectl get pods -n intelligentstaffingsystems PASS intelligentstaffingsystems-69c4f699d6-vp89s 1/1 Running 0 9h8 Production endpoint responds curl https://intelligentstaffingsystems.ai/ PASS HTTP 200 9 No regressions: subsequent CI pipelines pass Woodpecker pipeline #188 (push to main, commit b46c433) PASS Pipeline #188: status success— full CI (lint, security, test, build-and-push) passed on code that includes PR #110Regression Check
Pipeline #188 (the most recent push to main, commit
b46c433) ran the full CI suite — lint, security, test, build-and-push — and passed. This confirms the codebase including PR #110's changes has no regressions. Production pod is running with 0 restarts on the latest image.Notes
- Merge push pipeline #183 shows failure with all steps skipped. This is the known intermittent Woodpecker push-event gap documented in
project_push_event_gap.md. Pipeline #185 (next merge push) also failed the same way. Pipeline #188 (latest merge push) succeeded, confirming the issue is intermittent, not caused by this PR. - Local Docker verification skipped. Per project memory (
project_docker_test_gap.md): "Docker tests hang (#65); agents must skip docker verification." The fix itself addresses this very issue — building gems into the image eliminates the network timeout that caused hangs. - Dev URL (dev.intelligentstaffingsystems.ai) returns 502. This is expected when no dev tunnel is running — it is a separate concern from this ticket.
Discovered Issues
None. The push-event gap is already tracked.
- Merge push pipeline #183 shows failure with all steps skipped. This is the known intermittent Woodpecker push-event gap documented in
-
Validation: Replace favicon with ISS helmet logo
validation-106-2026-07-26Verdict: PASS
Ticket
ldraney/intelligentstaffingsystems#106 — Replace placeholder red circle favicon with the ISS astronaut helmet logo (phone visor variant). PNG and SVG both updated.
Merged PR: #107 (commit
2ef85dd)Board item: #1897 on board-iss
Environment
Production cluster, namespace
intelligentstaffingsystems, URL:https://intelligentstaffingsystems.aiPod:
intelligentstaffingsystems-69c4f699d6-vp89s(1/1 Running, 0 restarts)Image:
harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c43399b520241eece48595c114501489fc7f7(HEAD of main, includes commit2ef85dd)Tiers Executed
Tier 1 (local file verification) + Tier 3 (production deployment and visual check). Per
arch:frontendtier mapping.Checks
# Criterion How Verified Result Evidence 1 Woodpecker pipeline green for merge commit Woodpecker MCP: list_pipelines PASS Pipeline #140 (push to main) = success; Pipeline #139 (PR) = success 2 Deployment includes PR #107 commit kubectl get pods + git merge-base PASS Pod image tag b46c433...is HEAD of main;2ef85ddconfirmed as ancestor viagit merge-base --is-ancestor3 Old red circle favicon replaced with ISS helmet logo (PNG) curl + file size comparison PASS /icon.pngreturns HTTP 200, size = 98890 bytes (matches new file; old was 4166 bytes). Visual inspection of local file confirms astronaut helmet with phone visor and dashboard bars in navy/gold palette.4 SVG favicon updated with ISS helmet logo curl + content inspection PASS /icon.svgreturns HTTP 200. SVG contains ISS helmet elements: Dome, Visor, Dashboard bars, Antenna (4 elements confirmed via grep).5 HTML references correct favicon files curl + grep HTML head PASS HTML contains: <link rel="icon" href="/icon.png" type="image/png">,<link rel="icon" href="/icon.svg" type="image/svg+xml">,<link rel="apple-touch-icon" href="/icon.png">6 Route-level smoke test curl per route PASS /-> 200,/about-> 200,/catalog-> 302 (auth redirect),/appointments/new-> 302 (auth redirect),/icon.png-> 200,/icon.svg-> 2007 Visual verification of production site Playwright browser screenshot PASS Landing page loads correctly with proper styling and content. Page title: "Intelligence Staffing Systems -- Enterprise infrastructure for small businesses" Regression Check
No regressions detected. This change only touched
public/icon.pngandpublic/icon.svg(static assets). All other routes continue to function correctly:- Landing page (
/) loads with correct content and styling - About page (
/about) returns 200 - Auth-gated routes (
/catalog,/appointments/new) redirect properly (302) - Pod running with 0 restarts
Discovered Issues
None.
- Landing page (
-
Validation: fix: restore missing project_requests table in schema.rb
validation-103-2026-07-26Verdict: PASS
Ticket
ldraney/intelligentstaffingsystems#103 — Restore the
project_requeststable definition that was accidentally dropped fromdb/schema.rb. Merged via PR #104.Environment
Production cluster, namespace
intelligentstaffingsystems. Pod:intelligentstaffingsystems-69c4f699d6-vp89s. Image:harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:b46c43399b520241eece48595c114501489fc7f7(HEAD of main, includes fix commitd1097ba). ArgoCD: Synced / Healthy. URL:https://intelligentstaffingsystems.ai.Checks
# Criterion How Verified Result Evidence 1 project_requests table present in schema.rb with correct columns (lead_id, business_name, description, target_audience, inspiration, status, timestamps) grep schema.rb for create_table "project_requests" PASS Table found with all expected columns, uuid primary key, indices on lead_id and status 2 Foreign key project_requests → leads exists in schema.rb grep schema.rb for foreign_key "project_requests" PASS add_foreign_key "project_requests", "leads"present at end of schema.rb3 Migration file consistent with schema.rb Read migration 20260717200001_create_project_requests.rb, compared columns PASS Migration creates table with identical columns, indices, and foreign key 4 Tests and fixtures exist for project_requests Located test/models/project_request_test.rb, test/controllers/projects_controller_test.rb, test/fixtures/project_requests.yml PASS Model tests cover validations, associations, scopes, dependent destroy. 3 fixtures defined. Controller tests cover form rendering and submission. 5 Production pod running with fix deployed kubectl get pods -n intelligentstaffingsystems; checked image tag ancestry PASS Pod 1/1 Running, 0 restarts. Image tag b46c433 (HEAD) includes fix commit d1097ba in its git ancestry. 6 ArgoCD sync and health kubectl get application -n argocd intelligentstaffingsystems PASS Synced / Healthy 7 Production endpoints healthy curl -s -w "%{http_code}" for /, /about, /appointments/new PASS / → 200, /about → 200, /appointments/new → 302 (auth redirect to /login, expected) 8 Pod logs clean (no schema errors) kubectl logs --tail=30 PASS Logs show normal request processing. Only noise: /metrics 404 from monitoring probe (pre-existing), PaperTrail deprecation warning (pre-existing). No schema or migration errors. Regression Check
Production root URL, /about, and /appointments/new all respond correctly. Pod has 0 restarts and no crash loops. ArgoCD healthy. No new errors in pod logs.
Discovered Issues
No new issues discovered. Two pre-existing notes:
/metricsendpoint returns 404 — monitoring probe hitting a non-existent route. Pre-existing, not related to this fix.- No Woodpecker pipeline visible for the PR #104 merge commit (d1097ba). Subsequent pipelines built images that include the fix. Related to the known push event gap (see memory: project_push_event_gap.md).
Tier Summary
Tiers executed: Tier 1 (local schema + migration + test file verification), Tier 3 (production pod, ArgoCD, endpoint health). Tier 1 test execution skipped per known Docker test hang issue (#65). Tier 2 skipped (no staging environment).
-
Validation: Fix TLS cert for dev.intelligentstaffingsystems.ai + deploy register.ftl to Keycloak configmap
validation-98-2026-07-18Verdict: PASS
Ticket
ldraney/intelligentstaffingsystems#98 — Fix TLS cert for dev.intelligentstaffingsystems.ai + deploy register.ftl to Keycloak configmap
Merged PRs: ldraney/pal-e-platform#552 (caddy fix + register.ftl), ldraney/pal-e-platform#553 (pipeline git fix)
Environment
Production cluster. Edge proxy at 178.156.129.142 (Caddy via SaltStack). Keycloak namespace on k3s cluster. Domain: dev.intelligentstaffingsystems.ai. Keycloak: keycloak.tail5b443a.ts.net/realms/iss
Checks
# Criterion How Verified Result Evidence 1 TLS cert working for dev.intelligentstaffingsystems.ai (valid cert, no TLS errors) curl -vI https://dev.intelligentstaffingsystems.ai; openssl s_client -servername dev.intelligentstaffingsystems.ai -connect 178.156.129.142:443 PASS TLS handshake succeeds (TLSv1.3 / TLS_AES_128_GCM_SHA256). Valid Let's Encrypt certificate: subject=CN=dev.intelligentstaffingsystems.ai, issuer=C=US O=Let's Encrypt CN=YE2, notBefore=Jul 19 13:11:27 2026 GMT, notAfter=Oct 17 13:11:26 2026 GMT. SAN matches. OpenSSL verify result: 0. Previous failure was "TLS alert, internal error (592)" with no peer certificate — now fully resolved after pipeline #1649 applied the salt highstate with git installed. 2 Registration template deployed: Keycloak registration page renders with phone field and ISS branding kubectl get configmap keycloak-iss-theme -n keycloak -o jsonpath='{.data.register\.ftl}' PASS ConfigMap contains register.ftl with phone field (user.attributes.phone, type=tel), ISS theme (register.css), kc-register-form, firstName/lastName/email/password fields. Confirmed present and unchanged from prior validation. Regression Check
Production domain intelligentstaffingsystems.ai: HTTP 200, TLS working (valid cert, H2). No regressions detected on existing services.
Discovered Issues
HTTP 502 from dev.intelligentstaffingsystems.ai. TLS terminates correctly but Caddy returns 502 Bad Gateway — the upstream backend (dev ISS Rails app) is not reachable. This is NOT a TLS issue and is outside the scope of this ticket. The dev environment backend deployment is tracked separately (the dev Rails pod needs to be running for the full page to load). No new Forgejo issue created as this is expected state — the dev environment backend depends on the kustomize overlay being deployed.
History
2026-07-18: Initial validation — PARTIAL (register.ftl PASS, TLS FAIL due to salt apply silently skipped without git).
2026-07-19: Re-validation after pipeline #1649 succeeded (git installed, salt highstate applied) — TLS PASS. Verdict upgraded to PASS. -
Validation: Tab bar restructure to Catalog / Projects / Communications / Account + CRM
validation-49-2026-07-17Ticket
#49 Tab bar: restructure to Catalog / Projects / Communications / Account + CRM
Environment
Production cluster, namespace
intelligentstaffingsystems, URL:https://intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 CI pipeline green mcp__woodpecker__list_pipelines PASS Pipeline #116 (push to main): SUCCESS 2 Pod healthy kubectl get pods -n intelligentstaffingsystems PASS intelligentstaffingsystems-5ddd4556dd-nbbjd 1/1 Running, 0 restarts, 6h26m 3 ArgoCD synced kubectl get application -n argocd PASS intelligentstaffingsystems: Synced, Healthy 4 /catalog route exists curl https://intelligentstaffingsystems.ai/catalog PASS 302 to /login (auth gate active, route exists) 5 /projects route exists curl https://intelligentstaffingsystems.ai/projects PASS 302 to /login (auth gate active, route exists) 6 /communications route exists curl https://intelligentstaffingsystems.ai/communications PASS 302 to /login (auth gate active, route exists) 7 /account route exists curl https://intelligentstaffingsystems.ai/account PASS 302 to /login (auth gate active, route exists) 8 Invalid route returns 404 curl https://intelligentstaffingsystems.ai/nonexistent PASS 404 (confirms routes are real, not catchalls) 9 Tab CSS assets served curl landing page, check asset fingerprints PASS catalog-18750aed.css, communications-d7ae2212.css, projects-f6b6391a.css, tab_bar-8938008b.css Verdict
PASS — all checks green. Previously failed (2026-07-17) due to deployment blocker #85. Re-validated 2026-07-19 after pod was redeployed and stable. All navigation routes respond correctly behind auth.
Discovered Issues
None.
-
Validation: #85 fix: CI minitest/mock + placeholder k8s secrets
validation-85-2026-07-19Ticket
#85 fix: CI minitest/mock LoadError + placeholder k8s secrets + action_mailer example.com
Environment
Production cluster, namespace
intelligentstaffingsystems, URL:https://intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 CI pipeline green mcp__woodpecker__list_pipelines PASS Pipeline #116 (push to main): SUCCESS 2 Pod healthy kubectl get pods -n intelligentstaffingsystems PASS intelligentstaffingsystems-5ddd4556dd-nbbjd 1/1 Running, 0 restarts, 6h24m 3 Image matches main kubectl get pods -o jsonpath image PASS harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:dc97ba0a matches commit dc97ba0 4 Route returns 200 curl https://intelligentstaffingsystems.ai PASS HTTP 200 in 0.43s, full Rails HTML served 5 ArgoCD synced kubectl get application -n argocd PASS Synced, Healthy Verdict
PASS — all checks green. Pod stable for 6+ hours with zero restarts. All code through #85 fix is deployed and serving.
Discovered Issues
None.
-
Validation: ISS realm config — login_theme + verify_email
validation-184-2026-07-17Verdict: PASS
Ticket
ldraney/pal-e-services#184 — Set
login_theme = "iss"andverify_email = trueon the ISS Keycloak realm, with variable wiring throughvariables.tfandkeycloak.tf.Merged PR: #187 (commit
a64f29a, merged 2026-07-17)Environment
Production k3s cluster (archbox). Keycloak namespace:
keycloak. Pod:keycloak-d78ffb987-7hcpz(1/1 Running, 0 restarts). Terraform workspace:k3svia~/pal-e-services/terraform.Checks
# Criterion How Verified Result Evidence 1 login_theme = "iss"set on ISS realm ink3s.tfvarsgreponk3s.tfvarsline 104PASS login_theme = "iss"confirmed at line 104 inside theiss = {}block (lines 98-115)2 verify_email = trueset on ISS realm ink3s.tfvarsgreponk3s.tfvarsline 103PASS verify_email = trueconfirmed at line 103 inside theiss = {}block3 Keycloak login page renders with ISS theme after apply curlISS login page, inspect HTML for theme resource pathsPASS Login page loads CSS from /resources/.../login/iss/css/login.css, JS from/login/iss/js/, favicon from/login/iss/img/favicon.ico. Title: "Sign in to Intelligence Staffing Systems". Registration link present.4 New registrations receive email verification kcadm get realms/issforverifyEmail+ SMTP configPASS verifyEmail = trueconfirmed in live Keycloak. SMTP configured: Postmark (smtp.postmarkapp.com:587), fromnoreply@intelligentstaffingsystems.ai, STARTTLS enabled, basic auth active.Terraform State
Note:
tofu applyhad not been run after the merge. The CI push pipeline (#234) rantofu plan/validateonly. Applied manually during this validation session.- Pre-apply plan:
keycloak_realm.this["iss"]—+ login_theme = "iss",~ verify_email = false -> true - Apply result:
Apply complete! Resources: 0 added, 3 changed, 0 destroyed. - Post-apply plan: No changes. Your infrastructure matches the configuration.
Regression Check
- Keycloak pod healthy: 1/1 Running, 0 restarts
- All 9 realms enabled and accessible
- Other realm login themes unchanged: westside-basketball=westside, landscaping=landscaping
verify_emaildefaults tofalseinvariables.tf— no impact on existing realms (all showverifyEmail: falseexcept ISS)tofu planclean after apply — no unexpected drift
Discovered Issues
- Local working tree in
~/pal-e-serviceshad uncommitted changes removingverify_emailwiring fromkeycloak.tfandvariables.tf. Pre-existing local state (stashed changes from other work), not a regression. - Woodpecker push pipeline does not run
tofu applyautomatically — apply required manual execution. Known gap per project memory.
- Pre-apply plan:
-
Validation: Catalog tab — app portfolio with App Store links
validation-50-2026-07-17Verdict: FAIL
Ticket
#50 — Catalog tab: app portfolio with App Store links — Adds portfolio description header, App Store link buttons with
data-turbo="false"for external navigation,app_store_urlcolumn and HTTPS validation on CatalogEntry model.Merged PR: #84 (merge commit
9af07ff). CI fix commit:ca24329.Environment
Production cluster, namespace
intelligentstaffingsystems, URLhttps://intelligentstaffingsystems.ai.Running pod image:
harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79b(10 commits behind PR #84 merge). ArgoCD status: Synced / Degraded.Tiers Executed
- Tier 1 (Local — code inspection): Full source review of all changed files. Docker tests skipped per issue #65.
- Tier 3 (Production): kubectl pod status, ArgoCD sync/health, endpoint curl, pipeline status.
Checks
# Criterion How Verified Result Evidence 1 Pipeline green for merge commit Woodpecker pipeline #85 (PR #84 merge) and #90 (CI fix) FAIL Pipeline #85: security + test failed. Pipeline #90: security passed, test failed ( minitest/mockLoadError — systemic gem issue). Build-and-push SKIPPED on both.2 New image tag propagated to pod kubectl get pods -n intelligentstaffingsystemsFAIL Running pod uses image :93b9a79b(commit from before PR #84). No new image was pushed because CI failed.3 Pod running and ready kubectl get pods --all-namespacesPARTIAL Old pod -6d6896dd95-ls9k4is Running (0 restarts, 11h). New pod-8474c67bc8-nxphpis Init:CrashLoopBackOff (13 restarts) due toPLACEHOLDER_POSTGRES_HOSTDB connection error.4 Health endpoint returns 200 curl https://intelligentstaffingsystems.ai/upPASS Returns HTTP 200. Root URL also returns 200. /catalogreturns 302 (redirect to login — expected for unauthenticated).5 Portfolio description at top of catalog page Source: app/views/catalog/index.html.erblines 14-18CODE PASS Header has .catalog-introwith text: "These are real apps we have built and shipped to the App Store... Everything you see here is customizable to your exact needs."6 Description communicates target audience Source: index.html.erbline 17CODE PASS Text mentions "sports program, a local shop, or a service with monthly subscribers" and "the app that runs your business." 7 Cards display with App Store link via app_store_url column Source: _catalog_entry.html.erblines 25-30, migration, modelCODE PASS Migration adds app_store_url:string. Model validates HTTPS format (allow_blank: true). Partial renders.catalog-app-store-linkwhensafe_app_store_url(entry)returns a URL.8 App Store links use data-turbo="false"for external navigationSource: _catalog_entry.html.erbline 26,show.html.erbline 51CODE PASS Both index card partial and show page use data: { turbo: "false" }, target: "_blank", rel: "noopener noreferrer".9 Responsive card grid layout Source: catalog.csslines 114-118, 427-430CODE PASS Mobile: grid-template-columns: 1fr. Desktop (600px+):repeat(2, 1fr).10 All three roles see identical content Source: catalog_controller.rb(no role checks), tests lines 21-37CODE PASS Controller has no role restrictions. Tests verify lead, client, admin all get 200. 11 Detail page shows expanded description, screenshots, tech stack Source: show.html.erbCODE PASS Gallery section, description via simple_format, tech tags in sidebar, App Store link in sidebar.12 Endpoint tests: role access (lead/client/admin 200, signed-out redirect) Source: catalog_controller_test.rbCODE PASS Tests at lines 8-37 cover all four cases. Additional tests for content, App Store links, data-turbo attributes. 13 Model tests: CatalogEntry validations including app_store_url Source: catalog_entry_test.rbCODE PASS Tests at lines 112-137: optional field, blank allowed, HTTPS accepted, non-HTTPS rejected, arbitrary text rejected. Regression Check
- Production root URL returns 200 — existing deployment is healthy.
- The
/uphealth endpoint returns 200. - The currently running pod (old image) has 0 restarts and has been stable for 11 hours.
- No regression in existing deployment, but the NEW deployment attempt is CrashLooping due to database config.
Discovered Issues
- CI test infrastructure broken —
minitest/mockLoadError. Pipeline #90 test step fails withcannot load such file -- minitest/mock (LoadError). This is a systemic issue (not PR #84 specific) that blocks ALL CI pipelines from reaching build-and-push. Theminitest-mockgem needs to be added to Gemfile or the Ruby 3.4 bundled gems configuration needs updating. This blocks deployment of ALL merged changes. - ArgoCD Degraded —
PLACEHOLDER_POSTGRES_HOST. New ReplicaSet pod-8474c67bc8-nxphpcrashes in init container withActiveRecord::DatabaseConnectionError: There is an issue connecting with your hostname: PLACEHOLDER_POSTGRES_HOST. The deployment has a placeholder database host that was never replaced with the real value. This is a kustomize/secrets configuration issue inpal-e-deployments. - Image 10 commits behind. The running image (
:93b9a79b) is from before Sprint B PRs #82, #83, #84, and the CI fix commit. None of the Sprint B features are live in production.
Failure Summary
The code implementation is correct and complete — all acceptance criteria are satisfied at the source level. However, the changes have not been deployed to production because:
- CI pipeline fails at the test step (
minitest/mockLoadError), preventing image build-and-push. - No new image exists in Harbor for commits after
93b9a79. - ArgoCD is degraded due to database connection misconfiguration in the deployment overlay.
Both discovered issues (#1 CI gem fix, #2 deployment secrets) must be resolved before any Sprint B work can be validated in production. The ticket cannot move to done until the changes are confirmed live.
-
Validation: #69 Configure config.hosts (DNS rebinding protection)
validation-69-2026-07-17Verdict: FAIL
Ticket
#69 Configure config.hosts (DNS rebinding protection) — Enable Rails host authorization in production, allowing only
intelligentstaffingsystems.aiandiss.tail5b443a.ts.net, while excluding health checks and k8s IP-based probes.Merged PR: #70 (commit
a8e460a)Board item: #1866 on board-iss
Environment
Prod cluster:
archbox(k3s), namespaceintelligentstaffingsystemsRunning pod:
intelligentstaffingsystems-6d6896dd95-ls9k4— Running, 0 restarts, 11h uptimeCrash-looping pod:
intelligentstaffingsystems-8474c67bc8-nxphp— Init:CrashLoopBackOff, 13 restarts, 44m —PLACEHOLDER_POSTGRES_HOSTArgoCD: Synced / Degraded
Running image:
harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79b(commit93b9a79— 3 commits BEFORE PR #70 merge)Tiers Executed
Tier 1 (local): Skipped — Docker tests hang per known gap (#65).
Tier 3 (production): Executed — change not deployed, cannot validate acceptance criteria in production.Checks
# Criterion How Verified Result Evidence 1 Woodpecker pipeline green for merge commit Woodpecker pipeline list (all main branch pipelines) FAIL All pipelines since image 93b9a79are failing. Latest pipeline #90 fails atteststep:cannot load such file -- minitest/mock (LoadError).build-and-pushstep skipped. Previous validation saw messaging test failures; now the failure is a missing gem dependency.2 New image deployed to prod pod kubectl get pods -n intelligentstaffingsystems -o jsonpath=imageFAIL Running image tag 93b9a79bis 3 commits behind merge commita8e460a. No image was pushed because CI test step failed.3 Pod running and ready kubectl get pods -n intelligentstaffingsystemsPARTIAL One pod running (0 restarts). Second pod in Init:CrashLoopBackOff(13 restarts) withActiveRecord::DatabaseConnectionError: PLACEHOLDER_POSTGRES_HOST. ArgoCD: Synced / Degraded.4 Code correct at HEAD: config.hosts includes intelligentstaffingsystems.ai grep config.hosts config/environments/production.rbPASS config.hosts << "intelligentstaffingsystems.ai"present at line 875 Code correct at HEAD: config.hosts includes iss.tail5b443a.ts.net grep config.hosts config/environments/production.rbPASS config.hosts << "iss.tail5b443a.ts.net"present at line 886 Code correct at HEAD: health check /up excluded from host auth Read production.rb lines 90-94 PASS request.path == "/up"in host_authorization exclude lambda7 Code correct at HEAD: IP-based probes excluded Read production.rb lines 90-94 PASS Proper 0-255 octet IPv4 regex in host_authorization exclude lambda 8 Route smoke: / returns 200 curl https://intelligentstaffingsystems.ai/PASS HTTP 200, HTML with correct title "Intelligence Staffing Systems" 9 Route smoke: /up returns 200 curl https://intelligentstaffingsystems.ai/upPASS HTTP 200 10 DNS rebinding protection active in production curl -H "Host: evil.example.com" https://intelligentstaffingsystems.ai/FAIL Returns HTTP 200 instead of expected 403. Expected: running image does not include config.hosts changes (confirms check #2). Regression Check
Current production deployment (pre-PR #70 image) is healthy. Root page loads correctly. Health endpoint responds. No regressions from the running deployment. The config.hosts change cannot cause regressions since it is not yet deployed.
Discovered Issues
- BLOCKER: CI test step broken — minitest/mock LoadError. All Woodpecker pipelines fail at the
teststep withcannot load such file -- minitest/mock (LoadError). Thebuild-and-pushstep is skipped, so no new images are being built. This blocks deployment of PR #70 and all subsequent merges. The failure cause has evolved since the first validation attempt (was messaging test failures, now a gem dependency issue). - Crash-looping pod with PLACEHOLDER_POSTGRES_HOST. Pod
intelligentstaffingsystems-8474c67bc8-nxphpis inInit:CrashLoopBackOffwithActiveRecord::DatabaseConnectionError: PLACEHOLDER_POSTGRES_HOST. A deployment revision was created without proper database environment variables. This causes ArgoCD to report Degraded health. - Tailscale URL not responding.
https://iss.tail5b443a.ts.net/upreturns connection failure (curl exit code 6, HTTP 000). The Tailscale hostname may not be routed or funneled.
Validation History
2026-07-17 (rev 1): PARTIAL — CI blocked by messaging test failures. Code correct at HEAD. Image not deployed.
2026-07-17 (rev 2): FAIL — CI failure evolved to minitest/mock LoadError. New crash-looping pod discovered. ArgoCD now Degraded (was Healthy). Upgraded to FAIL because the deployment situation has worsened with no path to resolution without CI fix. - BLOCKER: CI test step broken — minitest/mock LoadError. All Woodpecker pipelines fail at the
-
Validation: In-app registration with Keycloak phone field and Lead sync
validation-59-2026-07-17Verdict: FAIL
Re-validated 2026-07-17. Previous validation also FAIL; root cause has shifted from messaging test failures (now fixed by PR #76) to minitest/mock infrastructure issue and secret placeholder values.
Ticket
ldraney/intelligentstaffingsystems#59 — In-app registration: post-Keycloak flow, phone validation, LeadsController reconciliation. Merged via PR #72 (commit
dfe3b8d). Board item #1831 on board-iss.Environment
Production cluster, namespace
intelligentstaffingsystems. URL:https://intelligentstaffingsystems.ai. ArgoCD application:intelligentstaffingsystems(Synced / Degraded). Keycloak realm:issathttps://keycloak.tail5b443a.ts.net/realms/iss.Two pods in namespace:
intelligentstaffingsystems-6d6896dd95-ls9k4— Running, 1/1, 0 restarts, 11h. Serving traffic on old image.intelligentstaffingsystems-8474c67bc8-nxphp— Init:CrashLoopBackOff, 0/1, 13 restarts, 42m. New ReplicaSet failing to start.
Tiers Executed
Tier 1 (local tests) — blocked, CI test step broken. Tier 3 (production) — executed, image not updated.
Checks
# Criterion How Verified Result Evidence 1 Woodpecker pipeline green for merge commit mcp__woodpecker__get_pipeline_status (pipeline #90, latest push to main) FAIL Pipeline #90: clone OK, database OK, bundle-install OK, lint OK, security OK, test FAIL (exit 1), build-and-push SKIPPED. Error: cannot load such file -- minitest/mock (LoadError)fromtest/test_helper.rb:4. Ruby 3.4 moved minitest/mock out of stdlib into bundled_gems. All pipelines since #19 have failed; no new image has been pushed to Harbor.2 New image tag propagated to pods kubectl get pods -n intelligentstaffingsystems -o jsonpath='{.items[*].spec.containers[*].image}'FAIL Both pods running image harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79b8a88cbb07a7f8fda1b6d85803580cbbb. This corresponds to commit93b9a79("fix: align pipeline push repo with Argo CD Image Updater annotation"), which is many commits behind PR #72's merge atdfe3b8d. No new image was ever built because build-and-push is always skipped.3 Pod running and ready, restarts = 0 kubectl get pods -n intelligentstaffingsystems+kubectl describe podFAIL Old pod (ReplicaSet 6d6896dd95): Running, 0 restarts — healthy but on pre-PR-#72 code. New pod (ReplicaSet8474c67bc8):Init:CrashLoopBackOff, 13 restarts. Init containermigratefails:ActiveRecord::DatabaseConnectionError: There is an issue connecting with your hostname: PLACEHOLDER_POSTGRES_HOST. The Kubernetes secretintelligentstaffingsystems-secretscontains placeholder values.4 Smoke test: health endpoint returns 200 curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/upPASS (stale) Both /and/upreturn HTTP 200. However, this is the old deployment serving on pre-PR-#72 code. The registration feature is NOT present.5 Post-Keycloak registration flow (SessionsController 3-path resolve_lead with phone) Cannot verify — code not deployed FAIL PR #72 added extract_phone,sync_phone, and 3-pathresolve_lead(by sub, by email claim, walk-in) to SessionsController. Code is in the repo at commitdfe3b8dbut not in the running container image (93b9a79).6 Phone validation (Lead::PHONE_FORMAT) on Lead model Cannot verify — code not deployed FAIL PHONE_FORMAT = /\A\+?[\d\s\-\(\)\.]{7,20}\z/regex and format validation exist in source but not in running image.7 Keycloak register.ftl theme with phone field Keycloak theme deployment is separate ticket (platform#541, board #1865) N/A The register.ftlandregister.cssfiles are in the repo. Their deployment to Keycloak is tracked by platform#541 (done) and svc#184 (#1864, in validation). This ticket covers only Rails-side wiring.8 Backfill migration (phone placeholders for existing leads) Cannot verify — migration never ran in production FAIL Migration 20260717100000_backfill_lead_phone_placeholders.rbexists in source but the image containing it was never deployed. The new pod's migrate init container crashes before reaching this migration (PLACEHOLDER_POSTGRES_HOST).Regression Check
The existing site at
intelligentstaffingsystems.aireturns HTTP 200 at/and/up. No regression from the merge — the old deployment continues serving. However, ArgoCD health isDegradeddue to the new pod's CrashLoopBackOff, indicating a deployment configuration problem independent of the code change.Root Cause
Two independent blockers prevent PR #72's code from reaching production:
- CI test runner broken (minitest/mock LoadError): Ruby 3.4's
bundled_gemschange movedminitest/mockout of the standard library.test/test_helper.rb:4doesrequire 'minitest/mock'which fails. The original messaging test failures (from the first validation) were fixed by PR #76, but this new infrastructure issue now blocks all pipelines. Theteststep exits 1, causingbuild-and-pushto be skipped. No new image has been pushed since commit93b9a79. - Kubernetes secret has placeholder values: The new ReplicaSet's init container
migratefails becausePOSTGRES_HOSTin secretintelligentstaffingsystems-secretsis set toPLACEHOLDER_POSTGRES_HOST. Even if a new image were built, it could not deploy until the secret is corrected.
Discovered Issues
- BLOCKER: minitest/mock LoadError in CI. All Woodpecker pipelines fail at the test step.
require 'minitest/mock'is no longer available in Ruby 3.4 without an explicit gem dependency. Fix: addgem "minitest"(with version that includes mock) to Gemfile, or adjust test_helper to not require minitest/mock if it's not needed. This blocks ALL ISS deployments. - BLOCKER: PLACEHOLDER_POSTGRES_HOST in prod secrets. The Kubernetes secret
intelligentstaffingsystems-secretshas a placeholder for POSTGRES_HOST. Any new pod (even on the same image) will fail to start. The old running pod predates this secret change. - ArgoCD Degraded health. Application shows Synced/Degraded. The CrashLoopBackOff pod from the new ReplicaSet is the cause.
-
Validation: Communications tab (lead/client): contact methods
validation-52-2026-07-17Verdict: FAIL
Ticket
#52 Communications tab (lead/client): contact methods — Role-branched contact methods tab with DM, Email, and Appointment cards. Lead sees locked DM; client sees active DM link. Admin sees incoming management placeholder.
Merged PR: #82 (commit
4656364)Board item: #1822 on board-iss
Environment
Production cluster, namespace
intelligentstaffingsystems, URLhttps://intelligentstaffingsystems.aiArgoCD application:
intelligentstaffingsystems— Synced / DegradedTiers Executed
Tier 1 (local/CI review) + Tier 3 (production). Per
arch:railslabel mapping.Checks
# Criterion How Verified Result Evidence 1 CI pipeline green for merge commit Woodpecker pipeline #78 (push event for PR #82 merge) FAIL Pipeline #78: clone success, all other steps skipped. Pipeline #90 (latest main push): test step fails with cannot load such file -- minitest/mock (LoadError), build-and-push skipped.2 New image tag propagated to pod kubectl get pods -o jsonpathfor image tagsFAIL Running pod image: 93b9a79b8a88cbb07a7f8fda1b6d85803580cbbb= commit93b9a79("fix: align pipeline push repo with Argo CD Image Updater annotation"), which predates the Communications tab merge at commit4656364. No new image was built because CI test step fails.3 Pod running and ready, restarts = 0 kubectl get pods -n intelligentstaffingsystemsPARTIAL Old pod 6d6896dd95-ls9k4: 1/1 Running, 0 restarts, 11h. New pod8474c67bc8-nxphp: 0/1 Init:CrashLoopBackOff — init containermigratefails withPLACEHOLDER_POSTGRES_HOST. ArgoCD reports Degraded.4 /communications route returns 200 curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/communicationsFAIL Returns HTTP 404. The running pod is on the pre-Communications-tab image; the route does not exist in that version. 5 Production root URL healthy curl https://intelligentstaffingsystems.aiPASS Returns HTTP 200. The old pod is still serving the landing page. 6 Lead sees 3 contact cards (DM locked, Email, Appointment) Cannot verify — code not deployed FAIL N/A — /communications returns 404 7 Client sees 3 contact cards with active DM link Cannot verify — code not deployed FAIL N/A — /communications returns 404 8 Admin sees incoming management view Cannot verify — code not deployed FAIL N/A — /communications returns 404 Regression Check
Production root URL (
https://intelligentstaffingsystems.ai) still returns 200. The old pod continues to serve existing functionality. No regression from the merge itself — the new code simply has not deployed.However, a separate issue exists: a new replica set pod is crash-looping due to
PLACEHOLDER_POSTGRES_HOSTin the deployment config (init containermigratecannot connect to database). This is a deployment configuration problem independent of the Communications tab code.Discovered Issues
- CI pipeline broken — minitest/mock LoadError. Pipeline #90 (latest push to main) fails at the test step because
minitest/mockcannot be loaded. This blocks all image builds. Theminitest-mockgem may need to be added to the Gemfile or the CI base image updated. This is the primary blocker preventing deployment of any merged code. - CrashLoopBackOff pod with PLACEHOLDER_POSTGRES_HOST. Pod
intelligentstaffingsystems-8474c67bc8-nxphphas a deployment config referencingPLACEHOLDER_POSTGRES_HOSTinstead of the real database host. This appears to be a kustomize overlay or secret configuration issue in pal-e-deployments. - Dev environment unreachable.
dev.intelligentstaffingsystems.aireturns connection refused (HTTP 000). ArgoCD appintelligentstaffingsystems-devnot found. Dev overlay may not be deployed yet.
Code Review (supplementary)
Although production validation fails, the merged code appears correctly implemented based on local review:
CommunicationsControllerhas role branching (admin vs lead/client) with correct helpers_contact_cards.html.erbrenders 3 cards: DM (locked/active based on role), Email (clipboard Stimulus controller), Appointment (links to booking_path)communications.cssprovides dedicated styling (144 lines)- Route defined at
GET /communicationsinconfig/routes.rb - 16 controller tests cover authentication, role branching, card rendering, and Stimulus attributes
clipboard_controller.jsStimulus controller for email copy functionality
Blockers to Re-validation
- Fix the
minitest/mockLoadError in CI (add gem to Gemfile or update base image) - Trigger a successful pipeline build to push a new image to Harbor
- Verify ArgoCD Image Updater picks up the new tag
- Fix the
PLACEHOLDER_POSTGRES_HOSTin the deployment config (separate from this ticket) - Re-run this validation once the new image is live
- CI pipeline broken — minitest/mock LoadError. Pipeline #90 (latest push to main) fails at the test step because
-
Validation: Deploy ISS Keycloak login theme
validation-541-2026-07-17Verdict: PASS
Ticket
platform#541 (board item #1865 on board-iss) — Deploy ISS Keycloak login theme via ConfigMap + volume mount. Navy + gold branded login theme files deployed to the Keycloak pod following the existing landscaping/paldocs/westside pattern.
Merged PR: #542
Environment
Production cluster (archbox), namespace:
keycloak, pod:keycloak-d78ffb987-7hcpz. Keycloak exposed via Tailscale funnel atkeycloak.tail5b443a.ts.net.Checks
# Criterion How Verified Result Evidence 1 Theme files copied to designated directory kubectl exec ls /opt/keycloak/themes/iss/login/PASS Directory contains resources/(symlink) andtheme.properties(symlink). Subdirsresources/css/login.css(12151 bytes) andresources/img/logo.svg(581 bytes) present.2 ConfigMap created in Terraform configuration kubectl get configmap -n keycloakPASS keycloak-iss-themeConfigMap exists with 3 data keys:login.css,logo.svg,theme.properties.3 Volume mount configured for Keycloak pod kubectl get pod -o jsonpath volumeMountsPASS Volume iss-thememounted at/opt/keycloak/themes/iss/login.4 Theme accessible at /opt/keycloak/themes/iss/ post-deployment kubectl exec ls + cat theme.propertiesPASS theme.propertiesreads:parent=keycloak,import=common/keycloak,styles=css/login.css. CSS contains ISS brand tokens (navy#1b2a4a, gold#996d13).5 Existing landscaping theme deployment remains unchanged kubectl get configmap + kubectl exec lsPASS keycloak-landscaping-themeConfigMap exists (2 data keys). Theme files at/opt/keycloak/themes/landscaping/login/intact withtheme.propertiesandresources/css/login.css.Tier Results
Tier Result Evidence Tier 1 (CI) PASS Woodpecker pipeline #1514 (push to main) — all steps green including apply. PR pipeline #1507 also green.Tier 2 (Staging) N/A No staging environment for pal-e-platform. Tier 3 (Prod) PASS Keycloak pod keycloak-d78ffb987-7hcpz: Running, 1/1 Ready, 0 restarts. ConfigMap, volume mount, and theme files all verified in-cluster. All 4 themes present: iss, landscaping, paldocs, westside.Regression Check
- Landscaping theme: ConfigMap present (2 keys), files intact in pod,
theme.propertiescorrect. - Westside theme:
resources/css/westside.csspresent in pod. - Paldocs theme:
resources/css/login.csspresent in pod. - Keycloak pod: 0 restarts, Running status, no CrashLoopBackOff.
- Keycloak service responding (302 on auth endpoints for both ISS and landscaping realms).
- Note: ISS realm login page currently renders default Keycloak theme — expected, as realm-level
login_themeconfiguration is handled by companion ticket svc#184 (board item #1864).
Discovered Issues
None. All checks passed cleanly. The theme deployment is complete and ready for realm-level activation by svc#184.
- Landscaping theme: ConfigMap present (2 keys), files intact in pod,
-
Validation: #42 Turbo Streams Live Delivery + Solid Cable
validation-42-2026-07-17Ticket
#42 Turbo Streams live delivery + cable fix
Board item: #1818 on board-iss. PR #66 (squash merge).
Environment
Prod cluster (k3s), namespace
intelligentstaffingsystems, verified via kubectl and curl.Checks
# Criterion How to Verify Result Evidence 1 Turbo Streams broadcasting wired Code review on main PASS broadcasts_to :leadin Message model;turbo_stream_from @leadin thread view2 Solid Cable configured Code review on main PASS production adapter is solid_cable; migration at db/cable_migrate/; cable: database in database.yml 3 Stimulus controllers present Code review on main PASS messages-thread (auto-scroll, broadcast alignment) and messages-form (textarea resize, Enter-to-send) 4 JS foundation bootstrapped Code review on main PASS importmap-rails configured; application.js imports turbo-rails and controllers 5 Security: opaque_sub Code review on main PASS Raw Keycloak subs never exposed in DOM; hashed via opaque_sub helper 6 Docs updated Code review on main PASS docs/messaging.md has live delivery architecture section 7 App deployed and running kubectl get deployment -n intelligentstaffingsystemsPASS Pod running with image harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79...which includes PR #668 Site accessible curl -s -o /dev/null -w '%{http_code}' https://intelligentstaffingsystems.ai/loginPASS HTTP 200 Verdict
PASS — all checks green. 18 files verified on main, deployed to production, site accessible.
Known Issue
Two test assertions compare raw Keycloak subs but views render opaque hashes. Production code is correct; test assertions need updating. Masked by PG17 local test blocker (#65) and squash-merge CI push-event gap.
Discovered Issues
Test assertion fix needed (minor, non-blocking).
-
Validation: ISS deployment overlay image name fix (pal-e-deployments#231)
validation-231-2026-07-17Ticket
pal-e-deployments#231 — Fix ISS deployment overlay: image name mismatch blocks auto-rollout
Board item: #1858 on board-iss
Environment
Prod cluster (k3s), namespace
intelligentstaffingsystems, site atintelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 Kustomization overlay references correct image path PR #232 diff review PASS Changed from intelligentstaffingsystems/intelligentstaffingsystemstointelligentstaffingsystems/app2 Deployment running correct image kubectl get deployment -n intelligentstaffingsystems -o jsonpath='{.items[*].spec.template.spec.containers[*].image}'PASS harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79b8a88cbb07a7f8fda1b6d85803580cbbb3 Site accessible curl -s -o /dev/null -w '%{http_code}' https://intelligentstaffingsystems.ai/PASS HTTP 200 4 Complementary ISS-side fix on main git log --onelinePASS Commit 93b9a79on main: "fix: align pipeline push repo with Argo CD Image Updater annotation"Verdict
PASS — all checks green. Image path aligned across pipeline, kustomization, and running deployment.
Discovered Issues
None.
-
Validation: Activate Woodpecker CI for ISS repo
validation-47-2026-07-17Verdict: PASS
Ticket
ldraney/intelligentstaffingsystems#47 — Activate Woodpecker CI for the ISS repo. CI activation was done via Woodpecker UI (no code PR). The
.woodpecker.yamlpipeline config was added as part of the initial bootstrap PR #31.Environment
Woodpecker CI at Forgejo instance
forgejo.tail5b443a.ts.net. Production cluster namespaceintelligentstaffingsystems. Harbor registry atharbor.tail5b443a.ts.net. ArgoCD managed deployment.Checks
# Criterion How Verified Result Evidence 1 Repo is activated in Woodpecker mcp__woodpecker__list_repos+get_repoPASS Repo id 48, ldraney/intelligentstaffingsystems,active: true, default_branch: main, allow_pull_requests: true2 Pipeline config exists in repo Read .woodpecker.yamlPASS Config present with 5 steps: bundle-install, lint (rubocop), security (brakeman), test (rails test), build-and-push (kaniko to Harbor). Events: push, pull_request, manual. Build-and-push gated to push on main only. 3 Push events on main trigger pipelines mcp__woodpecker__list_pipelines+get_pipeline_statusPASS Pipeline #19 (push, main): success — all 7 steps green (clone, database, bundle-install, lint, security, test, build-and-push). Pipeline #18 (push, main): success — all 7 steps green. 4 Pull request events trigger pipelines get_pipeline_statusfor PR pipelinesPASS Pipeline #16 (pull_request): success — 6 steps green (clone, database, bundle-install, lint, security, test). Build-and-push correctly skipped (PR, not main push). Pipeline #10 (pull_request): success. 5 Build-and-push produces deployable image kubectl get pods -o jsonpath imagePASS Pod running image harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:93b9a79b8a88cbb07a7f8fda1b6d85803580cbbb. Tag matches latest commit93b9a79.6 Full CI/CD loop completes (CI → Harbor → ArgoCD → pod) kubectl get application+kubectl get podsPASS ArgoCD sync: Synced. ArgoCD health: Healthy. Pod: 1/1 Running, 0 restarts. Regression Check
ArgoCD reports Synced + Healthy for the ISS application. Pod running with 0 restarts. 19 pipelines have executed across push, pull_request, and feature branch events — demonstrating sustained CI health, not just initial activation. Most recent two main-branch pipelines (#18, #19) both fully green.
Discovered Issues
None. Pipeline image repo mismatch (pushed to
intelligentstaffingsystems/intelligentstaffingsystemsinstead ofintelligentstaffingsystems/app) was already fixed in commit93b9a79(pipeline #19). No new issues found during validation. -
Validation: godaddy-tofu#39 Example app-domain modules (custom domain to edge)
validation-godaddy-39-2026-07-17Ticket
godaddy-tofu#39 — Board item 1799. GoDaddy provider + domain example modules for custom domain wiring.
Environment
Production: intelligentstaffingsystems.ai serving via Hetzner edge → Caddy → Tailscale → k3s
Checks
# Criterion How to Verify Result Evidence 1 Domain resolves and serves curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/PASS 200 OK 2 godaddy-tofu repo accessible curl https://forgejo.tail5b443a.ts.net/ldraney/godaddy-tofuPASS 200 OK 3 Health check endpoint curl https://intelligentstaffingsystems.ai/upPASS 200 OK Verdict
PASS — domain wired end-to-end, site live and healthy.
Discovered Issues
None.
-
Validation: #63 Consolidate CSS tokens and fix ror-css-guide violations
validation-63-2026-07-17Ticket
#63 — Board item 1857. CSS token consolidation and ror-css-guide compliance.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems. Domain: intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 Deployed with latest commit kubectl get pods -o jsonpath image tagPASS Image: harbor...intelligentstaffingsystems:96567f7 — matches merge commit for #63 2 All routes healthy curl all 12 defined routes PASS Public: 200 (/, /leads/new, /booking, /up, /login). Auth: 302 (/catalog, /messages, /profile, /dashboard, /admin/catalog) 3 Pipeline green Woodpecker pipeline #18 + #19 PASS Both success on main 4 ArgoCD healthy ArgoCD application status PASS Synced Healthy Verdict
PASS
Discovered Issues
None.
-
Validation: #48 UI/UX design doc + user stories rewrite
validation-48-2026-07-17Ticket
#48 — Board item 1828. UI/UX design doc + user stories rewrite with new tab architecture.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems.Checks
# Criterion How to Verify Result Evidence 1 docs/user-stories.md updated on main ls docs/user-stories.mdPASS File present with updated content 2 Pipeline green Woodpecker pipeline #18 (merge commit for #48/#62) PASS Pipeline #18 status: success 3 App deployed with changes kubectl get pods -n intelligentstaffingsystemsPASS Pod 1/1 Running, 0 restarts Verdict
PASS
Discovered Issues
None.
-
Validation: #40 Message CRUD (decomp:1792)
validation-40-2026-07-17Ticket
#40 — Board item 1817. Message model, controller, and conversation thread views.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems. Domain: intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 /messages route responds curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/messagesPASS 302 (auth-gated redirect to login) 2 Pod healthy kubectl get pods -n intelligentstaffingsystemsPASS Pod 1/1 Running, 0 restarts. Image: 96567f7 3 Pipeline green Woodpecker pipeline #19 PASS success 4 ArgoCD healthy ArgoCD application status PASS Synced Healthy Verdict
PASS
Discovered Issues
None.
-
Validation: #39 Public catalog browsing UI (decomp:1791)
validation-39-2026-07-17Ticket
#39 — Board item 1815. Public catalog browsing UI grouped by pillar.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems. Domain: intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 /catalog route responds curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/catalogPASS 302 (auth-gated redirect to login) 2 Pod healthy kubectl get pods -n intelligentstaffingsystemsPASS Pod 1/1 Running, 0 restarts 3 Pipeline green Woodpecker pipeline #19 PASS success 4 ArgoCD healthy ArgoCD application status PASS Synced Healthy Verdict
PASS
Discovered Issues
None.
-
Validation: ios#1 Scaffold Turbo Native shell + Fastlane
validation-ios-1-2026-07-17Ticket
ios#1 — Board item 1798. Scaffold Turbo Native iOS shell with Fastlane for App Store prep.
Environment
Forgejo: ldraney/intelligentstaffingsystems-ios (private repo)
Checks
# Criterion How to Verify Result Evidence 1 iOS repo exists mcp__forgejo__get_repo(owner=ldraney, repo=intelligentstaffingsystems-ios)PASS Repo exists, private, default branch main. Description: "Turbo Native iOS shell for ISS" 2 Rails backend accessible for iOS to load curl https://intelligentstaffingsystems.ai/PASS 200 OK — the Rails app the iOS shell connects to is live Verdict
PASS — repo scaffolded, QA-approved per project page. TestFlight pending first MacBook build (not a blocker for this ticket).
Discovered Issues
None.
-
Validation: #13 Profile view, edit, and logout
validation-13-2026-07-17Ticket
#13 — Board item 1793. Profile show/edit/update + logout for all authenticated roles.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems. Domain: intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 /profile route responds curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/profilePASS 302 (redirects to login — correct for unauthenticated) 2 /profile/edit route responds curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/profile/editPASS 302 (auth-gated redirect) 3 Pod healthy kubectl get pods -n intelligentstaffingsystemsPASS Pod 1/1 Running, 0 restarts. Image: 96567f7 4 Pipeline green Woodpecker pipeline #19 PASS Pipeline #19 status: success 5 ArgoCD healthy kubectl get application -n argocd intelligentstaffingsystemsPASS Synced Healthy Verdict
PASS — routes respond correctly, deployment healthy.
Discovered Issues
None.
-
Validation: #21 docs/pipeline.md (decomp:1800)
validation-21-2026-07-17Ticket
#21 — Board item 1804. Added docs/pipeline.md covering the dev-to-App-Store lifecycle.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems.Checks
# Criterion How to Verify Result Evidence 1 docs/pipeline.md exists on main ls docs/pipeline.mdPASS File present in working tree on main 2 Pipeline green Woodpecker pipeline #19 PASS Pipeline #19 status: success 3 App deployed kubectl get pods -n intelligentstaffingsystemsPASS Pod 1/1 Running, 0 restarts Verdict
PASS
Discovered Issues
None.
-
Validation: #1 Add CLAUDE.md symlink, docs/ TOC, user stories, and architecture
validation-1-2026-07-17Ticket
#1 — Board item 1780. Added CLAUDE.md symlink, docs/ directory with TOC, user-stories.md, and architecture.md.
Environment
Prod cluster (k3s archbox), namespace
intelligentstaffingsystems. Domain: intelligentstaffingsystems.aiChecks
# Criterion How to Verify Result Evidence 1 CLAUDE.md exists on main ls CLAUDE.mdPASS File present in working tree on main 2 docs/user-stories.md exists ls docs/user-stories.mdPASS File present 3 docs/architecture.md exists ls docs/architecture.mdPASS File present 4 App deployed and healthy kubectl get pods -n intelligentstaffingsystemsPASS Pod 1/1 Running, 0 restarts. ArgoCD: Synced Healthy 5 Pipeline green Woodpecker pipeline #19 PASS Pipeline #19 status: success (main branch) Verdict
PASS — all docs files present on main, app deployed and healthy.
Discovered Issues
None.
Project Page 1
-
Project: Intelligence Staffing Systems
project-issVision
Consulting business app for intelligentstaffingsystems.ai: a public landing page plus a client management app shipped to the App Store via Turbo Native. The app IS the sales proof — prospects book, register, and communicate through the exact pipeline they would be buying. $800/month after an approved first-month build. OWN your operations, software, and data.
User Stories
Authoritative story detail lives in the repo:
docs/user-stories.md(6 epics, acceptance criteria, role-tab matrix). Story keys used on board items:Key Backing (repo doc) Role Success metric project-setup README + docs/architecture.md + docs/adoption-plan.md Developer Repo, docs, infra, and CI exist; sprints can dispatch landing-page Epic 1 (US-1.1) Visitor Landing page renders publicly, mobile-first registration Epic 1 (US-1.2–1.4) Visitor/Lead Form → Lead record → booking → email with App Store link auth Epic 2 (US-2.1) + architecture.md Lead↔Keycloak linking Lead/Client Keycloak login works; roles gate tabs; Lead claimed by email dashboard Epic 2 (US-2.2) Lead "Hi, {first_name}" dashboard after login navigation Epic 2 + role-tab matrix All roles Bottom tab bar with role-correct tabs catalog Epic 3 (US-3.1–3.2) Lead/Client Browse portfolio by three pillars; admin CRUD messaging Epic 4 (US-4.1–4.2) Lead/Client/Admin One thread per lead; admin sees all communications docs/ui-ux.md (Communications tab layouts) + docs/messaging.md Lead/Client/Admin Lead/client: email + appointment + DM card; admin: incoming inbox with DM and appointment streams crm docs/ui-ux.md (CRM tab layout) + Epic 6 (US-6.1–6.2) Admin Business pipeline with search, role filter, lead→client promotion with audit trail profile Epic 5 (US-5.1) All roles Profile edit syncs Rails + Keycloak; logout ends SSO admin Epic 6 (US-6.1–6.2) Admin Pipeline list; lead→client promotion with audit ios-app docs/ios.md Lead/Client App Store app loads the Rails app; rebuilds almost never android-app docs/ios.md (same Turbo Native model) Lead/Client Play Store app loads the Rails app; same update model as iOS domains godaddy-tofu examples (PR #40) Platform operator New domain = tfvars edit; DNS → Hetzner edge → k3s ui-ux docs/ui-ux.md All roles Design doc + tab architecture established as single source of truth dev-environment #192 / #193 / #194 + docs/pipeline.md Developer Dev → staging → prod pipeline: dev auto-deploys via ArgoCD, staging on merge, prod on manual promotion Architecture
Authoritative: repo
docs/architecture.md. Key decisions:- Rails 8 full-stack monolith (Hotwire, no SPA), Turbo Native iOS shell (config, not code)
- Keycloak realm
iss, roles admin/lead/client; roles authoritative in Keycloak, Lead.role is display mirror - Lead record exists pre-auth; claimed on first login by case-insensitive email match; walk-in fallback creates Lead from token
- Postmark for all transactional email (postmark-email project owns account/domain/server IaC)
- Custom domain via GoDaddy DNS → Hetzner edge (Caddy) → Tailscale → k3s; port 3000 prod, 9999 local dev
- Keycloak architecture documented in
docs/keycloak.md— theme deployment path, domain routing (current Tailscale + planned auth.palinks.app), cross-repo dependency map
Board
board-iss — sub-boards: board-1800-decomp (docs adoption decomposition)
Status
- Repo live with docs foundation on main (README TOC, user-stories, architecture, ios, adoption-plan)
- iOS companion repo scaffolded and QA-approved (TestFlight pending first MacBook build)
- godaddy-tofu example modules merged; intelligentstaffingsystems.ai DKIM-verified in Postmark
- Sprint 0 (docs gate) complete — all Tier 1 docs merged
- Sprint 1 complete — all 4 tickets merged: #3 Rails bootstrap (PR #31), #17 Keycloak theme (PR #30), #4 pal-e-services registration (PR #178), #5 deployment overlay (PR #228). All in validation.
- Sprint 2 complete — all 3 tickets merged: #8 Lead model (PR #33), #6 Keycloak OIDC auth (PR #34), #7 Landing page (PR #32). All in validation.
- Sprint 3 complete — all 3 tickets merged: #9 Dashboard (PR #35), #10 Tab bar (PR #36), #13 Profile (PR #37). All in validation.
- Sprint 4 complete — #11 decomposed (#38/#39/#41 merged), #12 decomposed (#40 merged, #42 Turbo Streams merged via PR #66). #42 in validation.
- Domain wired to production — pal-e-platform PR #534 merged: DNS A + www CNAME → Hetzner edge, Caddy vhost added, Salt highstate pipeline created. intelligentstaffingsystems.ai now serves the live Rails app.
- UX redesign docs merged — #48 UI/UX design doc + user stories rewrite (PR #62). New tab architecture (Catalog/Projects/Communications/Account + CRM for admin), new client journey (landing → App Store → in-app registration), Sprint A–D delivery plan with 13 new tickets (#48–#60).
- Live messaging shipped — #42 Turbo Streams + Solid Cable (PR #66). Real-time message delivery via Action Cable, Stimulus controllers for auto-scroll and alignment, importmap + Turbo + Stimulus JS foundation. No Redis dependency (Solid Cable).
- Keycloak architecture documented — #67 docs/keycloak.md (PR #68). Auth flow diagrams, domain routing (Tailscale current, auth.palinks.app planned), theme deployment path across repos, cross-repo dependency map. Gaps identified: theme not deployed to pal-e-platform, login_theme not set, config.hosts commented out.
- Sprint A scope refined — deprecated old sprint 5/6 tickets (#14/#15/#16/#18). Registration decomposed: #59 (Rails + register.ftl, 8pts), svc#184 (login_theme + verify_email, 2pts), platform#541 (theme ConfigMap deploy, 3pts), #69 (config.hosts, 1pt). Dependency chain: platform#541 → svc#184 → #59.
- Sprint A executed — all 6 tickets merged in parallel (2026-07-17). platform#541 done. #49 (PR #73), #58 (PR #74), #59 (PR #72), #69 (PR #70), svc#184 (PR #187) in validation. CI blocker #75 (Messages test failures from Turbo Streams merge) fixed by PR #76 — pipeline unblocked, ~6 commits deploying.
- Sprint B complete — all 6 tickets merged (2026-07-17). #50 Catalog App Store links (PR #84), #51 Projects tab (PR #83), #52 Communications tab (PR #82), #80 Makefile + docs (PR #81) merged in ISS repo. #78 Kustomize overlays (PR #234 in pal-e-deployments), #79 DNS + Caddy dev subdomain (PR #543 in pal-e-platform) merged. All 6 in validation.
- Sprint C: Dev environment (PR #94, merged 2026-07-18) — #86 dev environment: shared Keycloak env vars (.env.development.example), ephemeral DB (make reset), dev URL (dev.intelligentstaffingsystems.ai in config.hosts), port convention fix (9999), migration workflow docs. Cross-repo: pal-e-services PR #191 (Keycloak redirect URIs), pal-e-deployments PR #238 (overlay docs), pal-e-platform PR #545 (CI fix). In validation.
Milestones
M1: docs gate merged (Sprint 0). M2: app deployed to k3s behind funnel (Sprint 1–2). M3: dashboard live end-to-end (Sprint 3). M4: TestFlight (Sprint 6).
Repos
Repo Platform Role Status ldraney/intelligentstaffingsystems Forgejo Rails app — all product work Active ldraney/intelligentstaffingsystems-ios Forgejo Turbo Native shell — supplementary Active ldraney/godaddy-tofu Forgejo GoDaddy provider + domain examples Active
Architecture 5
-
Deployment: intelligentstaffingsystems
arch-deployment-issDeployment: intelligentstaffingsystems
Diagram
graph TB subgraph "Public Internet" V[Visitor Browser] IOS[iOS App - Turbo Native] end subgraph "Edge (Hetzner VPS)" CADDY[Caddy - TLS termination + reverse proxy] TS_EDGE[Tailscale - mesh to cluster] end subgraph "k3s Cluster" subgraph "iss namespace" RAILS[Rails App - Puma :3000] PG[PostgreSQL - CNPG] end subgraph "keycloak namespace" KC[Keycloak - SSO/OIDC] end subgraph "CI/CD" FORGEJO[Forgejo - Git] WOOD[Woodpecker CI] KANIKO[Kaniko - image build] HARBOR[Harbor - registry] ARGOCD[ArgoCD - GitOps sync] IMG_UPD[Image Updater - tag detection] end end subgraph "External" PM[Postmark - Email] AS[App Store - Subscriptions] DNS[GoDaddy DNS - godaddy-tofu provider] end V -->|HTTPS| CADDY IOS -->|HTTPS| CADDY CADDY -->|Tailscale mesh| RAILS RAILS -->|OIDC| KC RAILS -->|SQL| PG RAILS -->|SMTP| PM IOS -->|Payments| AS FORGEJO -->|webhook| WOOD WOOD --> KANIKO KANIKO -->|push image| HARBOR HARBOR -->|poll tags| IMG_UPD IMG_UPD -->|write tag to pal-e-deployments| ARGOCD ARGOCD -->|sync overlay| RAILS DNS -->|A record| CADDYComponents
Component Purpose Notes rails Rails application server (Puma) Port 3000 production, 9999 local dev. Image: intelligentstaffingsystems/intelligentstaffingsystems in Harbor. infra Platform infrastructure (k3s cluster + edge) Self-hosted on Hetzner. All components below are infra. Caddy TLS termination, reverse proxy Runs on Hetzner VPS, proxies to k3s via Tailscale mesh PostgreSQL Primary database CNPG-managed, iss namespace. Backups to MinIO. Keycloak SSO/OIDC Realm: iss. Client: intelligentstaffingsystems. PKCE enforced. Forgejo Git hosting Tailnet-only access Woodpecker CI CI pipelines Triggered by Forgejo webhooks (push events) Harbor Container registry Project: intelligentstaffingsystems. Robot accounts for push/pull. ArgoCD GitOps deployment Syncs from pal-e-deployments overlays/intelligentstaffingsystems/ Image Updater Tag detection Polls Harbor, writes new tag to pal-e-deployments via git commit Postmark Transactional email The one managed dependency. Single API token. App Store Payment collection Apple handles subscriptions. No PCI surface. Key Decisions
- Fully self-hosted except email — Postmark is the only managed dependency. Everything else (Git, CI, registry, GitOps, SSO, database) runs on the cluster. Trades operational complexity for full ownership.
- Three-repo model — pal-e-platform (infra provisioning), pal-e-services (per-service automation), pal-e-deployments (Kustomize overlays). Separation of concerns: infra changes don't touch app config.
- Caddy edge on Hetzner — public traffic enters via a VPS, not directly into the cluster. Caddy handles TLS + reverse proxy; Tailscale mesh connects to k3s. Adds a hop but keeps the cluster off the public internet.
- SOPS-encrypted secrets in git — all secrets live in pal-e-deployments as SOPS-encrypted YAML. ArgoCD decrypts at sync time. No external secrets manager.
- App Store for payments — Apple collects $800/month subscriptions. Guaranteed collection (no app access without payment), no PCI surface, at the cost of Apple's commission.
- Image Updater writes to git — rather than ArgoCD polling the registry directly, Image Updater commits the new tag to pal-e-deployments. GitOps purity: the git repo is always the source of truth for what's deployed.
Related
arch-domain-iss— entity relationshipsarch-dataflow-iss— runtime data flowproject-iss— project pagesop-secrets-management— SOPS workflowdeployment-lessons— lessons learned from deploy issues
-
Data Flow: intelligentstaffingsystems
arch-dataflow-issData Flow: intelligentstaffingsystems
Diagram
Flow 1: Authentication (OIDC)
sequenceDiagram participant U as User (iOS/Browser) participant R as Rails App participant KC as Keycloak U->>R: GET /login R->>U: 302 → Keycloak authorize URL U->>KC: Login / Register (themed page) KC->>U: 302 → /auth/keycloak/callback?code=... U->>R: GET /auth/keycloak/callback?code=... R->>KC: POST /token (exchange code) KC->>R: ID token + access token + refresh token R->>R: Extract sub, name, email, roles R->>R: Resolve Lead (by sub → email → create) R->>R: Set session R->>U: 302 → /dashboardFlow 2: Lead ↔ Keycloak Account Linking
flowchart TD A[OIDC callback: sub + email + name] --> B{Lead with this keycloak_sub?} B -->|Yes| Z[Session established] B -->|No| C{Unclaimed Lead with matching email?} C -->|Yes| D[Claim: set keycloak_sub on that Lead] C -->|No| E[Create new Lead from ID token] D --> Z E --> ZFlow 3: Message Broadcasting
sequenceDiagram participant S as Sender participant R as Rails participant DB as PostgreSQL participant TS as Turbo Streams S->>R: POST /messages (body, lead_id) R->>DB: INSERT message R->>TS: broadcasts_to :lead (after_create_commit) TS->>S: Append message to thread (WebSocket)Components
Component Purpose Notes Rails App Full-stack application server Server-rendered HTML with Hotwire; no API mode Keycloak SSO/OIDC provider Realm: iss. Roles: lead, client, admin. PKCE enforced. PostgreSQL Primary data store CNPG-managed on k3s Turbo Streams Real-time UI updates WebSocket via Action Cable; message broadcasting Postmark Transactional email Appointment confirmations, password resets Key Decisions
- Keycloak roles are authoritative — access control reads realm roles from the ID token, never Lead.role. Lead.role is a display mirror synced on each login.
- Three-step lead resolution — by sub (fast path), by email (first login after form), walk-in fallback (new Lead from token). Handles the gap between form registration and Keycloak account creation.
- Turbo Streams for messaging — broadcasts_to :lead gives real-time message delivery without polling. One broadcast channel per lead thread.
Related
arch-domain-iss— entity relationshipsarch-deployment-iss— where services runproject-iss— project page
-
Domain Model: intelligentstaffingsystems
arch-domain-issDomain Model: intelligentstaffingsystems
Diagram
erDiagram Lead { uuid id PK string keycloak_sub UK "NULL until first login" string first_name string last_name string email string phone string business_name text business_description text project_description string role "lead | client | admin" datetime registered_at datetime promoted_at } ProjectRequest { uuid id PK uuid lead_id FK string business_name text description string target_audience string inspiration string status "submitted | active | completed" } Appointment { uuid id PK uuid lead_id FK datetime scheduled_at string status "booked | completed | cancelled" text notes } Message { uuid id PK uuid lead_id FK string sender_sub "keycloak sub of sender" text body datetime sent_at } CatalogEntry { uuid id PK string title text description string pillar "web_presence | operations | internal_tooling" text technologies integer position boolean published } CatalogImage { uuid id PK uuid catalog_entry_id FK integer position } Lead ||--o{ ProjectRequest : "submits" Lead ||--o{ Appointment : "books" Lead ||--o{ Message : "sends/receives" CatalogEntry ||--o{ CatalogImage : "has"Components
Component Purpose Notes Lead Prospect/client record — exists before Keycloak account keycloak_sub NULL until first login claims it via email match ProjectRequest Client project submission business_name copied from Lead at creation time Appointment Booking with Lucas Booked through the iOS app — proof of the pipeline Message Chat messages (one thread per lead) sender_sub identifies who sent it; broadcasts_to :lead via Turbo Streams CatalogEntry Portfolio item under one of three pillars Admin CRUD; public read. Pillar maps to the ISS value prop CatalogImage Image attachment for a catalog entry Ordered by position Key Decisions
- Lead exists before auth — the registration form creates a Lead with keycloak_sub NULL; Keycloak account claims it on first login by email match. Admin sees every prospect, not just those who finished account creation.
- One message thread per lead — Message.lead_id IS the thread; no Conversation model. Simplest model for the client journey; revisit only if multi-project clients need separate threads.
- UUID primary keys everywhere — all models use UUIDs. Consequence: .last orders lexicographically, not by creation time.
- No Conversation/Thread model — intentionally excluded. Leads see their own thread, admin enters any thread.
- business_name denormalized onto ProjectRequest — copied from Lead at creation; avoids join for display.
Related
arch-dataflow-iss— runtime data flow (auth, messaging)arch-deployment-iss— where services runproject-iss— project page
-
Architecture: Auth (ISS)
arch-auth-issArchitecture: Auth (ISS)
Authentication and authorization architecture for the Intelligence Staffing Systems app.
Diagram
sequenceDiagram participant U as User/iOS App participant R as Rails App participant K as Keycloak (ISS Realm) U->>R: GET /protected_route R->>U: 302 → Keycloak login U->>K: Login (or self-register) K->>U: 302 → /auth/keycloak/callback U->>R: GET /auth/keycloak/callback R->>R: SessionsController#create (set session) R->>U: 302 → DashboardComponents
Component Role Location Keycloak Identity provider, OIDC, self-registration, email verification Self-hosted, ISS realm OmniAuth OIDC client, token exchange config/initializers/omniauth.rbSessionsController Callback handler, session lifecycle app/controllers/sessions_controller.rbApplicationController authenticate_user!,current_user, role helpersapp/controllers/application_controller.rbSessionHelper Session management utilities app/helpers/session_helper.rbKey Decisions
- Keycloak over Devise: Multi-tenant SSO across all ISS client apps. One login, all dashboards.
- Realm roles over client roles: Simpler mapping — admin/client/lead are realm-level, not per-client.
- CSS-only theme: Minimal Keycloak customization.
register.ftlis the first FreeMarker override (planned for self-registration). - Session cookie over JWT: Rails handles session state server-side. Keycloak token is consumed once at callback, not passed to the client.
- Keycloak SMTP independent of Rails Postmark: Email verification is realm-level config, not tied to the Rails mailer integration (#16).
Roles
Role Source Access admin Keycloak realm role All tabs including CRM, all threads, user management client Keycloak realm role (promoted from lead) Catalog, Projects, Communications, Account lead Default on registration Catalog, Communications, Account Related
arch-frontend-iss— frontend architecture (tab bar, Turbo, Stimulus)docs/security.md— security posture and attack surfacedocs/keycloak-setup.md— realm config details
-
Frontend Architecture: ISS
arch-frontend-issFrontend Architecture: ISS
Rails view layer with Hotwire (Turbo + Stimulus) and Propshaft asset pipeline. Answers: how does the UI render and what conventions govern it?
Diagram
graph TB subgraph iOS["iOS App (Turbo Native)"] TN[Turbo Native Shell] end subgraph Rails["Rails Server"] LAYOUT["application.html.erb"] VIEWS["View Templates (ERB)"] TABBAR["_tab_bar.html.erb (shared)"] TF[Turbo Frames] TS[Turbo Streams] end subgraph Assets["Asset Pipeline (Propshaft)"] CSS["CSS with design tokens"] IMPORTMAP["importmap-rails"] STIMULUS["Stimulus Controllers"] end subgraph Pages["View Directories"] LANDING["pages/landing"] DASH["dashboard/"] CATALOG["catalog/ + admin/catalog/"] MSGS["messages/"] PROFILE["profile/"] LEADS["leads/"] SESSIONS["sessions/"] end TN -->|"loads HTML"| LAYOUT LAYOUT --> TABBAR LAYOUT --> VIEWS VIEWS --> Pages CSS --> LAYOUT IMPORTMAP --> STIMULUS STIMULUS --> TF TF -->|"partial updates"| VIEWS TS -->|"real-time updates"| VIEWSComponents
Component Purpose Notes application.html.erbRoot layout — nav, tab bar, flash messages, content yield Wraps all authenticated views. Includes _tab_bar.html.erbpartial for bottom navigation._tab_bar.html.erbBottom tab bar navigation shared across all authenticated views Role-aware: shows different tabs for admin vs lead/client. Tabs: Catalog, Projects, Communications, Account (+ CRM for admin). pages/landing.html.erbPublic landing page — the sales pitch and App Store CTA Root route ( root "pages#landing"). No auth required. Marketing-only — no login form.Propshaft Asset fingerprinting and serving No Node.js build step. CSS files served directly with fingerprinted URLs. importmap-rails ES module management without bundler Pins Turbo, Stimulus, and application JS via importmap. No webpack/esbuild. Turbo Drive SPA-like page transitions without full reloads Default Hotwire behavior — intercepts link clicks and form submissions. Turbo Frames Partial page updates scoped to a frame Used for inline editing, modal-like flows, tab content switching. Turbo Streams Real-time DOM updates via WebSocket (Solid Cable) Used for live messaging updates. Backed by Solid Cable (PostgreSQL, no Redis). Stimulus Modest JS framework for DOM behavior Controllers for interactive UI elements. No heavy client-side state. CSS Conventions
Convention Detail Design tokens CSS custom properties on :rootinapplication.css. Brand colors:--color-accent: #1b2a4a(navy),--color-gold: #996d13.Per-view stylesheets One CSS file per view area: dashboard.css,catalog.css,messages.css,profile.css,tab_bar.css,forms.css,pages.css,admin_catalog.css.No utility-first Semantic class names, not Tailwind. Styles reference design tokens via var(--color-*).Mobile-first Base styles target mobile (Turbo Native shell). Desktop breakpoints added as needed. Key Decisions
- Propshaft + importmap over esbuild/webpack — No Node.js build step. Propshaft handles asset fingerprinting; importmap-rails pins ES modules directly. Simpler deploy, fewer moving parts.
- Hotwire over React/Vue SPA — Server-rendered HTML with Turbo Drive for navigation, Turbo Frames for partial updates, Turbo Streams for real-time. One codebase serves both web and Turbo Native iOS.
- Semantic CSS with design tokens — All colors, spacing, and typography flow from CSS custom properties defined once in
application.css. No Tailwind. ISS brand palette (navy + gold) enforced via tokens. - Per-view CSS files — Each view area gets its own stylesheet. Avoids monolithic CSS. Propshaft serves them individually with fingerprinting.
- Tab bar as shared partial —
_tab_bar.html.erbrenders role-aware navigation. Admin sees CRM tab; leads/clients do not. Consistent bottom nav across the iOS shell. - Landing page outside auth —
pages#landingis the root route, served without authentication. All other views require login via theauthenticate_user!filter. - Solid Cable for WebSocket — Turbo Streams use Solid Cable backed by PostgreSQL. No Redis dependency for real-time features.
Key Directories
Path Contents app/views/layouts/application.html.erb— root layout with tab barapp/views/shared/_tab_bar.html.erb— role-aware bottom navigationapp/views/pages/landing.html.erb— public landing pageapp/views/dashboard/Authenticated dashboard views app/views/catalog/Public catalog browsing app/views/admin/catalog/Admin CRUD for catalog entries app/views/messages/Messaging thread views app/views/profile/User profile display and edit app/assets/stylesheets/Per-view CSS files with shared design tokens Related
- project-iss — ISS project page
Board 1
-
ISS MVP
board-issNo content
Repos 1
-
intelligentstaffingsystemsactive