Review: Profile tab: business code join form
Verdict: READY
Template Completeness
- [x] Type — Feature
- [x] Lineage — SaaS / multi-tenancy sprint
- [x] Repo — ldraney/landscaping-assistant
- [x] User Story — well-formed (As a user on the Profile/Person tab...)
- [x] Context — thorough, describes current placeholder state and target flow with 6-step behavior spec
- [x] File Targets — 6 files listed in table format with current state and change needed
- [x] Feature Flag — business_codes, disabled by default, removal criteria stated (2 weeks stable)
- [x] Acceptance Criteria — 10 criteria, all testable
- [x] Test Expectations — request specs in spec/requests/join_crew_spec.rb, 6 test cases described
- [x] Constraints — 6 explicit do-NOT boundaries
- [x] Checklist — present
- [x] Dependencies — explicit hard dependency on #308
- [x] Related — links to #308, downstream tickets, and docs
Traceability
- [x] story:saas label — "SaaS subscription, business codes for crew onboarding, admin approval of join requests, Apple IAP billing"
- [x] story note verified — found in project-landscaping-assistant user-stories section. Key: "saas", role: "All roles", summary includes business codes and crew onboarding. #309 explicitly listed as child of umbrella #308.
- [x] arch:rails-app label — Rails App (Shared Pattern)
- [x] arch note verified — arch-rails-app note exists in pal-e-docs (active, covers deployment pipeline, Hotwire, CNPG, Keycloak)
- [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/landscaping-assistant/issues/309, state: open
File Targets
- [x]
app/views/join_crew/index.html.erb— verified (811 bytes): disabled placeholder form with business_name and join_notes fields, disabled Submit Request button. Matches issue description exactly. - [x]
app/controllers/join_crew_controller.rb— verified (102 bytes, 6 lines): emptyindexaction only, nocreate. Matches issue description. - [x]
config/routes.rb— verified: line 63 hasget "join-crew", to: "join_crew#index"only. No POST route. Matches issue description. - [x]
app/models/user_business.rb— verified: STATUSES = %w[pending approved denied], ROLES = %w[crew_member crew_lead admin], validates uniqueness on [user_id, business_id]. No changes needed per issue. Confirmed. - [x]
app/views/profile/index.html.erb— verified: line 35 links tojoin_crew_path. No change needed per issue. Confirmed. - [x]
lib/tasks/feature_flags.rake— verified: FEATURES array exists with 14 flags,business_codesnot yet present. Agent will add it.
Additional verification:
user_businesses table confirmed in db/schema.rb with user_id (string — stores Keycloak sub), business_id (bigint FK), role, status (default: "pending"), favorited. Unique index on [user_id, business_id]. Existing test file spec/requests/join_crew_spec.rb has 3 passing specs for GET /join-crew (unauthenticated redirect, authenticated render, placeholder form). Agent will extend this file.Note: Issue Context section references
current_sub but the actual app helper is current_user[:sub] (verified in application_controller.rb and profile_controller.rb). This is in narrative text only — file targets and AC are correct. Agent will read actual code.Repo Placement
OK. Issue filed on ldraney/landscaping-assistant. All file targets are in the same repo. Single-repo change, no cross-repo effects.
Dependencies
- Hard dependency: #308 (board item #1905) — "Add business code and subscription fields to Business model". Adds
join_codecolumn to businesses table. Currently in backlog, state: open. Verified:join_codedoes NOT exist in db/schema.rb or any migration. This ticket callsBusiness.find_by(join_code: ...)which requires #308 merged first. Dependency correctly documented in issue. - Downstream: #310 (board item #1907) — "Admin approval UI on Crew tab for pending join requests". In backlog, 3 points. Enabled by #309 (creates pending UserBusiness records that #310 will display).
- Downstream: #312 (board item #1909) — Keycloak registration field. In backlog, 5 points. Same story:saas but independent path.
- No items currently in
in_progressornext_upthat block this ticket (next_up has only #1683, an iOS pipeline bug). - Issue correctly states exclusive ownership of
business_codesfeature flag registration — #310, #311, #312 should NOT also register it.
Acceptance Criteria
10 ACs, all testable via request specs. Each maps to a specific HTTP verb + path + expected response. Test expectations section names the spec file (
spec/requests/join_crew_spec.rb) and describes 6 test cases covering the major ACs. Auth enforcement testable via existing sign_in_as helper (already used in the existing spec file). Feature flag gating testable via existing feature_enabled? helper. Turbo response testable via content type assertion.Blast Radius
Low. Changes are self-contained to the join_crew namespace (controller + view + route + flag). UserBusiness model is NOT modified — only creates new records via standard ActiveRecord. Feature flag gating ensures zero impact when disabled. No cross-repo effects. No downstream consumers affected until #310 adds admin approval UI. The
business_codes flag is new and independent of the existing multi_tenancy flag.Decomposition Assessment
- 6 file targets in 1 repo — under the >3 files across >2 repos threshold
- 10 acceptance criteria — exceeds the >5 threshold
- Estimated agent work: ~4 minutes (1 controller action, 1 view rewrite, 1 route, 1 flag)
The AC count formally exceeds the decomposition threshold. However, all 10 ACs are state variations of a single controller action (
create) and a single view (conditional rendering based on membership status + feature flag). Decomposing "valid code submission" from "invalid code handling" or "denied status display" would split one controller action into artificial sub-tickets with shared dependencies on the same route and view. The work is cohesive: 1 new action + 1 view rewrite + 1 route + 1 flag definition. No decomposition needed.Recommendations
No action needed.