Westside RoR
Notes
Review 19
-
Review: K8s prod manifests + secrets for ArgoCD deployment (R3)
review-1375-2026-06-06-r3Verdict: APPROVED
Third review pass. All critical issues from R1 (wrong repo, wrong ingress assumptions, wrong secret pattern, port mismatch, overlap with #28) and R2 (wrong repo owner, files said "create" instead of "rewrite") have been resolved. The issue body is now accurate and agent-ready.
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- child of #40, depends on #41
- [x] Repo --
ldraney/pal-e-deployments(correct) - [x] User Story -- present and clear
- [x] Context -- thorough explanation of why existing files must be rewritten, references PR #189/#28, describes platform pattern
- [x] File Targets -- present with correct rewrite/create distinction
- [x] Acceptance Criteria -- 10 criteria, all testable
- [x] Test Expectations -- includes kustomize build dry-run command
- [x] Constraints -- clear on target repo, patterns, SOPS, port
- [x] Checklist -- present
- [x] Related -- comprehensive cross-references
Traceability
- [x] story:ci-pipeline label -- present on board item
- [ ] story note NOT verified --
project-westside-rornote does not exist in pal-e-docs. [SCOPE] Create project page with user-stories section (acknowledged non-blocking in R1/R2) - [x] arch:k8s label -- present on board item
- [ ] arch note NOT verified -- no
arch-k8snote found in pal-e-docs. [SCOPE] Create architecture note arch-k8s (acknowledged non-blocking in R1/R2) - [x] Forgejo issue -- ldraney/westside-ror#42, open
File Targets
- [x]
overlays/westside-ror/prod/kustomization.yaml-- verified EXISTS in pal-e-deployments. Currently referencesbases/standard, usesruby:3.4-slimimage, removes imagePullSecrets. Correctly marked as "rewrite" - [x]
overlays/westside-ror/prod/deployment-patch.yaml-- verified EXISTS. Currently has hostPath mount, inline apt-get/bundle, envFrom secretRef. Correctly marked as "rewrite" - [x]
overlays/westside-ror/prod/ingress.yaml-- verified DOES NOT EXIST in prod (exists in dev). Correctly marked as "create" - [x]
overlays/westside-ror/prod/ingress-westsidekingsandqueens.yaml-- verified DOES NOT EXIST. Correctly marked as "create" - [x]
overlays/westside-ror/prod/secrets.enc.yaml-- verified DOES NOT EXIST. Correctly marked as "create". SOPS pattern verified viabelievers-elite/prod/secrets.enc.yaml - [x]
overlays/westside-ror/prod/harbor-creds.enc.yaml-- verified DOES NOT EXIST. Correctly marked as "create". SOPS pattern verified viawestsidekingsandqueens/prod/harbor-creds.enc.yaml
Reference patterns verified:
landscaping-assistant/prod/-- confirmed kustomization.yaml sets namespace, references bases/standard, uses Harbor image tag, deployment-patch has initContainer, individual secretKeyRef entries, security context, probes. Only has 2 files (no secrets.enc.yaml -- secrets likely managed separately)westsidekingsandqueens/prod/-- confirmed has harbor-creds.enc.yaml and ingress.yaml with Tailscale Funnel patternbelievers-elite/prod/-- confirmed has secrets.enc.yaml with SOPS age encryption.sops.yaml-- confirmed path_regex\.enc\.yaml$with age recipient key
Repo Placement
Correct. Issue is tracked on
ldraney/westside-rorfor board visibility, but clearly states PR must targetldraney/pal-e-deployments. This is documented in the Repo section, Constraints, and Checklist. All three locations now sayldraney/pal-e-deployments(R2 fix confirmed).Dependencies
- #41 (Terraform onboarding) -- prerequisite, creates namespace + ArgoCD app. Status: OPEN. Documented in Lineage and Related. This ticket cannot be fully validated (ArgoCD sync) until #41 ships, but the manifests themselves can be written independently.
- #43 (Dockerfile + CI pipeline) -- sibling, sets port 3000 in Dockerfile. Status: OPEN. Documented in Context and Related. The manifests reference port 3000 which aligns with #43's plan to drop Thruster.
- #28 (Commit prod deployment manifests) -- predecessor, DONE. Created the existing dev-like prod files that this ticket replaces. Documented in Context and Related.
- #40 (Epic: CI/CD pipeline) -- parent epic. In BACKLOG. Documented in Lineage.
Acceptance Criteria
10 criteria, all verifiable by an agent:
- AC 1-4: Structural checks -- agent can verify via grep/read after writing files
- AC 5: Security context -- agent can compare against landscaping-assistant pattern
- AC 6: Ingress presence -- agent can verify files exist
- AC 7-8: SOPS secrets -- agent can create with
sops --encryptand verify key count - AC 9: Port 3000 -- agent can grep rendered output
- AC 10: kustomize build -- agent can run the test command
Test command is real:
kustomize build overlays/westside-ror/prod/ | kubectl apply --dry-run=client -f -Blast Radius
- westsidekingsandqueens ingress conflict risk: The issue says to create
ingress-westsidekingsandqueens.yamlin the westside-ror namespace for thewestsidekingsandqueenshostname. The existingwestsidekingsandqueens/prod/ingress.yamlcurrently serves that hostname from the westsidekingsandqueens namespace. The README says westsidekingsandqueens is "being replaced by westside-ror" but is "still running as the active production frontend." The issue's Context section explains this: the westsidekingsandqueens hostname was "manually created in westside-ror namespace after consolidation." This is consistent with the consolidation story. The agent implementing this should be aware that the old overlay's ingress may need to be removed separately, but the issue correctly scopes the DO-NOT-TOUCH list to exclude that. - No impact on dev overlay -- correctly excluded from file targets
- No impact on bases/standard -- correctly excluded, patches only
- DATABASE_URL construction: The existing deployment-patch constructs DATABASE_URL from individual env vars. The new pattern uses individual secretKeyRef entries. The issue lists the correct 6 keys but does not mention DATABASE_URL construction. The agent will need to add a DATABASE_URL env var that interpolates the secret values, matching the current pattern. This is implicit in "follow landscaping-assistant pattern" but worth noting.
Decomposition Assessment
6 file targets across 1 repo (
pal-e-deployments). 10 acceptance criteria (above the 5-criterion threshold). However:- All files are in the same directory (
overlays/westside-ror/prod/) - Strong reference patterns exist (landscaping-assistant, westsidekingsandqueens, believers-elite)
- 2 files are rewrites of existing content, 4 are new but follow established patterns
- SOPS encryption is mechanical (sops --encrypt with age key)
- Estimated agent time: ~5 minutes -- borderline but feasible in a single pass given the pattern-following nature
No decomposition needed. The high AC count reflects thoroughness of verification, not complexity of implementation.
Observations (non-blocking)
- Missing
namespace:in kustomization.yaml: The existing westside-ror kustomization does NOT setnamespace: westside-ror, but the landscaping-assistant and westsidekingsandqueens patterns both set their namespace explicitly. The issue says "follow landscaping-assistant pattern" which implies the agent should add it. Not a ticket defect -- the agent should follow the pattern. - Missing SOPS secrets.enc.yaml reference in kustomization.yaml: The issue's kustomization.yaml rewrite should add
secrets.enc.yamlandharbor-creds.enc.yamlto theresources:list (as westsidekingsandqueens does for harbor-creds). Not explicitly stated but implied by "follow pattern." - ServiceMonitor rename: The landscaping-assistant pattern renames the ServiceMonitor. The existing westside-ror kustomization does not. The agent should follow the pattern and add it.
- Project page and arch note:
project-westside-rorandarch-k8sdo not exist in pal-e-docs. Acknowledged as non-blocking in previous reviews.
Recommendation
- [SCOPE] Create
project-westside-rorproject page with user-stories section in pal-e-docs (non-blocking, acknowledged) - [SCOPE] Create
arch-k8sarchitecture note in pal-e-docs (non-blocking, acknowledged)
No blocking issues remain. Ticket is agent-ready.
-
Review: Terraform service onboarding for westside-ror (re-review)
review-1374-2026-06-06-r2Verdict: APPROVED
Re-review of board item #1374. Previous review
review-1374-2026-06-06returned NEEDS_REFINEMENT with 4 findings. Two[BODY]fixes confirmed applied; two[SCOPE]gaps acknowledged as known and non-blocking.Template Completeness
- [x] Type -- Feature
- [x] Lineage -- child of #40
- [x] Repo -- forgejo_admin/pal-e-services (explicit NOTE clarifies cross-repo tracking)
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All template sections present and complete.
Traceability
- [x] story:ci-pipeline label -- present on board item
- [ ] story note MISSING -- project-westside-ror note does not exist. Known gap, not blocking (issue body is self-contained). [SCOPE] Create project page with user-stories section.
- [x] arch:terraform label -- present on board item
- [ ] arch note MISSING -- No arch-terraform note in pal-e-docs. Known gap, not blocking. [SCOPE] Create architecture note arch-terraform.
- [x] Forgejo issue -- ldraney/westside-ror#41, state: open
File Targets
- [x]
pal-e-services/terraform/k3s.tfvars-- verified exists (225 lines). Services block spans lines 137-225. 10 existing service entries (issue says 9, minor). westside-ror NOT yet present -- correct. - [x] Line reference FIXED -- now reads "services block spans approximately lines 137-225; individual entries are ~8 lines each". Verified accurate against file.
Repo Placement
FIXED. Cross-repo instruction is now explicit and repeated in three locations:
- Repo section: NOTE block explains issue is tracked on westside-ror for board visibility but PR targets forgejo_admin/pal-e-services
- Constraints: "PR must be opened against forgejo_admin/pal-e-services, NOT ldraney/westside-ror"
- Checklist: "PR opened (on forgejo_admin/pal-e-services)"
An implementing agent will not miss this.
Dependencies
- #40 (board #1372) -- parent epic, backlog. Not blocking.
- #42 (board #1375) -- K8s manifests, backlog. Depends on this ticket (needs Harbor project). Documented.
- #43 (board #1376) -- Dockerfile + CI, backlog. Depends on this (needs Harbor creds). Documented.
- No in_progress or next_up items block this ticket.
Acceptance Criteria
6 acceptance criteria. AC 1-2 are code-verifiable (grep the entry, match pattern). AC 3-6 are infrastructure validation steps requiring terraform CLI + live cluster access -- manual post-merge steps. The code change itself is a single file edit. Acceptable scope.
Blast Radius
- Existing namespace resources (rails-env secret, Tailscale Funnel ingresses) are documented as a risk. Constraints section addresses this explicitly.
- ArgoCD pruning risk documented in Context. #42 will handle including these in managed manifests.
- No similar pattern bugs across sibling services -- well-established block with 10 entries.
Decomposition Assessment
1 file target, 1 repo (pal-e-services), 6 AC (1 code change + 5 infra validation). Estimated agent work under 5 minutes. No decomposition needed.
Previous Findings Resolution
- [x]
[BODY]Line reference -- FIXED. Now accurately describes services block span. - [x]
[BODY]Cross-repo PR instruction -- FIXED. Explicit NOTE added, repeated in Constraints and Checklist. - [ ]
[SCOPE]No project page -- still missing. Known gap, non-blocking. - [ ]
[SCOPE]No arch-terraform note -- still missing. Known gap, non-blocking.
Recommendation
No action needed. Ticket is ready for implementation.
Remaining
[SCOPE]items for future backlog:[SCOPE]Create project pageproject-westside-rorwith user-stories section including ci-pipeline story.[SCOPE]Create architecture notearch-terraformdocumenting the terraform services module pattern.
-
Re-Review: Dockerfile + Woodpecker CI pipeline
review-1376-2026-06-06-r2Verdict: APPROVED
Re-review of board item #1376 after refinement. Previous review:
review-1376-2026-06-06(NEEDS_REFINEMENT).Previous Findings — Resolution
- [x] Test framework mismatch (RSpec vs Minitest) — FIXED. Issue Context now states: "westside-ror uses Minitest (
bundle exec rails test)". AC4 explicitly requiresbundle exec rails test, NOTbundle exec rspec. Constraints section reiterates: "Use Minitest (bundle exec rails test), NOT RSpec — westside-ror hastest/dir, nospec/dir, no rspec in Gemfile." Test Expectations run command also usesbundle exec rails test. - [x] AC7/AC8 unachievable in PR — FIXED. AC1-AC7 are now in-PR criteria. AC8-AC9 are in a separate "Post-merge manual steps" section with note: "depend on #41 completing first." Clear separation.
- [ ] Project page missing — Known gap, non-blocking.
project-westside-rorpage does not exist in pal-e-docs. [SCOPE] remains. - [ ] Arch note missing — Known gap, non-blocking.
arch-ci-cdnote does not exist in pal-e-docs. [SCOPE] remains.
Template Completeness
- [x] Type — Feature
- [x] Lineage — child of #40, depends on #41
- [x] Repo — ldraney/westside-ror
- [x] User Story
- [x] Context — includes reference implementation and explicit Minitest callout
- [x] File Targets — modify (Dockerfile, bin/docker-entrypoint), create (.woodpecker.yaml), do-not-touch (k8s/dev.yaml, k8s/prod/*)
- [x] Acceptance Criteria — 7 in-PR criteria, 2 post-merge manual steps
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:ci-pipeline label present
- [ ] story note MISSING — [SCOPE] Project page
project-westside-rordoes not exist. Known gap, non-blocking. - [x] arch:ci-cd label present
- [ ] arch note MISSING — [SCOPE] No
arch-ci-cdnote exists. Known gap, non-blocking. - [x] Forgejo issue — #43, open
File Targets
- [x]
Dockerfile— verified: exists at repo root, usesdocker.io/library/ruby:3.4.8-slim. CMD references./bin/thrustbut thrust binary does not exist and thruster gem is not in Gemfile/Gemfile.lock. Issue correctly identifies all three problems (base image, Thruster, port 80). - [x]
bin/docker-entrypoint— verified: exists, runsdb:prepareon server start. - [x]
.woodpecker.yaml— confirmed does not exist yet (to be created). - [x] Reference:
~/landscaping-assistant/.woodpecker.yaml— verified: exists with clone, bundle-install, lint, test, build-and-push steps. Test step usesbundle exec rspec(correctly identified as needing change for westside-ror). - [x]
test/directory exists with controllers/, models/, services/, test_helper.rb. Nospec/directory. No rspec in Gemfile. Minitest confirmed. - [x] Rubocop available:
rubocop-rails-omakasegem in Gemfile,.rubocop.ymlexists. Lint step will work. - [x] Puma gem present in Gemfile. Port 3000 switch is correct.
Repo Placement
OK — issue filed on ldraney/westside-ror, all file targets in same repo. Single-repo scope.
Dependencies
- #41 (Terraform service onboarding) — open, board item #1374 in backlog. Creates Harbor project + robot account. Prerequisite for build-and-push to succeed, but correctly documented as post-merge manual step dependency. Does NOT block the PR itself (Dockerfile and .woodpecker.yaml can be written and merged independently).
- #40 (Epic: CI/CD pipeline) — open, board item #1372 in backlog. Parent epic.
- #42 (K8s prod manifests) — open, board item #1375 in backlog. Sibling, references images this pipeline pushes. No blocking relationship.
Acceptance Criteria
- [x] AC1 (build image base) — agent-verifiable: grep Dockerfile for harbor build image.
- [x] AC2 (runtime image base) — agent-verifiable: grep Dockerfile for harbor runtime image.
- [x] AC3 (woodpecker steps) — agent-verifiable: parse .woodpecker.yaml for step names.
- [x] AC4 (Minitest not RSpec) — agent-verifiable: grep .woodpecker.yaml for test command. Explicitly stated.
- [x] AC5 (Kaniko repo/tag) — agent-verifiable: check build-and-push settings.
- [x] AC6 (push only on main) — agent-verifiable: check when clause.
- [x] AC7 (lint+test on push+PR) — agent-verifiable: check when clauses on lint/test steps.
- [x] Post-merge AC8-AC9 — correctly separated, depend on #41. Not in PR scope.
Blast Radius
- Dockerfile change is self-contained to westside-ror.
- Thruster reference removal is safe — binary and gem do not exist in repo.
- No other repos affected.
Decomposition Assessment
2 file modifications + 1 file creation, single repo, 7 in-PR acceptance criteria. Core agent work is well under the 5-minute rule. No decomposition needed.
Recommendations
No action needed. All previous [BODY] recommendations have been addressed. Remaining [SCOPE] items (project page, arch note) are known gaps and non-blocking for this ticket.
[SCOPE]Create project pageproject-westside-rorwith user-stories section (non-blocking, pre-existing gap).[SCOPE]Create architecture notearch-ci-cd(non-blocking, pre-existing gap).
- [x] Test framework mismatch (RSpec vs Minitest) — FIXED. Issue Context now states: "westside-ror uses Minitest (
-
Review: K8s prod manifests + secrets for ArgoCD deployment
review-1375-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — child of #40, depends on #41
- [x] Repo —
ldraney/westside-ror - [x] User Story
- [x] Context
- [x] File Targets
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All required feature template sections present.
Traceability
- [x] story:ci-pipeline label — present on board item
- [ ] story note MISSING —
project-westside-rornote does not exist in pal-e-docs (404). [SCOPE] Create project pageproject-westside-rorwith user-stories section includingci-pipeline. - [x] arch:k8s label — present on board item
- [ ] arch note MISSING — search for
arch-k8sreturned zero results. [SCOPE] Create architecture notearch-k8sfor the k8s manifest component. - [x] Forgejo issue —
ldraney/westside-ror#42, state: open
File Targets
- [ ]
k8s/prod/deployment.yaml— ISSUE: Wrong repo. The platform pattern places production manifests inpal-e-deployments/overlays/westside-ror/prod/, not in the app repo. Awestside-ror/overlays/westside-ror/dev/overlay already exists inpal-e-deployments. The sibling servicewestsidekingsandqueenshas its prod overlay atpal-e-deployments/overlays/westsidekingsandqueens/prod/. Some older services (pal-e-docs, basketball-api) still have in-repok8s/dirs, but the platform has converged onpal-e-deployments. - [ ]
k8s/prod/service.yaml— ISSUE: Same — belongs inpal-e-deployments. - [ ]
k8s/prod/ingress-westside-ror.yaml— ISSUE: Same repo problem. Additionally, file already exists functionally ink8s/dev.yaml(lines 131-148) as a combined manifest. - [ ]
k8s/prod/ingress-westsidekingsandqueens.yaml— ISSUE: Wrong assumption. ThewestsidekingsandqueensTailscale Funnel ingress belongs to thewestside-app(westsidekingsandqueens) deployment, NOT to westside-ror. It already exists atpal-e-deployments/overlays/westsidekingsandqueens/prod/ingress.yamlpointing to thewestside-appservice. Creating a second ingress for the same hostname would conflict. - [ ]
k8s/prod/kustomization.yaml— ISSUE: The platform pattern usespal-e-deploymentswithbases/standardas a kustomize base (deployment, service, networkpolicy). Prod overlays reference../../../bases/standardand apply patches. This file should be inpal-e-deployments. - [ ]
k8s/prod/sealed-secret.yaml— ISSUE: Platform uses SOPS (age encryption), not sealed-secrets. Seepal-e-deployments/overlays/westsidekingsandqueens/prod/harbor-creds.enc.yamlandwestside-app/k8s/auth-secret.enc.yamlfor the pattern. File should berails-env.enc.yamlin the overlay. - [x]
k8s/dev.yaml— verified exists, ticket correctly says not to touch it.
Repo Placement
MAJOR MISMATCH. The issue says repo is
ldraney/westside-rorand all file targets arek8s/prod/*inside the app repo. However, the established platform pattern places production manifests inpal-e-deployments. The closed issue #28 ("Commit prod deployment manifests") was correctly filed againstldraney/pal-e-deployments. This ticket should either:- Target
pal-e-deployments/overlays/westside-ror/prod/as the file location (matching the pattern fromwestsidekingsandqueens/prod/), OR - Be filed on the
pal-e-deploymentsrepo if the team wants the Forgejo issue to live with the code it modifies.
Dependencies
- #41 (Terraform onboarding) — documented as prerequisite, state: open. Creates namespace, Harbor project, and ArgoCD app via terraform. This ticket correctly depends on it.
- #43 (Dockerfile + Woodpecker CI) — documented as related, state: open. Pushes images to Harbor that these manifests reference. The deployment manifest needs a valid Harbor image to pull.
- #28 (Commit prod deployment manifests) — state: closed/done. This was the PREVIOUS attempt to commit prod manifests, filed against
pal-e-deployments. Overlap with this ticket needs clarification — was #28 completed, partially done, or superseded? - #1358 board item — board item for #28 is in
donecolumn. If that work was completed, this ticket may be partially or fully redundant.
Acceptance Criteria
- [x]
k8s/prod/directory contains all manifests — testable but wrong directory per platform pattern - [x] Deployment references Harbor image — testable, clear
- [ ] Both Tailscale Funnel ingresses present — ISSUE:
westsidekingsandqueensingress belongs to the separate westside-app service, not westside-ror. Onlywestside-rorfunnel should be created here. - [x] Secret manifest includes all env vars — testable, clear list provided
- [ ] Secret management follows platform pattern — ticket says "SOPS, sealed-secrets, or external-secrets — match landscaping-assistant" but landscaping-assistant has NO k8s directory. The reference should be
westsidekingsandqueensoverlay inpal-e-deployments, which uses SOPS with age encryption. - [x] docker-entrypoint runs db:prepare — verified:
bin/docker-entrypointrunsdb:preparewhen starting rails server - [x] Dev overlay untouched — clear, testable
Blast Radius
- Ingress hostname conflict: Creating a
westsidekingsandqueensingress under westside-ror would conflict with the existing ingress inpal-e-deployments/overlays/westsidekingsandqueens/prod/ingress.yaml. Tailscale Funnel hostnames are unique per cluster. - Overlap with closed #28: If issue #28 already committed manifests to
pal-e-deployments, creating a second set in the app repo creates drift and confusion about source of truth. - Dockerfile entrypoint port: The Dockerfile uses Thruster and EXPOSEs port 80 (not 3000). The deployment and service manifests need to match — either target port 80 or override the CMD.
Decomposition Assessment
6 file targets (would be ~4 after corrections), 7 acceptance criteria. However, all files are in a single directory and the work is straightforward manifest creation. With corrected scope (single repo, ~4 files), this fits in a single agent pass. No decomposition needed after scope fixes are applied.
Recommendation
[BODY]Fix repo: change fromldraney/westside-rortoldraney/pal-e-deployments, or clarify that file targets are inpal-e-deployments/overlays/westside-ror/prod/.[BODY]Fix file targets: rewrite all paths fromk8s/prod/*tooverlays/westside-ror/prod/*inpal-e-deployments.[BODY]Removeingress-westsidekingsandqueens.yamltarget — that ingress belongs to the separatewestsidekingsandqueensoverlay and already exists.[BODY]Fix secret pattern reference: change "match landscaping-assistant" to "match westsidekingsandqueens overlay in pal-e-deployments (SOPS with age encryption)". Userails-env.enc.yamlnaming.[BODY]Add note about kustomize base: prod overlay should reference../../../bases/standardand apply patches (matchingwestsidekingsandqueens/prod/kustomization.yamlpattern).[BODY]Fix AC #3: remove "westsidekingsandqueens" from the Funnel ingress criterion — onlywestside-rorfunnel is needed.[BODY]Fix AC #5: specify SOPS with age, not "SOPS, sealed-secrets, or external-secrets".[BODY]Add AC: verify container port matches Dockerfile (port 80 via Thruster, not 3000).[BODY]Clarify relationship with closed #28 — is this a replacement, continuation, or does #28 need reopening?[SCOPE]Create project pageproject-westside-rorwith user-stories section includingci-pipelinestory.[SCOPE]Create architecture notearch-k8sfor the k8s manifest component.
-
Review: Terraform service onboarding for westside-ror
review-1374-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
All template sections present. Template completeness is good.
Traceability
- [x] story:ci-pipeline label -- present on board item
- [ ] story note MISSING -- [SCOPE] project-westside-ror note does not exist; cannot verify user story entry. Create project page with user-stories section.
- [x] arch:terraform label -- present on board item
- [ ] arch note MISSING -- [SCOPE] No
arch-terraformnote found in pal-e-docs. Create architecture note arch-terraform for the terraform services module. - [x] Forgejo issue -- ldraney/westside-ror#41, state: open
File Targets
- [x]
pal-e-services/terraform/k3s.tfvars-- verified exists (225 lines). Services block starts at line 137. westside-ror is NOT yet present in the file. - [ ] Line reference inaccurate -- [BODY] Issue says "Reference: landscaping-assistant entry in k3s.tfvars (lines 137-225)". The landscaping-assistant service entry is actually at lines 147-154; lines 137-225 is the entire services block. Recommend clarifying to "lines 147-154" for the landscaping-assistant entry pattern.
Repo Placement
MISMATCH: The issue body declares
### Repo: forgejo_admin/pal-e-services(the repo where the file change lives), but the Forgejo issue is filed onldraney/westside-ror. This is a cross-repo issue -- the actual code change is in pal-e-services, not westside-ror. The implementing agent needs to clone/checkout pal-e-services, not westside-ror.[BODY] Clarify that the PR should be opened against
forgejo_admin/pal-e-services, notldraney/westside-ror. Consider whether the Forgejo issue should be filed on pal-e-services instead, or add explicit instructions that the agent must work in the pal-e-services repo.Dependencies
- #40 (board item #1372) -- parent epic "CI/CD pipeline", backlog. This ticket is a child.
- #42 (board item #1375) -- "K8s prod manifests + secrets for ArgoCD deployment", backlog. Depends on this ticket (needs Harbor project for image refs). Documented in issue body.
- #43 (board item #1376) -- "Dockerfile + Woodpecker CI pipeline", backlog. Depends on this indirectly (CI needs Harbor to push images).
- No items in in_progress or next_up block this ticket.
- The
k8s/proddirectory referenced in the ArgoCD source_path does NOT exist yet in westside-ror -- expected, as #42 will create it. ArgoCD app will be unhealthy until then (documented in AC).
Acceptance Criteria
5 acceptance criteria -- at the upper bound but acceptable for a single agent pass.
- AC 1 (add services entry) -- verifiable by grep/read
- AC 2 (terraform plan shows resources) -- verifiable but requires terraform CLI access and credentials
- AC 3 (terraform apply succeeds) -- requires live infra access, not automatable by code agent alone
- AC 4 (Harbor project exists) -- requires Harbor API/UI access post-apply
- AC 5 (ArgoCD app created) -- requires ArgoCD access post-apply
AC 2-5 are infrastructure verification steps that happen after the code change. The code change itself (AC 1) is straightforward. An agent can handle the code change + PR; AC 2-5 are manual validation steps.
Blast Radius
- Existing namespace resources:
rails-envsecret and Tailscale Funnel ingresses are manually created in the westside-ror namespace. Terraform namespace resource could conflict. Constraints section documents this risk correctly. - No similar pattern bugs found -- the services block is well-established with 9 existing entries.
- ArgoCD pruning policy is a risk factor -- if ArgoCD prunes unmanaged resources in the namespace, the manually-created resources could be deleted. This is noted in the Context section.
Decomposition Assessment
1 file target, 1 repo (pal-e-services), 5 AC (but only 1 is a code change). Estimated agent work: under 5 minutes for the code change + PR. No decomposition needed.
Recommendation
[BODY]Fix line reference: "landscaping-assistant entry in k3s.tfvars (lines 137-225)" should be "(lines 147-154)" for the service entry pattern, or "(services block: lines 137-225)" for the full block.[BODY]Add explicit instruction that the PR must be opened againstforgejo_admin/pal-e-services, and the agent must clone/work in that repo, not westside-ror.[SCOPE]Create project pageproject-westside-rorwith a user-stories section that includes the ci-pipeline story.[SCOPE]Create architecture notearch-terraformdocumenting the terraform services module pattern.
-
Review: Dockerfile + Woodpecker CI pipeline
review-1376-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- child of #40, depends on #41
- [x] Repo -- ldraney/westside-ror
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:ci-pipeline label present
- [ ] story note MISSING -- [SCOPE] Project page
project-westside-rordoes not exist in pal-e-docs. Cannot verify user story entry. Create project page with user-stories section. - [x] arch:ci-cd label present
- [ ] arch note MISSING -- [SCOPE] No
arch-ci-cdnote found in pal-e-docs. Create architecture note for CI/CD component. - [x] Forgejo issue -- #43, open
File Targets
- [x]
Dockerfile-- verified: exists, usesdocker.io/library/ruby:3.4.8-slimas claimed. Thruster reference in CMD butbin/thrustdoes NOT exist and thruster gem is NOT in Gemfile/Gemfile.lock. Issue correctly identifies this needs changing. - [x]
bin/docker-entrypoint-- verified: exists,db:prepareruns correctly. - [x]
.woodpecker.yaml-- confirmed does not exist yet (to be created). - [x] Reference:
~/landscaping-assistant/.woodpecker.yaml-- verified exists, structure matches what issue describes (clone, bundle-install, lint, test, build-and-push steps). - [x] Reference:
~/landscaping-assistant/Dockerfile-- verified usesruby-rails-build:latest/ruby-rails-runtime:latest, exposes port 3000, uses Puma directly.
Repo Placement
OK -- issue is filed on ldraney/westside-ror, all file targets are in that repo. Single-repo scope.
Dependencies
- #41 (Terraform service onboarding) -- open, creates Harbor project + robot account. This is a prerequisite: without the Harbor project, Kaniko build-and-push will fail. Documented in issue Lineage section. Board item #1374 is in backlog.
- #40 (Epic: CI/CD pipeline) -- open, parent epic. Board item #1372 in backlog.
- #42 (K8s prod manifests) -- sibling, references images this pipeline pushes. Board item #1375 in backlog. No blocking relationship for this ticket.
Acceptance Criteria
- [x] AC1-AC6 are clear and agent-verifiable (file content checks).
- [ ] AC3 says "test" step should use the reference pattern, but the reference uses
bundle exec rspecwhile westside-ror uses Minitest (test/directory, no rspec gem). The issue body and AC do not mention this difference. The agent will copybundle exec rspecfrom the reference and the pipeline will fail. [BODY] The test step must usebundle exec rails testinstead ofbundle exec rspec. - [ ] AC7 ("Repo activated in Woodpecker") is a manual/API step outside the PR scope. Should be split out or marked as a manual post-merge step.
- [ ] AC8 ("First pipeline run succeeds") depends on AC7 and on #41 completing first. Not achievable in the same PR.
Blast Radius
- Dockerfile change is self-contained to westside-ror.
- Thruster (
bin/thrust) is referenced in the current Dockerfile CMD but does not exist in the repo and the gem is not bundled -- the current Dockerfile is already broken for production. No downstream risk from removing the Thruster reference. - No other repos are affected by this change.
Decomposition Assessment
2 file modifications + 1 file creation, single repo. 8 acceptance criteria but 2 (AC7, AC8) are manual/post-merge. Core agent work is ~3 files, well under 5-minute rule. No decomposition needed.
Recommendations
[BODY]Add explicit note in Context or Constraints: westside-ror uses Minitest (bundle exec rails test), NOT RSpec. The test step in.woodpecker.yamlmust differ from the landscaping-assistant reference.[BODY]Clarify AC3: the test step command should bebundle exec rails test, notbundle exec rspec.[BODY]Clarify AC7-AC8: mark as manual post-merge steps or split into a separate task, since they cannot be verified in a PR.[SCOPE]Create project pageproject-westside-rorin pal-e-docs with user-stories section includingci-pipelinestory.[SCOPE]Create architecture notearch-ci-cdin pal-e-docs for the CI/CD component.
-
Review: Set up CI/CD pipeline: Woodpecker + Harbor + ArgoCD
review-1372-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- Standalone, discovered from undeployed Stripe PRs
- [x] Repo -- ldraney/westside-ror
- [x] User Story -- present and well-formed
- [x] Context -- thorough, references landscaping-assistant pattern
- [x] File Targets -- present with both modify/create and do-not-touch sections
- [x] Acceptance Criteria -- 10 items, clear and specific
- [x] Test Expectations -- present with run commands
- [x] Constraints -- present with platform patterns, base images, access requirements
- [x] Checklist -- present
- [x] Related -- present
All required sections for the Feature template are present.
Traceability
- [x] story:ci-pipeline label -- present on board item
- [ ] story note MISSING -- [SCOPE] No project page
project-westside-rorexists in pal-e-docs, so user-stories section cannot be verified. Create project page with user story entry forci-pipeline. - [x] arch:ci-cd label -- present on board item
- [ ] arch note MISSING -- [SCOPE] No architecture note
arch-ci-cdfound in pal-e-docs. Create architecture notearch-ci-cdfor CI/CD pipeline component. - [x] Forgejo issue -- ldraney/westside-ror#40, open
File Targets
- [x]
.woodpecker.yaml-- confirmed does NOT exist yet (new file, correct) - [x]
Dockerfile-- exists, currently usesdocker.io/library/ruby:3.4-slim. Needs update to platform base images (ruby-rails-build,ruby-rails-runtime). Verified reference impl atlandscaping-assistant/Dockerfileusesharbor.tail5b443a.ts.net/library/ruby-rails-build:latest. - [x]
k8s/-- exists with onlydev.yaml. Currently referencesruby:3.4-slimimage with hostPath mount. Ticket correctly identifies need for proper prod manifests referencing Harbor image. - [x]
bin/docker-entrypoint-- exists and already runsdb:prepareon startup. No changes needed. - [x]
k8s/dev.yaml-- correctly listed under "do not touch" - [x]
pal-e-services/terraform/k3s.tfvars-- verified: westside-ror is NOT in theservicesblock (line 137-225). Needs to be added. Confirmed other services follow the pattern: forgejo_repo, image_repo, port, funnel, source_repo, source_path.
Repo Placement
This ticket correctly identifies work across TWO repos:
ldraney/westside-ror-- .woodpecker.yaml, Dockerfile, k8s manifests (Forgejo issue is filed here)ldraney/pal-e-services-- terraform/k3s.tfvars services block
The issue body explicitly documents the cross-repo file target. However, there is no separate Forgejo issue on pal-e-services for the terraform change. This is acceptable since the terraform change is a single-line addition and is clearly documented in the file targets. A separate issue would be over-engineering.
Dependencies
- No board items currently blocking this ticket. Item #1372 is in backlog.
- Items #1207 (issue #2, in_progress) and #1222 (issue #13, in_progress) are unrelated feature work.
- Done items #1334 (issue #24) and #1357 (issue #27) are the Stripe work this ticket aims to deploy -- they are completed, not blocking.
- Done item #1358 (issue #28, "Commit prod deployment manifests") is DIRECTLY related -- it committed deployment manifests but those are the dev overlay. This ticket replaces those with proper Harbor-image manifests. No conflict.
- The ticket requires platform base images (
ruby-rails-build,ruby-rails-runtime) to exist in Harbor. The constraints section mentions this but does not verify it. The landscaping-assistant reference already uses these images successfully. - Requires Harbor admin access, Woodpecker admin access, and terraform access to pal-e-services. Documented in Constraints.
- The
westsidekingsandqueens-funnelingress currently exists in the cluster (verified via kubectl) -- created manually. AC #8 requires preserving both funnel ingresses. The terraform services block will create a newwestside-rorfunnel, but thewestsidekingsandqueensfunnel needs special handling since it is a second hostname for the same service. This is not addressed in the file targets.
Acceptance Criteria
10 acceptance criteria present. Assessment:
- AC 1-4 (Harbor project, .woodpecker.yaml, Dockerfile, Woodpecker activation) -- agent-verifiable via API/file checks
- AC 5-6 (terraform services block, ArgoCD app) -- agent-verifiable via file diff and ArgoCD API
- AC 7 (k8s manifests reference Harbor image) -- agent-verifiable via file content check
- AC 8 (both funnel ingresses preserved) -- [BODY] This is the most complex criterion. The
westsidekingsandqueensfunnel was created viakubectl apply(see docs/consolidation.md). When terraform creates the ArgoCD app, the deployment manifests need to include this second ingress OR it will be lost. The file targets do not mention creating a second ingress manifest. Recommend adding explicit file target for the westsidekingsandqueens funnel ingress in k8s prod manifests. - AC 9 (docker-entrypoint runs db:prepare) -- already satisfied, verified in code
- AC 10 (first pipeline builds and deploys) -- manual verification needed post-implementation
Blast Radius
- The
westsidekingsandqueens-funnelingress was manually created (kubectl apply) and is NOT managed by ArgoCD or terraform. When this ticket transitions westside-ror to ArgoCD management, the ArgoCD app will only sync what is in the deployment manifests. If the funnel ingress manifest is not included, thewestsidekingsandqueensURL will be lost. This is the highest-risk item. - The current dev overlay (
k8s/dev.yaml) contains hardcoded secrets (POSTGRES_PASSWORD, SECRET_KEY_BASE). These should NOT be committed to prod manifests. The ticket correctly says to keep dev.yaml as-is. - The external CNPG database connection (pal-e-postgres-rw.postgres.svc:5432, database: basketball) must be preserved in the prod manifests. The current dev.yaml references this via env vars -- prod manifests will need equivalent secret references.
- No other services are affected -- this is a new pipeline for an existing service.
Decomposition Assessment
5-minute rule assessment:
- File targets: 4 files in westside-ror + 1 in pal-e-services = 5 files across 2 repos
- Acceptance criteria: 10 items
- Estimated agent work: >5 minutes (Harbor project creation, Woodpecker activation, terraform apply, ArgoCD sync, pipeline validation)
- However, several AC items require manual admin operations (Harbor project creation, Woodpecker repo activation, terraform apply) that cannot be done by a code agent alone.
NEEDS DECOMPOSITION -- 10 AC across 2 repos with manual admin steps. However, the decomposition is natural: (1) code changes PR (Dockerfile, .woodpecker.yaml, k8s manifests), (2) infra provisioning (Harbor, Woodpecker, terraform), (3) validation. Route to
skill-decompose-ticket.Recommendation
[BODY]Add explicit file target forwestsidekingsandqueensfunnel ingress manifest in k8s prod directory -- without it, ArgoCD sync will drop the second hostname.[BODY]Add file target for Stripe-related env vars/secrets in prod manifests (STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, etc.) -- these are needed for the Stripe features to actually work in prod.[SCOPE]Create project pageproject-westside-rorin pal-e-docs with user-stories section includingci-pipelinestory.[SCOPE]Create architecture notearch-ci-cddocumenting the platform CI/CD pipeline pattern.[DECOMPOSE]10 AC across 2 repos with manual admin operations. Route toskill-decompose-ticketfor sub-ticket creation: (1) code changes PR, (2) infra provisioning, (3) end-to-end validation.
-
Review: Port multi-step registration form from westside-app (re-review)
review-1370-2026-06-06-r2Verdict: APPROVED
Re-review after refinement. All [BODY] findings from
review-1370-2026-06-06have been addressed. Remaining items are [SCOPE] infrastructure recommendations only.Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, discovered during session review
- [x] Repo — ldraney/westside-ror
- [x] User Story — well-formed (As a parent / I want to register / So that I can complete registration, waiver, and payment)
- [x] Context — thorough: describes old SvelteKit 4-step flow, current Rails state, existing Registration model columns, existing Parent waiver fields
- [x] File Targets — present with create/modify/don't-touch sections, all verified accurate
- [x] Acceptance Criteria — 10 criteria listed
- [x] Test Expectations — system and unit tests specified with run command
- [x] Constraints — patterns, references, design language, model reuse constraints specified
- [x] Checklist — present
- [x] Related — present (project-westside-ror, westside-app, #39)
Traceability
- [x] story:consolidation label — present on board item
- [ ] story note MISSING — [SCOPE]
project-westside-rornote does not exist in pal-e-docs; cannot verify user story entry. Create project page with user-stories section including "consolidation" story. (Carried forward from R1) - [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] No
arch-railsnote found in pal-e-docs. Create architecture note for Rails component. (Carried forward from R1) - [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/westside-ror/issues/38, open
File Targets
Files to create (verified do not exist yet):
- [x]
app/views/public/register.html.erb— does not exist, directoryapp/views/public/confirmed present - [x]
app/javascript/controllers/registration_progress_controller.js— does not exist; follows existing Stimulus pattern (program_controller.js, inline_fee_controller.js). R1 FIX: now listed in file targets. - [x]
app/javascript/controllers/age_gate_controller.js— does not exist; follows existing Stimulus pattern. R1 FIX: now listed in file targets.
Files to modify (verified exist):
- [x]
config/routes.rb— exists (47 lines); no register routes present yet; public routes followget "name" => "public#action"pattern - [x]
app/controllers/public_controller.rb— exists (79 lines); no register or create_registration actions yet - [x]
app/models/registration.rb— exists withbelongs_to :tenantandbelongs_to :player; correctly listed as "modify" to add validations. R1 FIX: changed from "create" to "modify". - [x]
app/views/welcome/index.html.erb— exists; hero CTA at line 13 currently links to/teams, confirmed needs change to/register - [x]
app/assets/stylesheets/application.css— exists (1709 lines)
Files NOT to touch (verified correct):
- [x]
app/views/public/_interest_form.html.erb— exists, correctly excluded - [x] Stripe webhook controller — already working (PR #31 merged)
- [x]
db/schema.rb— registrations table has: amount_cents, payment_status (enum: pending/paid/refunded/failed), player_id, registration_type, signup_method, stripe_checkout_session_id, stripe_payment_intent_id, tenant_id. Parents table has: waiver_signed, waiver_signed_at, waiver_signed_ip. R1 FIX: no spurious migration file target.
Repo Placement
OK — issue filed on ldraney/westside-ror, all file targets within that repo. westside-app is read-only source reference.
Dependencies
- Stripe webhook infrastructure (PR #31) — merged, in place
- Existing Stimulus patterns — program_controller.js and inline_fee_controller.js in app/javascript/controllers/
- Player model has
has_many :registrations; Tenant model hashas_many :registrations - Parent model has waiver fields and
has_many :players— R1 FIX: issue now documents that create_registration should update Parent waiver fields - Board item #1371 (feature parity audit spike) — same story:consolidation, in backlog. Not blocking.
- No items in in_progress block this ticket
Acceptance Criteria
10 acceptance criteria — assessment:
- 8 of 10 are objectively verifiable by an agent (route renders, form sections present, age gate toggles, hero CTA link, Stripe redirect, progress bar)
- "Matching the old SvelteKit flow" — subjective but the 536-line Svelte source serves as reference spec
- "Mobile-first and matches existing site design" — visual assessment, testable via screenshot comparison
- Stripe test mode configuration not explicitly documented in constraints — minor gap, agent can infer from existing webhook setup
Blast Radius
- Parent model waiver fields — now documented in issue; create_registration will update waiver_signed, waiver_signed_at, waiver_signed_ip
- Interest form on /teams stays as-is (correctly documented)
- No other controllers or views reference /register currently
- Registration model associations (Player has_many, Tenant has_many) must be respected — documented in constraints
- paymentstatus enum (pending/paid/refunded/failed) already exists in DB — no migration needed for payment_status column
Decomposition Assessment
10 AC, 7+ file targets, estimated 15-25 min agent work. Exceeds 5-minute rule thresholds. Previous review flagged [DECOMPOSE]; user acknowledged but explicitly deferred decomposition. Not blocking approval — the issue body is complete and actionable as a single unit of work, though an implementing agent may need extended time.
R1 Findings Resolution
R1 Finding Type Status registration.rb listed as "create" not "modify" [BODY] RESOLVED — now under "Files to modify" Spurious migration file target [BODY] RESOLVED — removed; db/schema.rb listed as "do not touch" Missing Stimulus controller file targets [BODY] RESOLVED — both controllers now listed under "Files to create" Parent waiver fields undocumented [BODY] RESOLVED — documented in Context and File Targets sections Create project-westside-ror page [SCOPE] OPEN — project page still does not exist Create arch-rails note [SCOPE] OPEN — architecture note still does not exist Decomposition needed [DECOMPOSE] DEFERRED — acknowledged by user, not blocking Recommendations
- [SCOPE] Create project page
project-westside-rorwith user-stories section including "consolidation" story. (Carried forward from R1 — does not block implementation) - [SCOPE] Create architecture note
arch-railsfor the Rails component. (Carried forward from R1 — does not block implementation)
No [BODY] or [LABEL] recommendations remain. Issue body is complete and accurate.
-
Review: Port multi-step registration form from westside-app
review-1370-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone, discovered during session review
- [x] Repo — ldraney/westside-ror
- [x] User Story — present and well-formed
- [x] Context — thorough description of old SvelteKit flow and current state
- [x] File Targets — present with create/modify/don't-touch sections
- [x] Acceptance Criteria — 10 criteria listed
- [x] Test Expectations — system and unit tests specified
- [x] Constraints — patterns, references, and design language specified
- [x] Checklist — present
- [x] Related — present
Traceability
- [x] story:consolidation label — present on board item
- [ ] story note MISSING — [SCOPE] project-westside-ror note does not exist in pal-e-docs; cannot verify user story entry in user-stories section. Create project page with user stories section.
- [x] arch:rails label — present on board item
- [ ] arch note MISSING — [SCOPE] No arch-rails note found in pal-e-docs. Create architecture note arch-rails for Rails component.
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/westside-ror/issues/38, open
File Targets
- [x]
config/routes.rb— verified exists; no register routes present yet, ready for modification - [x]
app/controllers/public_controller.rb— verified exists; no register/create_registration actions yet - [x]
app/views/welcome/index.html.erb— verified exists; hero CTA currently links to /teams (line 13), confirmed needs change - [x]
app/assets/stylesheets/application.css— verified exists; 1709 lines currently - [x]
app/views/public/_interest_form.html.erb— verified exists; correctly listed as "do not touch" - [ ]
app/models/registration.rb— ISSUE: issue says "create" but file already exists withbelongs_to :tenantandbelongs_to :player. The registrations table already exists in the schema with columns: amount_cents, payment_status, player_id, registration_type, signup_method, stripe_checkout_session_id, stripe_payment_intent_id, tenant_id. [BODY] Change from "create" to "modify" and document which columns/validations to add. - [ ]
db/migrate/*_create_registrations.rb— ISSUE: registrations table already exists. Migration should add missing columns (e.g., waiver fields, promo code) rather than create table. [BODY] Rename to "add registration form fields" migration. - [x]
app/views/public/register.html.erb— confirmed does not exist yet, correct to create - [x] westside-app source files — verified:
+page.svelte(536 lines) andapp.cssboth exist at referenced paths
Repo Placement
OK — issue is filed on ldraney/westside-ror and all file targets are within that repo. The westside-app reference is read-only source material, not a target.
Dependencies
- Stripe webhook infrastructure (PR #31) — merged, in place. Webhook controller handles checkout.session.completed.
- Existing Stimulus patterns — program_controller.js and inline_fee_controller.js provide patterns to follow.
- Board item #1371 (Spike: audit westside-app vs westside-ror feature parity) — same story:consolidation label, in backlog. Not a blocking dependency but related; the audit spike would inform whether this registration port is complete.
- No items in in_progress block this ticket.
- Player model already has has_many :registrations association.
- Parent model has waiver_signed, waiver_signed_at, waiver_signed_ip fields — waiver may need to update parent record, not just registration.
Acceptance Criteria
10 acceptance criteria — mostly verifiable by an agent, but some concerns:
- "Matches the old SvelteKit flow" — subjective without pixel-level spec; the 536-line Svelte source is the reference but visual parity is hard to test automatically.
- "Mobile-first and matches existing site design" — again subjective; testable only via screenshot comparison.
- Stripe checkout redirect testing requires Stripe test mode configuration — not specified in constraints.
- "Progress bar tracks current section via scroll position" — requires a new Stimulus controller (not listed in file targets). [BODY] Add
app/javascript/controllers/registration_progress_controller.jsto file targets. - "Age gate toggles" — requires another Stimulus controller. [BODY] Add
app/javascript/controllers/age_gate_controller.jsto file targets.
Blast Radius
- Parent model has waiver fields (waiver_signed, waiver_signed_at, waiver_signed_ip) — registration waiver should update these. Not mentioned in issue.
- The interest form on /teams stays as-is (correctly noted in issue).
- No other controllers or views reference /register currently.
- The registrations table is already referenced by Player (has_many) and Tenant (has_many) — new registration creation flow must respect these associations.
Decomposition Assessment
NEEDS DECOMPOSITION — route to skill-decompose-ticket.
- 10 acceptance criteria (threshold: >5)
- 7+ file targets to create/modify across views, models, controllers, JS, CSS, migrations, routes
- Estimated agent work: 15-25 minutes (port 536-line Svelte component, port ~500 lines CSS, create 2+ Stimulus controllers, add model validations, add routes, add controller actions, write tests)
- Natural decomposition into: (1) route + controller + basic view, (2) form UI with Stimulus controllers, (3) waiver section, (4) Stripe payment integration, (5) CSS port, (6) hero CTA update + tests
Recommendations
- [BODY] Fix file target:
app/models/registration.rb— change from "create" to "modify"; document which validations and columns to add to existing model/table. - [BODY] Fix file target:
db/migrate/*_create_registrations.rb— rename to "add registration form fields" migration since table already exists. - [BODY] Add missing file targets:
app/javascript/controllers/registration_progress_controller.jsandapp/javascript/controllers/age_gate_controller.js(or a combinedregistration_controller.js). - [BODY] Document that parent model waiver fields (waiver_signed, waiver_signed_at, waiver_signed_ip) should be updated during registration waiver step.
- [SCOPE] Create project page
project-westside-rorwith user-stories section including "consolidation" story. - [SCOPE] Create architecture note
arch-railsfor the Rails component. - [DECOMPOSE] 10 AC, 7+ files, estimated 15-25 min agent work. Route to skill-decompose-ticket for sub-ticket creation.
-
Review: Spike: audit westside-app vs westside-ror feature parity
review-1371-2026-06-06Verdict: READY
Spike scope is solid. The question is clear, the time-box is appropriate, both codebases exist locally for comparison, and the deliverable (audit checklist, no code) fits a single agent pass. The traceability gaps below are pre-existing project-level issues already flagged in prior reviews — they do not block this spike.
Template Completeness
- [x] Type — "Spike"
- [x] Lineage — "Standalone — discovered during session when the registration form was found missing"
- [x] Repo —
ldraney/westside-ror - [x] Question — Clear top-level question with 6 sub-areas (routes, forms, content, styles, JS behavior, API integrations)
- [x] Deliverables — Present, describes checklist output. Minor format deviation: uses paragraph instead of template's checkbox format with explicit
docs/{topic}.mdartifact, but intent is equivalent for a spike that produces findings rather than an architecture doc. - [x] Time-box — "2 hours"
- [x] Related — References #38 (registration form port) and project-westside-ror
- [x] Checklist — Extra section not in template, but harmless (duplicates Deliverables intent)
Traceability
- [x] story:consolidation label — present on board item
- [ ] story note MISSING —
project-westside-rorproject page does not exist in pal-e-docs, so user story cannot be verified. This is a known gap flagged in review-1367-2026-06-06 and review-1367-2026-06-06-r2. [SCOPE] Createproject-westside-rorproject page with user-stories section. - [x] arch:rails label — present on board item
- [ ] arch note MISSING — no
arch-railsnote exists in pal-e-docs. However, "rails" is the framework itself, not a custom architecture component. For a spike that audits feature parity, this is acceptable — no custom architecture decision document is expected. [SCOPE] Consider whetherarch-railswarrants a dedicated note or should be renamed to a more specific component label. - [x] Forgejo issue — #39, open, body well-formed
File Targets
N/A — spike type. No file targets expected. The issue correctly does not list file targets.
However, verified that both codebases are available locally for the audit agent:
- [x]
/home/ldraney/westside-ror/— Rails app with 7 public routes, admin namespace, webhooks, emails - [x]
/home/ldraney/westside-app/— SvelteKit app (archived) with ~35 route files across (app) and (public) groups - [x]
/home/ldraney/westside-ror/docs/consolidation.md— existing consolidation doc documents what was killed, what survives, and open items
Repo Placement
OK. Issue filed on
ldraney/westside-rorwhich is the surviving app. The spike needs to read bothwestside-app(archived SvelteKit) andwestside-ror(Rails), but both are available locally. No cross-repo issue needed — the audit output belongs in westside-ror.Dependencies
- #38 (Port multi-step registration form) — board item 1370, backlog, 8 points. This is a known gap that prompted the spike. The spike should discover this and potentially other gaps. No blocking dependency — the spike informs #38, not the other way around.
- #33 (Consolidation spike) — closed, done. Prior spike that drove the consolidation. This spike is a follow-up audit after consolidation is complete.
- No blockers — no items in in_progress or next_up block this spike. The two in_progress items (#2 tournament payments, #13 Queens Phoenix trip) are unrelated.
Acceptance Criteria
The issue uses a "Checklist" section with 2 items: (1) Audit complete, (2) Findings documented. These are appropriate for a spike — the deliverable is knowledge, not code. An agent can verify completion by checking whether the audit findings exist in issue comments or a linked note.
The "Deliverables" section adds specificity: "A checklist of inconsistencies with severity (missing feature vs. cosmetic difference vs. content drift), grouped by page/route." This is testable — the output must be a structured checklist with severity classification.
Blast Radius
Low. This is a read-only audit — no code changes. The findings will generate follow-up tickets. No downstream consumers are affected by the spike itself.
Note: the
westside-apprepo is archived on Forgejo, so the local copy at/home/ldraney/westside-app/is the source of truth for the audit. The agent should not attempt to clone or pull from the archived remote.Decomposition Assessment
No decomposition needed. Single repo, 2-hour time-box, read-only audit. The deliverable is a checklist document, not code changes. Well within a single agent pass. 0 file targets to modify, 2 acceptance criteria, estimated agent work under 5 minutes for the review (the spike execution itself is time-boxed at 2 hours but that is execution, not scope review).
Recommendation
- [SCOPE] Create
project-westside-rorproject page with user-stories section — pre-existing gap, not blocking this spike. - [SCOPE] Evaluate whether
arch-railsneeds a dedicated architecture note or if the label should reference something more specific (e.g.,arch-westside-ror) — pre-existing gap, not blocking this spike.
No action needed to unblock this spike. READY to move to next_up.
-
Review: Decommission basketball-api and westsidekingsandqueens namespaces (re-review)
review-1367-2026-06-06-r2Verdict: APPROVED
Re-review after NEEDS_REFINEMENT. The issue body was substantially rewritten to address all critical findings from
review-1367-2026-06-06. The two blocking recommendations ([BODY] and [LABEL]) are resolved. Two [SCOPE] items remain but are not blockers for this ticket's execution.Previous Review Findings — Resolution Status
- [x]
[BODY]Addk3s.tfvarsto file targets — RESOLVED. Now the primary file target with specific line references for bothservicesandclientsblocks. - [x]
[LABEL]Changestory:admin-roster-reporttostory:consolidation— RESOLVED. Board item #1367 now has labelstory:consolidation. - [ ]
[SCOPE]Createproject-westside-rorproject page — STILL MISSING. Noproject-westside-rornote exists in pal-e-docs. Not a blocker for ticket execution; the story label is meaningful without it. - [ ]
[SCOPE]Createarch-westside-rorarchitecture note — STILL MISSING. Noarch-westside-rornote exists in pal-e-docs. Not a blocker for this infra teardown ticket. - [x]
[DECOMPOSE]Previous review recommended decomposition — REASSESSED below. The rewritten issue correctly reframes all work as terraform-driven, making it a single coordinated operation rather than 5 separate system touches.
Template Completeness
- [x] Type — Feature
- [x] Lineage — references #33 consolidation spike, #35, #36 as prerequisites
- [x] Repo — correctly identifies
pal-e-services(terraform),pal-e-deployments(overlays), Forgejo admin (archival) - [x] User Story — clear operator perspective
- [x] Context — explains terraform as source of truth, why manual kubectl is wrong
- [x] File Targets — specific files with line references, plus explicit "do NOT touch" list
- [x] Acceptance Criteria — 12 items
- [x] Test Expectations — 5 verification commands
- [x] Constraints — terraform-first, review plan before apply, archive-not-delete, keep realm
- [x] Checklist — two PRs (pal-e-services, pal-e-deployments) + tofu plan output
- [x] Related — links to project and prerequisite issues
Traceability
- [x] story:consolidation label — matches decommission/cleanup scope
- [ ] story note NOT verified — no
project-westside-rornote with user-stories section exists. [SCOPE] Create project pageproject-westside-rorwith user-stories section (deferred, not a blocker). - [x] arch:westside-ror label — present on board item
- [ ] arch note NOT verified — no
arch-westside-rornote exists. [SCOPE] Create architecture notearch-westside-ror(deferred, not a blocker). - [x] Forgejo issue — #37, open, valid
File Targets
- [x]
pal-e-services/terraform/k3s.tfvars— verified exists (10k).basketball-apiservice block at lines 200-208.westsidekingsandqueensservice block at lines 209-217. Both confirmed present. - [x]
pal-e-services/terraform/k3s.tfvarsclients —westside-landingblock (HCL key) at lines 73-89 withclient_id = "westside-app".westside-spablock at lines 90-109. Both confirmed present. - [x]
pal-e-deployments/overlays/basketball-api/— verified exists (prod/ subdirectory with postgres.yaml, secrets, etc.) - [x]
pal-e-deployments/overlays/westsidekingsandqueens/— verified exists (dev/ and prod/ subdirectories)
Minor line reference inaccuracies (not blocking):
- Issue says
basketball-apiat lines 200-207 — actual block includescmp_pluginfield, runs to line 208 - Issue says
westsidekingsandqueensat lines 209-216 — actual block runs to line 217 - Issue says
westside-appat lines 74-89 — the HCL key iswestside-landing(line 73), inner content 74-89 is correct. Agent implementing this should remove the entire block including the key line. - Issue says
westside-spaat lines 91-107 — actual block starts at line 90, includes extrahttp://localhostweb_origin, closing brace at line 109
These are off-by-one or off-by-two errors typical of line references. The blocks are unambiguously identifiable by their HCL keys and the agent will handle them correctly.
Repo Placement
Issue filed on
ldraney/westside-ror. Work spanspal-e-services(terraform) andpal-e-deployments(overlay cleanup). The issue correctly identifies both repos and specifies separate PRs for each. Filing on westside-ror is acceptable since this is the consolidation project's home repo and the ticket coordinates cross-repo work.Dependencies
- [x] #35 (data migration) — board item 1365, column: done. Prerequisite satisfied.
- [x] #36 (URL cutover) — board item 1366, column: done. Prerequisite satisfied.
- [x] #33 (consolidation spike) — board item 1362, column: done. Parent work complete.
- [x] #7 (Keycloak auth) — correctly noted as unblocked by this work; realm is preserved.
- No blocking items in
in_progress.
Acceptance Criteria
12 acceptance criteria. Assessment:
- AC 1-4 (remove tfvars entries) — directly verifiable by diffing the PR
- AC 5-6 (tofu plan/apply) — verifiable by operator running commands; plan output included in PR per checklist
- AC 7 (kubectl get ns) — verifiable post-apply
- AC 8-9 (repo archival) — manual Forgejo admin action, verifiable
- AC 10 (Tailscale nodes) — issue now correctly notes "may happen automatically via funnel teardown." Acceptable.
- AC 11 (PVC noted) — informational, not a pass/fail criterion. Backup location documented.
- AC 12 (overlay directories removed) — verifiable via PR diff
All criteria are clear and verifiable. The previous concern about Tailscale being unautomatable is addressed by the "may happen automatically" qualifier.
Blast Radius
- pal-e-services docs —
README.md(line 65),CLAUDE.md(line 12),SERVICE_ONBOARDING.md(17+ references) all mentionbasketball-apias examples. These are documentation references, not functional. Low priority cleanup, not required for this ticket. - pal-e-deployments/overlays/dev-tunnel/README.md — line 27 references
basketball-api.basketball-api.svc.cluster.local:8000. Minor doc cleanup. - pal-e-deployments/overlays/westside-ror/README.md — line 3 mentions "replacing basketball-api and westsidekingsandqueens." Historical reference, no action needed.
- No code-level blast radius — terraform handles all resource teardown cleanly.
Decomposition Assessment
Previous review recommended decomposition (9 AC across 5 systems). Reassessment: No decomposition needed.
The rewritten issue correctly reframes the work as terraform-driven:
- PR 1: Edit
k3s.tfvars(remove 4 blocks from 1 file), runtofu plan, include output — single agent pass, <5 min - PR 2:
git rmtwo overlay directories in pal-e-deployments — trivial, <2 min - Manual steps:
tofu apply(operator), repo archival (operator), Tailscale cleanup (may auto-resolve) — these are operator actions, not agent work
The agent work is 2 simple PRs touching 3 files total. Well within the 5-minute rule. The 12 AC count is high but most are verification steps after
tofu apply, not implementation work.Recommendation
[SCOPE]Create project pageproject-westside-rorwith user-stories section (deferred — does not block ticket execution).[SCOPE]Create architecture notearch-westside-ror(deferred — does not block ticket execution).
No
[BODY],[LABEL], or[DECOMPOSE]recommendations. Ticket is ready for implementation. - [x]
-
Review: Decommission basketball-api and westsidekingsandqueens namespaces
review-1367-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — references #33 consolidation spike
- [x] Repo — specifies pal-e-deployments
- [x] User Story
- [x] Context — describes what's no longer needed after #35/#36
- [x] File Targets — pal-e-deployments overlays + Forgejo repo archival
- [x] Acceptance Criteria — 9 items
- [x] Test Expectations — kubectl verification commands
- [x] Constraints — prerequisite gates, PVC retention, archive-not-delete
- [x] Checklist
- [x] Related — links to #33, #35, #36
Traceability
- [ ] story:admin-roster-report label — MISMATCH. This is a namespace decommission ticket, not part of the admin roster report story. The story label should reflect the consolidation effort (e.g.,
story:consolidationorstory:infra-cleanup). [LABEL] Change story label to match actual work scope. - [ ] story note MISSING — No project page
project-westside-rorexists in pal-e-docs to verify any story entry. [SCOPE] Create project pageproject-westside-rorwith user-stories section. - [ ] arch note MISSING —
arch:westside-rorlabel present but noarch-westside-rornote found in pal-e-docs. [SCOPE] Create architecture notearch-westside-ror. - [x] Forgejo issue — #37, open, valid
File Targets
- [x]
pal-e-deployments/overlays/basketball-api/— verified: exists (6 files including kustomization.yaml, deployment-patch.yaml, postgres.yaml, pvc.yaml, secrets) - [x]
pal-e-deployments/overlays/westsidekingsandqueens/— verified: exists (prod: 4 files, dev: 4 files) - [x] westside-ror codebase — verified: only doc references (README.md, docs/db-reconciliation.md), no code changes needed. Correct.
- [ ]
pal-e-services/terraform/k3s.tfvars— MISSING from file targets. Containsbasketball-apiservice entry (lines 200-206),westsidekingsandqueensservice entry (lines 209-215), andwestside-spaKeycloak client (lines 90-105 with redirect URIs). If overlays are deleted but terraform entries remain,terraform applywill fail or attempt to recreate resources. [BODY] Addpal-e-services/terraform/k3s.tfvarsto file targets: remove basketball-api + westsidekingsandqueens service entries and westside-spa Keycloak client block.
Repo Placement
Issue filed on
ldraney/westside-rorbut all work happens inpal-e-deployments(manifest removal),pal-e-services(terraform cleanup), Forgejo admin (repo archival), Keycloak admin, and Tailscale admin console. The issue body correctly identifiespal-e-deploymentsas the repo, but the Forgejo issue itself is onwestside-ror. Acceptable since this is the consolidation project's repo and the PR checklist says "PR opened (on pal-e-deployments)." However, pal-e-services is also affected (see file targets).Dependencies
- [x] #35 (data migration) — board item 1365, column: done. Prerequisite satisfied.
- [x] #36 (URL cutover) — board item 1366, column: done. Prerequisite satisfied.
- [x] #33 (consolidation spike) — board item 1362, column: done. Parent work complete.
- No blocking items in
in_progressfor this work.
Acceptance Criteria
9 acceptance criteria. Most are verifiable by an agent via kubectl commands. Concerns:
- "Orphaned Tailscale nodes cleaned up in Tailscale admin console" — requires Tailscale admin UI access, not automatable by an agent. Manual step.
- "Sidecar postgres PVC preserved for 30 days" — this is a deferred action, not verifiable at implementation time. Needs a follow-up ticket or calendar reminder for day-30 deletion.
- "Keycloak westside-spa client disabled or deleted" — needs to specify whether this is via Keycloak admin UI or terraform (answer: terraform, since it's in k3s.tfvars).
Blast Radius
- pal-e-services/terraform — The
servicesmap ink3s.tfvarsdrives Argo CD applications, Harbor robot accounts, and Kubernetes namespaces via terraform. Removing overlays without removing the terraform entries will cause plan/apply drift or failures. This is the most critical gap. - pal-e-deployments README and dev-tunnel README reference these namespaces — minor doc cleanup.
- westside-ror README/docs — historical references only, no action needed.
- pal-e-services README, SERVICE_ONBOARDING.md, CLAUDE.md — reference basketball-api, minor doc cleanup.
Decomposition Assessment
9 AC across 5 systems (k8s cluster, pal-e-deployments, pal-e-services/terraform, Forgejo admin, Tailscale admin). Estimated agent work exceeds 5 minutes. However, the nature of this work is mostly imperative commands (kubectl delete, git rm, terraform changes) rather than code authoring. Some steps (Tailscale admin, PVC retention scheduling) are manual and cannot be agent-executed. Recommendation: NEEDS DECOMPOSITION — split into: (1) terraform cleanup PR on pal-e-services, (2) overlay removal PR on pal-e-deployments, (3) manual checklist for Forgejo archival + Tailscale cleanup + PVC retention timer. Route to
skill-decompose-ticket.Recommendation
[BODY]Addpal-e-services/terraform/k3s.tfvarsto File Targets — removebasketball-apiservice entry,westsidekingsandqueensservice entry, andwestside-spaKeycloak client block.[LABEL]Changestory:admin-roster-reporttostory:consolidationorstory:infra-cleanup— current label is a mismatch for decommission work.[SCOPE]Create project pageproject-westside-rorwith user-stories section.[SCOPE]Create architecture notearch-westside-ror.[DECOMPOSE]9 AC across 5 systems. Route toskill-decompose-ticketfor sub-ticket creation: (1) pal-e-services terraform cleanup, (2) pal-e-deployments overlay removal, (3) manual ops checklist (Forgejo archival, Tailscale nodes, PVC retention timer).
-
Review 2: Commit prod deployment manifests
review-1358-2026-06-06-v2Verdict: READY
Re-review of board item #1358 after refinement. Previous review
review-1358-2026-06-06returned NEEDS_REFINEMENT with 3[BODY]fixes and 1[SCOPE]recommendation. All 3 body fixes have been addressed. The[SCOPE]item (missing project page) is pre-existing platform documentation debt, not a ticket scope problem.Previous Recommendations Resolved
[BODY]Clarify service.yaml file target -- FIXED: removed ambiguousservice.yamlentirely. File targets now list onlykustomization.yamlanddeployment-patch.yaml.[BODY]Add kubectl command for live spec capture -- FIXED: issue now includeskubectl get deployment westside-ror -n westside-ror -o yaml > /tmp/westside-ror-live.yaml.[BODY]Add explicit bases/standard requirement -- FIXED: issue now states "The prod overlay MUST usebases/standard(not standalone resources like the dev overlay)" and referencesbasketball-api/prod/kustomization.yamlas canonical example.[SCOPE]Createproject-westside-rorproject page -- NOT ADDRESSED (human decision, carried forward as non-blocking).
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- spike #22, prerequisite for #27
- [x] Repo -- ldraney/pal-e-deployments (primary), ldraney/westside-ror (tracking)
- [x] User Story -- present and well-formed
- [x] Context -- thorough, includes live vs committed comparison with specific env vars and patterns
- [x] File Targets -- 2 files to create, clear do-not-touch list, no ambiguity
- [x] Acceptance Criteria -- 7 items, all testable
- [x] Test Expectations -- kustomize build command provided, diff against live deployment
- [x] Constraints -- explicit bases/standard requirement, references canonical example
- [x] Checklist -- present
- [x] Related -- lists project and related issues (#27, #24)
All required Feature template sections present and complete.
Traceability
- [x] story:subscription-links label -- present on board item
- [ ] story note MISSING -- no
project-westside-rorproject page exists in pal-e-docs. Acceptable: user story is fully stated inline in the issue body. Per precedent (review-1356-2026-06-06), not blocking. [SCOPE] Createproject-westside-rorproject page with user-stories section (low priority, carried from v1). - [x] arch:kustomize label -- present on board item
- [x] arch note verified --
convention-kustomize-overlayexists in pal-e-docs (convention note; kustomize overlays are a convention, not a diagrammable arch component, per precedentreview-1044-2026-04-21) - [x] Forgejo issue -- ldraney/westside-ror#28, open
File Targets
- [x]
overlays/westside-ror/prod/kustomization.yaml-- verified: directory does NOT exist yet (correct, file to create).bases/standard/exists with deployment.yaml, service.yaml, hpa.yaml, kustomization.yaml, networkpolicy.yaml, servicemonitor.yaml. Reference patternbasketball-api/prod/kustomization.yamlverified: uses../../../bases/standard, JSON patches to renameapp, deployment-patch.yaml. - [x]
overlays/westside-ror/prod/deployment-patch.yaml-- verified: file to create. Reference patternbasketball-api/prod/deployment-patch.yamlverified: shows env vars, secretRef, container spec patches. - [x]
overlays/westside-ror/dev/-- verified: exists with deployment.yaml, service.yaml, kustomization.yaml, ingress.yaml. Issue correctly says "do not touch".
Repo Placement
OK. Issue filed on
ldraney/westside-ror(tracking), work targetsldraney/pal-e-deployments(primary). Explicitly documented in Repo section. PR should be opened againstpal-e-deployments.Dependencies
- Upstream: spike #22 (done) -- no blocker
- Downstream: #27 (Stripe webhook needs STRIPE_WEBHOOK_SECRET in deployment config) -- this ticket is a prerequisite. Documented.
- Downstream: #24 (editable fees, safe deploys needed) -- documented.
- Board state: No blockers in
in_progress. Items #2 and #13 are in progress but unrelated (tournament payments/email).
Acceptance Criteria
7 criteria, all verifiable:
- [x] AC1: prod/ overlay exists -- verifiable with
ls - [x] AC2: kustomization.yaml references
../../../bases/standard-- verifiable withgrep - [x] AC3: JSON patches rename base
app-- verifiable in YAML - [x] AC4: deployment-patch.yaml matches live pod spec -- verifiable with kubectl diff (issue now provides capture command)
- [x] AC5:
kustomize buildproduces valid YAML -- verifiable with command - [x] AC6: diff between build output and live deployment shows no meaningful divergence -- verifiable with diff
- [x] AC7: Comment noting STRIPE_WEBHOOK_SECRET for #27 -- verifiable with grep
All criteria are testable by an agent with cluster access.
Blast Radius
Low. This is a "commit what's running" task -- no behavior change. The committed manifests will match the live pod. No sibling services affected. Dev overlay is explicitly excluded.
Decomposition Assessment
2 file targets in 1 repo (pal-e-deployments). 7 acceptance criteria (slightly above the 5 threshold but all are closely related verification steps for the same 2 files). Estimated agent work: ~3 minutes. No decomposition needed.
Recommendations
[SCOPE]Createproject-westside-rorproject page in pal-e-docs with a user-stories section containing the subscription-links story (carried from v1, non-blocking, low priority).
No
[BODY]or[LABEL]fixes needed. Ticket is ready for implementation. -
Review: Commit prod deployment manifests
review-1358-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- spike #22, prerequisite for #27
- [x] Repo -- ldraney/pal-e-deployments (primary), ldraney/westside-ror (tracking)
- [x] User Story -- present and well-formed
- [x] Context -- thorough, includes live vs committed comparison
- [x] File Targets -- present, lists create and do-not-touch files
- [x] Acceptance Criteria -- 5 items, all testable
- [x] Test Expectations -- kustomize build command provided
- [x] Constraints -- present and clear
- [x] Checklist -- present
- [x] Related -- lists project and related issues
All required Feature template sections present.
Traceability
- [x] story:subscription-links label -- present on board item
- [ ] story note MISSING -- no
project-westside-rorproject page exists in pal-e-docs at all. [SCOPE] Createproject-westside-rorproject page with user-stories section. - [x] arch:kustomize label -- present on board item
- [x] arch note verified --
convention-kustomize-overlayexists in pal-e-docs (convention note, not arch note, but this is correct -- kustomize overlays are a convention, not a diagrammable arch component per prior review precedentreview-1044-2026-04-21) - [x] Forgejo issue -- ldraney/westside-ror#28, open
File Targets
- [x]
overlays/westside-ror/prod/-- verified: directory does NOT exist yet (correct, these are files to create) - [x]
overlays/westside-ror/dev/-- verified: exists with deployment.yaml, service.yaml, kustomization.yaml, ingress.yaml. Issue correctly says "do not touch" - [ ] File targets list
service.yamlwith "if different from dev" qualifier -- ISSUE: the issue should clarify whether the prod service differs. Based on the basketball-api and believers-elite patterns, prod overlays use thebases/standardService (renamed via JSON patch) rather than a standalone service.yaml. The agent needs explicit guidance. [BODY] Clarify whetherservice.yamlis needed or if the base Service (renamed via JSON patch in kustomization.yaml) suffices -- per platform convention, prod overlays usebases/standardnot standalone resources.
Repo Placement
The issue is filed on
ldraney/westside-rorbut the work is inldraney/pal-e-deployments. The issue acknowledges this explicitly (Repo section says "primary: pal-e-deployments, tracking: westside-ror"). This is acceptable -- the tracking issue pattern is established practice. However, the PR should be opened againstpal-e-deployments, notwestside-ror.Dependencies
- Upstream: spike #22 (done per memory) -- no blocker
- Downstream: #27 (Stripe webhook needs STRIPE_WEBHOOK_SECRET in deployment config) -- this ticket is a prerequisite. Documented in issue.
- Downstream: #24 (editable fees, safe deploys needed) -- documented in issue.
- Board state: No blockers in
in_progress. Items #2 and #13 are in progress but unrelated (tournament payments/email).
Acceptance Criteria
- [x] AC1: prod/ overlay exists -- verifiable with
ls - [x] AC2: deployment patch matches live pod spec -- verifiable with diff
- [x] AC3: kustomize build produces valid YAML -- verifiable with command
- [ ] AC4: "deploying from committed manifests produces same pod spec as live" -- ISSUE: this is functionally a superset of AC2+AC3 but harder to verify without cluster access. The agent would need
kubectl get deployment -o yamloutput to diff against. The issue provides a good description of what's running (Context section) but the agent needs the actual live spec to diff. [BODY] Add a note that the live spec can be captured viakubectl get deployment westside-ror -n westside-ror -o yamland should be diffed againstkustomize buildoutput. - [x] AC5: STRIPE_WEBHOOK_SECRET placeholder -- verifiable in the YAML
Blast Radius
Low blast radius. This is a "commit what's running" task -- no behavior change. The only risk is if the committed manifests don't match reality and someone syncs ArgoCD, but that's exactly what this ticket prevents. No sibling services affected.
Note: the dev overlay uses a standalone structure (no
bases/standardreference), while the prod overlay should usebases/standardper platform convention. This is not a blast radius concern but an implementation detail the agent must get right.Decomposition Assessment
3 file targets in 1 repo (pal-e-deployments). 5 acceptance criteria. Estimated agent work: ~3 minutes. No decomposition needed. Well within the 5-minute rule.
Recommendations
[SCOPE]Createproject-westside-rorproject page in pal-e-docs with a user-stories section containing the subscription-links story.[BODY]Clarify theservice.yamlfile target: per platform convention (convention-kustomize-overlay), prod overlays referencebases/standardand rename via JSON patch. Remove "service.yaml -- if different from dev" and replace with guidance to use the base Service renamed via JSON patch, matching basketball-api/believers-elite patterns.[BODY]Add instruction for the agent to capture the live spec:kubectl get deployment westside-ror -n westside-ror -o yaml > /tmp/live-spec.yamlfor diffing againstkustomize buildoutput.[BODY]Add explicit note that the prod overlay must usebases/standard(unlike the dev overlay which uses standalone resources). Reference basketball-api and believers-elite as patterns.
-
Review: Stripe webhook for subscription status sync (re-review)
review-1357-2026-06-06-r2Verdict: APPROVED
Re-review of board item #1357 (Forgejo issue ldraney/westside-ror#27). Previous review
review-1357-2026-06-06returned NEEDS_REFINEMENT with 3[BODY]and 2[SCOPE]recommendations. All[BODY]items have been addressed in the updated issue.[SCOPE]items remain outstanding but are platform-level documentation tasks that do not block implementation.Previous Findings Disposition
- [x]
[BODY]Graceful handling of missing metadata -- FIXED. New AC #6 explicitly requires graceful handling of events with missing or unrecognized metadata. Context section now documents that Marcus created some payment links outside the app. Test Expectation #8 covers this case. - [x]
[BODY]Explicit idempotency AC -- FIXED. New AC #10: "Idempotent: processing the same event twice produces the same result without errors." Test Expectation #9: "processing the same event twice does not error or create duplicate state." Constraint section also restates this. - [x]
[BODY]Clarify #23 closed -- FIXED. Issue #23 is confirmed closed on Forgejo. Related section in #27 now states "(closed, replaced by #26 + #27)." - [ ]
[SCOPE]Createproject-westside-rorwith user-stories section -- STILL OUTSTANDING. Not a blocker for implementation. - [ ]
[SCOPE]Createarch-railsnote in pal-e-docs -- STILL OUTSTANDING. Not a blocker for implementation. In-repo architecture docdocs/stripe-subscription-architecture.mdcovers the webhook design in detail (Flow 3).
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- split from #23 (Sub-B: webhook + status sync)
- [x] Repo -- ldraney/westside-ror
- [x] User Story -- system actor, auto-updates roster report
- [x] Context -- explains gap, documents data format, addresses external links
- [x] File Targets -- 4 modify/create, 3 do-not-touch
- [x] Acceptance Criteria -- 10 criteria (up from 8, added graceful handling + idempotency)
- [x] Test Expectations -- 9 test cases + run command (up from 7, added missing-metadata + idempotency tests)
- [x] Constraints -- 5 constraints listed (includes idempotency)
- [x] Checklist -- standard 3-item
- [x] Related -- references project, companion tickets, spike, arch doc; #23 confirmed closed
Traceability
- [x] story:subscription-links label -- present on board item
- [ ] story note --
project-westside-rordoes not exist in pal-e-docs (404). Carried forward as non-blocking [SCOPE] item. - [x] arch:rails label -- present on board item
- [ ] arch note -- no
arch-railsnote in pal-e-docs. In-repo docdocs/stripe-subscription-architecture.mdcovers webhook design (Flow 3). Carried forward as non-blocking [SCOPE] item. - [x] Forgejo issue -- ldraney/westside-ror#27, state: open
File Targets
- [x]
config/routes.rb-- verified: exists (39 lines), no webhook route currently. Route addition straightforward. - [x]
app/controllers/webhooks_controller.rb-- correctly marked as NEW. Does not exist. No existingskip_forgery_protectionpatterns in codebase; new controller will need it. - [x]
app/services/stripe_client.rb-- verified: exists (127 lines). Uses raw net/http, no Stripe gem. Addingverify_webhook_signatureis consistent with existing patterns. - [x] Deployment config (env var STRIPE_WEBHOOK_SECRET) -- no existing references. New secret needed.
- [x] DB columns verified in schema.rb:
payment_links.paid_at(line 216) -- datetime, nullablepayment_links.stripe_payment_link_id(line 221) -- string, not nullplayers.stripe_subscription_id(line 267) -- string, nullableplayers.subscription_status(line 268) -- enum (active, past_due, canceled, none), default none
- [x] Enum values match AC:
subscriptionstatus= [active, past_due, canceled, none] (schema line 37)
Repo Placement
OK. Issue filed on ldraney/westside-ror, all file targets in that repo. Single-repo change.
Dependencies
- #24 (editable fees) -- no blocking dependency. Webhook does not require fee editing.
- #26 (copy links UI) -- companion ticket, explicitly independent.
- #22 (spike) -- closed. Produced architecture doc.
- #23 (original combined) -- confirmed closed on Forgejo. Housekeeping resolved.
- No items in
in_progressblock this ticket.
Acceptance Criteria
All 10 criteria are testable by an agent. Test expectations map cleanly to AC (9 test cases cover all 10 AC). Run command (
rails test) is valid. The two new additions (graceful handling AC #6, idempotency AC #10) close the gaps from the previous review.Blast Radius
subscription_statusread byadmin/roster_report_controller.rb(lines 14, 24, 29, 30). Webhook updates surface automatically in roster report -- desired effect, no code changes needed.paid_atread byStripeClient#db_payment_summary(lines 70, 84), used by payments dashboard. Same -- desired effect.skip_forgery_protectionscoped to new WebhooksController only. No global impact.- No other controllers or services reference these columns.
Decomposition Assessment
4 file targets in 1 repo. 10 AC, 9 test cases. Estimated agent work: ~8-10 minutes. Above the 5-minute threshold but all targets are tightly coupled in one repo -- decomposing would create artificial seams. Single agent pass is appropriate. No decomposition needed.
Recommendations
No blocking recommendations. Two carried-forward [SCOPE] items for platform documentation:
[SCOPE]Create project pageproject-westside-rorwith user-stories section including subscription-links story. (Non-blocking)[SCOPE]Create architecture notearch-railsin pal-e-docs, or reconsider label asarch:stripe. In-repo doc exists atdocs/stripe-subscription-architecture.md. (Non-blocking)
- [x]
-
Review: Copy-to-clipboard subscription links (UI)
review-1356-2026-06-06Verdict: READY
Template Completeness
- [x] Type — Feature
- [x] Lineage — Split from #23, depends on #24
- [x] Repo — ldraney/westside-ror
- [x] User Story — Marcus (admin) copy-to-clipboard workflow
- [x] Context — Thorough: spike #22 findings, existing state, dependency chain
- [x] File Targets — 3 files to modify, 2 exclusions documented
- [x] Acceptance Criteria — 7 criteria, all testable
- [x] Test Expectations — 2 unit tests, 1 integration test, run command
- [x] Constraints — Product reuse, raw net/http pattern, cents conversion
- [x] Checklist — Present
- [x] Related — Links to project, prerequisite, spike, and arch doc
Traceability
- [x] story:subscription-links label — present on board item
- [ ] story note MISSING — no project-westside-ror project page exists in pal-e-docs; no user-stories section to verify. Acceptable: the user story is fully stated inline in the issue body. [SCOPE] Create project page
project-westside-rorwith user-stories section (low priority, not blocking). - [x] arch:rails label — present on board item
- [ ] arch note MISSING — search for
arch-railsreturned no results. Acceptable: "rails" is the application framework, not a discrete architecture component. The actual architecture doc exists atdocs/stripe-subscription-architecture.mdin the repo and is referenced in the issue. [SCOPE] Consider creatingarch-stripenote in pal-e-docs to back the scope:stripe label (low priority, not blocking). - [x] Forgejo issue — ldraney/westside-ror#26, open
File Targets
- [x]
app/services/stripe_client.rb— verified: exists (3.6k). Currently has only GET methods (paginate, get). Addingcreate_subscription_linkrequires a new privatepostmethod. Correct target. - [x]
app/controllers/admin/roster_report_controller.rb— verified: exists (1.3k). Currently loads teams/players withincludes(players: :parent). Will need to add:payment_linksto the includes and instantiate StripeClient. Correct target. - [x]
app/views/admin/roster_report/index.html.erb— verified: exists (4.0k). Currently renders player rows with name/parent/phone/email/monthly/status columns. "Copy Link" button + JS clipboard logic will be added here. Correct target. - [x] Exclusions verified —
payments_controller.rbandwebhooks_controller.rbcorrectly excluded (separate concerns).
Repo Placement
Correct. Issue filed on
ldraney/westside-ror, all file targets are in the same repo. Single-repo change.Dependencies
- #24 (inline-editable monthly fee) — documented as prerequisite, confirmed still open. Payment link amount derives from
player.monthly_fee. Correctly identified. Board item #1334 is in backlog. - #27 (Stripe webhook) — correctly split out as separate ticket. Board item #1357 is in backlog.
- #23 (original combined ticket) — parent ticket, board item #1335 still in backlog. Should be closed/superseded once #26 and #27 replace it.
- Spike #22 — closed, findings documented in issue context.
Acceptance Criteria
7 criteria, all verifiable by an agent:
- [x] AC1: Copy Link button per row — testable via view rendering
- [x] AC2: Clipboard copy without navigation — testable via JS behavior
- [x] AC3: "Copied!" feedback for 2s — testable via JS
- [x] AC4: Subscription mode with correct price — testable via unit test on StripeClient
- [x] AC5: Metadata includes player_id, player_name, team — testable via unit test
- [x] AC6: Pre-fill parent email — testable via unit test
- [x] AC7: Links stored and reused — testable via integration test
Minor note: AC1 mentions "players with no parent email show 'No email' indicator" but per schema,
players.parent_idis NOT NULL andparents.emailis NOT NULL. Every player has a parent with an email. The "No email" edge case may never trigger in practice. Not blocking — the code can handle it defensively, but the agent should be aware.Blast Radius
PaymentLinkmodel is used by payments_controller (separate concern) — no conflict.- Unique constraint
uq_payment_links_player_product_tenanton[player_id, product_id, tenant_id]— sinceproduct_idis nullable, subscription links can coexist with one-time payment links for the same player. No conflict. - Adding a POST method to StripeClient is additive — no existing code affected.
payment_links.parent_idis NOT NULL — creating a payment link requires a parent record. This is fine since every player has a parent.- No other views or controllers reference clipboard or copy-link functionality.
Decomposition Assessment
3 file targets in 1 repo. 7 acceptance criteria (over 5 threshold but tightly coupled). All changes are in a single feature flow: service method + controller wiring + view rendering. Estimated agent work: ~4 minutes. No decomposition needed — this is a cohesive single-pass feature.
Recommendations
No blocking recommendations. Minor items for awareness:
- [SCOPE] Create project page
project-westside-rorwith user-stories section in pal-e-docs (low priority, does not block this ticket). - [SCOPE] Consider creating
arch-stripenote in pal-e-docs to back thescope:stripelabel (low priority, does not block this ticket). - [BODY] Minor: "No email" edge case in AC1 is impossible per current schema (
players.parent_id NOT NULL,parents.email NOT NULL). Agent should implement defensively but be aware this path may never trigger. Not worth changing the AC — defensive coding is fine.
-
Review: Stripe webhook for subscription status sync
review-1357-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- split from #23
- [x] Repo -- ldraney/westside-ror
- [x] User Story -- system actor, auto-updates roster
- [x] Context -- explains gap (no webhook endpoint, DB columns exist)
- [x] File Targets -- 4 modify/create, 3 do-not-touch
- [x] Acceptance Criteria -- 8 criteria
- [x] Test Expectations -- 7 test cases + run command
- [x] Constraints -- 5 constraints listed
- [x] Checklist -- standard 3-item
- [x] Related -- references project, companion tickets, spike, arch doc
Traceability
- [x] story:subscription-links label -- present on board item
- [ ] story note MISSING --
project-westside-rornote does not exist in pal-e-docs (404). [SCOPE] Create project pageproject-westside-rorwith user-stories section including subscription-links story. - [x] arch:rails label -- present on board item
- [ ] arch note MISSING -- no
arch-railsnote found in pal-e-docs. [SCOPE] Create architecture notearch-railsfor the Rails application component. Note:docs/stripe-subscription-architecture.mdexists in-repo but is not a pal-e-docs note. - [x] Forgejo issue -- ldraney/westside-ror#27, state: open
File Targets
- [x]
config/routes.rb-- verified: exists, currently has no webhook route (line 1-39). Route addition is straightforward. - [x]
app/controllers/webhooks_controller.rb-- correctly marked as NEW. Does not exist yet. Will needskip_forgery_protectionsince ApplicationController inherits from ActionController::Base (no existing CSRF skip patterns in codebase). - [x]
app/services/stripe_client.rb-- verified: exists (127 lines). Uses raw net/http, no Stripe gem. Addingverify_webhook_signaturemethod here is consistent with existing patterns. - [x] Deployment config (env var STRIPE_WEBHOOK_SECRET) -- no existing references. New secret needed.
- [x] DB columns verified in schema.rb:
payment_links.paid_at(line 216) -- datetime, nullablepayment_links.stripe_payment_link_id(line 221) -- string, not nullplayers.stripe_subscription_id(line 267) -- string, nullableplayers.subscription_status(line 268) -- enum (active, past_due, canceled, none), default none
Repo Placement
OK. Issue filed on ldraney/westside-ror, all file targets are in that repo. Single-repo change.
Dependencies
- #24 (editable fees) -- architecture doc says #24 ships first, but the issue correctly notes this webhook can ship independently. The webhook does not require fee editing to work. No blocking dependency.
- #26 (copy links UI) -- companion ticket, explicitly independent. No dependency.
- #22 (spike) -- closed. Produced the architecture doc. No dependency.
- #23 (original combined ticket) -- still on board in backlog. Should be closed or updated once #26 and #27 replace it. Not a blocker but a housekeeping item.
- No items in in_progress block this ticket. Items in in_progress (#2 Stripe payment links, #13 email) are unrelated to webhook functionality.
Acceptance Criteria
All 8 criteria are testable by an agent. The test expectations map cleanly to acceptance criteria. Run command (
rails test) is valid.Observations:
- AC #4 references reading metadata (player_id, team) from checkout.session.completed. The ticket should clarify HOW player_id gets into session metadata -- this is set when creating the payment link (which happens in #26). The webhook needs to handle the case where metadata is missing or incomplete.
- AC #5 references finding payment_link by
stripe_payment_link_id. The checkout session object from Stripe includes apayment_linkfield -- this is the correct lookup key. - Idempotency constraint is stated but not in AC. Could be an explicit test case (processing same event twice should not error).
Blast Radius
subscription_statusis read byadmin/roster_report_controller.rb(lines 14, 24, 29, 30). Webhook updates to this field will surface automatically in the roster report. No code changes needed there -- this is the desired effect.paid_atis read byStripeClient#db_payment_summary(lines 70, 84), used by the payments dashboard. Again, webhook updates will surface automatically. No blast radius concern.- No other controllers or services reference these columns.
- Adding
skip_forgery_protectionto the new WebhooksController is scoped -- it only affects that controller, not the app globally.
Decomposition Assessment
4 file targets in 1 repo. 8 acceptance criteria. 7 test expectations. Estimated agent work: ~8-10 minutes (new controller, service method, route, tests). This is above the 5-minute threshold but all targets are in one repo and tightly coupled -- decomposing would create artificial seams. The 8 AC are all part of the same webhook handler. A single agent pass is appropriate if the agent is given clear guidance. No decomposition needed.
Recommendations
[SCOPE]Create project pageproject-westside-rorwith user-stories section including thesubscription-linksstory entry.[SCOPE]Create architecture notearch-railsfor the Rails application component in pal-e-docs (or re-evaluate whetherarch:railsis the right label -- possiblyarch:stripewould be more specific).[BODY]Add note to AC #4 about handling missing metadata gracefully (payment links created outside the app may lack player_id metadata).[BODY]Add explicit AC for idempotency: "Processing the same webhook event twice does not create duplicate records or errors."[BODY]Clarify that #23 (the original combined ticket) should be closed now that #26 and #27 replace it.
-
Review: Copy-to-clipboard subscription links + webhook (re-review)
review-1335-2026-06-06-r2Verdict: NEEDS_REFINEMENT
Re-review after refinement. 5 of 8 previous findings addressed. Remaining blocker: decomposition still required (14 AC, 6 file targets, 8 points).
Previous Findings Status
- [x] [BODY] Fix audit doc reference — FIXED. Now references
docs/stripe-subscription-architecture.mdin Related section. - [x] [BODY] Add dependency on #24 — FIXED. Lineage and Context both document #24 must ship first.
- [x] [BODY] Add STRIPE_WEBHOOK_SECRET file target — FIXED. Deployment config listed in File Targets.
- [x] [BODY] Add AC for players without parent email — FIXED. AC 1 covers it, test expectation added, Context section documents behavior.
- [~] [BODY] Add AC for fee-tier-change edge case — DEFERRED. Not added, but acceptable: #24 owns fee editing and should handle link invalidation when fee changes. Dependency is documented.
- [ ] [SCOPE] Create project-westside-ror page — Still missing in pal-e-docs. Cannot verify story note.
- [ ] [SCOPE] Create arch-rails note — Still missing in pal-e-docs. Cannot verify arch note.
- [ ] [DECOMPOSE] Ticket too large — Still needs decomposition. Issue has grown from 12 to 14 AC.
Template Completeness
- [x] Type — Feature
- [x] Lineage — follow-up from spike #22, dependency on #24 documented
- [x] Repo — ldraney/westside-ror
- [x] User Story — well-formed (As Marcus, I want copy-to-clipboard links)
- [x] Context — thorough, includes Stripe data, dependency rationale, dollars-vs-cents, no-email handling
- [x] File Targets — 6 targets listed with rationale, plus 1 do-not-touch
- [x] Acceptance Criteria — 14 criteria (up from 12)
- [x] Test Expectations — 8 test cases + run command
- [x] Constraints — 6 constraints listed (added dollars-vs-cents)
- [x] Checklist — present
- [x] Related — lists spike, prerequisite, arch doc, live URL
All required sections for a Feature template are present and well-structured.
Traceability
- [x] story:subscription-links label — present on board item
- [ ] story note MISSING —
project-westside-rornote does not exist in pal-e-docs. Cannot verify user story entry. [SCOPE] Create project pageproject-westside-rorwith user-stories section. - [x] arch:rails label — present on board item
- [ ] arch note MISSING — no
arch-railsnote found in pal-e-docs. [SCOPE] Create architecture notearch-railsfor the Rails component. - [x] Forgejo issue — ldraney/westside-ror#23, open
File Targets
- [x]
config/routes.rb— verified: exists (39 lines), has admin namespace but no webhook route. Correct target. - [x]
app/controllers/webhooks_controller.rb— verified: does NOT exist yet (new file). Correct. - [x]
app/services/stripe_client.rb— verified: exists (127 lines), uses rawnet/http, haspayment_linksandcheckout_sessionsmethods but no subscription-mode link creation. Correct target. - [x]
app/controllers/admin/roster_report_controller.rb— verified: exists (35 lines), loads tenant/teams/players but not payment_links. Correct target. - [x]
app/views/admin/roster_report/index.html.erb— verified: exists (98 lines) with desktop table and mobile cards. No Copy Link button yet. Correct target. - [x] Deployment config for
STRIPE_WEBHOOK_SECRET— verified:docker-compose.ymlcurrently only hasSTRIPE_API_KEY(line 30). Correct target for adding webhook secret. - [x]
app/controllers/admin/payments_controller.rb— correctly listed as do-NOT-touch.
Repo Placement
OK — issue filed on
ldraney/westside-ror, all file targets within this repo. Single-repo change.Dependencies
- #24 (editable fees) — prerequisite: Now explicitly documented in Lineage and Context. Architecture doc confirms order: #24 first, then #23. Board item #1334 is also in backlog. Dependency is clear and correctly stated.
- #1207 (Stripe payment links + email blast, issue #2) — in_progress: Uses same
StripeClientandpayment_linkstable for one-time payments. No direct conflict but shared blast radius. - CSRF exemption:
ApplicationControllerinherits fromActionController::Basewith default CSRF protection. Issue now has AC 13 explicitly requiring CSRF exemption for webhook route. Covered. - Schema constraint:
payment_links.parent_idis NOT NULL, meaning a PaymentLink record requires a parent. The issue handles this correctly — players without parent email get "No email" indicator instead of a link. SincePlayer belongs_to :parent(required in Rails 7), all players have a parent, but parent.email may be nil.
Acceptance Criteria
14 acceptance criteria — exceeds the 5-AC decomposition threshold by nearly 3x.
- AC 1-7: Copy-to-clipboard link generation flow (UI + Stripe API + storage + no-email handling)
- AC 8-13: Webhook endpoint (signature, event handling, status updates, CSRF)
- AC 14: End-to-end status reflection on roster report
All criteria are testable and specific. The added ACs (CSRF exemption, no-email handling, status reflection) improve completeness.
Dollars vs cents: Now documented in Context ("multiply by 100") and Constraints. AC 4 says "correct recurring price tier based on player's monthly_fee" which is clear enough given the constraint.
Blast Radius
StripeClientchanges are additive — new methods, existing methods untouched. Safe.payment_linkstable shared with one-time payment system. New subscription links coexist. The unique constraintuq_payment_links_player_product_tenantmeans one link per player per product — aligns with AC 7 (reuse on reload).- No other controllers handle webhooks — new endpoint is isolated.
subscriptionstatusenum already hasactive,past_due,canceled,none— matches webhook events.paymentlinkstatusenum hasactive,paid,canceled— sufficient for webhook updates.
Decomposition Assessment
NEEDS DECOMPOSITION
- 14 acceptance criteria (threshold: 5) — up from 12 in first review
- 6 file targets (threshold: 3) — up from 5
- 8 test expectations
- Two distinct subsystems: (a) link generation + copy-to-clipboard UI, (b) webhook endpoint + status sync
- Estimated agent work: well over 5 minutes — involves Stripe API integration, webhook signature verification, JS clipboard logic, multiple controller/model changes, deployment config
- 8 story points further confirms this is too large for a single pass
Natural decomposition split:
- Sub-ticket A: Subscription link generation + copy-to-clipboard UI (AC 1-7, ~5 points)
- Sub-ticket B: Webhook endpoint + status sync (AC 8-14, ~3 points)
Route to
skill-decompose-ticketfor sub-ticket creation.Recommendations
- [SCOPE] Create project page
project-westside-rorwith user-stories section includingsubscription-linksstory - [SCOPE] Create architecture note
arch-railsfor the Rails component - [DECOMPOSE] 14 AC across 2 subsystems (link generation + webhook), 6 file targets, 8 points, 8 test expectations — route to
skill-decompose-ticket. Natural split: (a) subscription link generation + copy-to-clipboard UI (AC 1-7), (b) webhook endpoint + status sync (AC 8-14)
Note: All [BODY] findings from the first review have been addressed. The issue body is now clean and complete. The remaining blocker is decomposition (ticket size) and missing backing notes in pal-e-docs.
- [x] [BODY] Fix audit doc reference — FIXED. Now references
-
Review: Copy-to-clipboard subscription links + webhook
review-1335-2026-06-06Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — follow-up from spike #22
- [x] Repo — ldraney/westside-ror
- [x] User Story — present and well-formed
- [x] Context — thorough, includes Stripe data audit
- [x] File Targets — 5 files listed with rationale
- [x] Acceptance Criteria — 12 criteria
- [x] Test Expectations — 6 test cases + run command
- [x] Constraints — 5 constraints listed
- [x] Open Questions — 3 questions for Lucas/Marcus
- [x] Checklist — present
- [x] Related — lists parent spike and upstream PR
All required sections for a Feature template are present. Issue is thorough and well-structured.
Traceability
- [x] story:subscription-links label — present on board item
- [ ] story note MISSING —
project-westside-rornote does not exist in pal-e-docs. Cannot verify user story entry. [SCOPE] Create project pageproject-westside-rorwith user-stories section. - [x] arch:rails label — present on board item
- [ ] arch note MISSING — no
arch-railsnote found in pal-e-docs. [SCOPE] Create architecture notearch-railsfor the Rails component. - [x] Forgejo issue — ldraney/westside-ror#23, open
File Targets
- [x]
config/routes.rb— verified: exists, currently has admin namespace and email routes but no webhook route. Correct target for addingpost '/webhooks/stripe'. - [x]
app/controllers/webhooks_controller.rb— verified: does NOT exist yet (new file). Correct — needs creation. - [x]
app/services/stripe_client.rb— verified: exists at 127 lines, uses rawnet/httppattern, haspayment_linksandcheckout_sessionsmethods but no subscription-mode link creation. Correct target. - [x]
app/controllers/admin/roster_report_controller.rb— verified: exists at 35 lines, loads tenant/teams/players. Currently does not load payment_links. Correct target. - [x]
app/views/admin/roster_report/index.html.erb— verified: exists at 98 lines with desktop table and mobile card layout. No "Copy Link" button yet. Correct target. - [x]
app/controllers/admin/payments_controller.rb— verified: exists, separate one-time payment flow. Correctly listed as "do NOT touch".
Issue: Context section references
docs/reports/2026-06-01-stripe-payment-link-audit.mdbut this file does not exist. The actual spike output is atdocs/stripe-subscription-architecture.md.Repo Placement
OK — issue is filed on
ldraney/westside-rorand all file targets are within this repo. Single-repo change.Dependencies
- Ordering conflict: The architecture doc (
docs/stripe-subscription-architecture.md, line 172-173) specifies implementation order as #24 first, then #23. However, #23 is being reviewed for advancement while #24 (inline-editable monthly fee with Stripe sync) is also in backlog. If #24 lands first, it changes howmonthly_feeworks and could affect which Stripe price tier the subscription link uses. The issue should explicitly document whether it depends on #24 or can proceed independently. - Board item #1334 (Inline-editable monthly fee, Forgejo #24) — same
story:subscription-linkslabel, also in backlog. These two tickets share the same Stripe product and price tiers. No documented dependency between them on the board. - Board item #1207 (Stripe payment links + email blast, Forgejo #2) — in_progress. Uses the same
StripeClientandpayment_linkstable but for one-time payments. No conflict but blast radius overlap. - CSRF exemption needed:
ApplicationControllerinherits fromActionController::Basewhich has CSRF protection enabled by default. The webhook controller must skip this. Issue mentions this in Constraints but not in File Targets or AC. - Webhook signing secret: Issue says "must go through secrets management" but does not specify the env var name or where it will be configured (docker-compose.yml currently only has
STRIPE_API_KEY). File target for docker-compose.yml or deployment config is missing.
Acceptance Criteria
12 acceptance criteria — exceeds the 5-AC decomposition threshold.
- AC 1-7 cover the copy-to-clipboard link generation flow (UI + Stripe API + storage)
- AC 8-12 cover the webhook endpoint (signature verification, event handling, status updates)
- These are two distinct subsystems that could be implemented and tested independently.
Schema concern: AC 9 says webhook "sets
paid_at" — this column is onpayment_linkstable (notplayers), which is correct but the AC text is ambiguous about which record.Unique constraint concern:
payment_linkshas a unique constraint on(player_id, product_id, tenant_id). If all subscription links use the same "Monthly Club Dues" product, a player can only have one link. The ticket says "reused on subsequent page loads" (AC 7) which aligns. But if a player's fee tier changes, the old link must be deactivated and a new one created — this edge case is not covered in the AC.Missing AC: No acceptance criterion for players without a parent record (Open Question #3 acknowledges this but doesn't resolve it).
Blast Radius
StripeClientis used by bothAdmin::PaymentsController(one-time payments) and the roster report. Adding subscription link methods is additive and should not break existing one-time flows.payment_linkstable is shared with the one-time payment system. New subscription links will coexist. Thepaymentlinkstatusenum already includesactive,paid,canceledvalues.- No other controllers currently handle webhooks, so the new endpoint is isolated.
- The
subscriptionstatusenum already hasactive,past_due,canceled,none— matches webhook events perfectly.
Decomposition Assessment
NEEDS DECOMPOSITION
- 12 acceptance criteria (threshold: 5)
- 5 file targets (threshold: 3)
- Two distinct subsystems: (a) link generation + copy UI, (b) webhook endpoint + status updates
- Estimated agent work: well over 5 minutes — involves Stripe API integration, webhook signature verification, JS clipboard logic, and multiple controller/model changes
- 8 story points further confirms this is too large for a single pass
Route to
skill-decompose-ticketfor sub-ticket creation.Recommendations
- [BODY] Fix audit doc reference:
docs/reports/2026-06-01-stripe-payment-link-audit.md→docs/stripe-subscription-architecture.md - [BODY] Add dependency note: document whether #23 depends on #24 or can proceed independently (architecture doc says #24 first)
- [BODY] Add file target:
docker-compose.ymlor deployment config forSTRIPE_WEBHOOK_SECRETenv var - [BODY] Add AC for fee-tier-change edge case: when monthly_fee changes, old link must be deactivated and new link created
- [BODY] Add AC for players without a parent record (resolve Open Question #3)
- [SCOPE] Create project page
project-westside-rorwith user-stories section includingsubscription-linksstory - [SCOPE] Create architecture note
arch-railsfor the Rails component - [DECOMPOSE] 12 AC across 2 subsystems (link generation + webhook), 5 file targets, 8 points — route to
skill-decompose-ticket. Natural split: (a) subscription link generation + copy-to-clipboard UI (AC 1-7), (b) webhook endpoint + status sync (AC 8-12)
Board 1
-
Westside RoR
board-westside-rorNo content