Review: Copy-to-clipboard subscription links + webhook (re-review)
Verdict: 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-ticket for 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.