Review: ServiceRequest model + migration
Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [ ] Feature Flag -- MISSING. Template requires a Feature Flag section. This ticket is an internal model change with no UI, so the correct value is "none", but the section must be present.
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:auth label -- auth story
- [x] story note verified -- "auth" entry found in project-landscaping-assistant user-stories table
- [x] arch:rails-app label
- [ ] arch note MISSING -- [SCOPE] No
arch-rails-appnote exists in pal-e-docs. Create architecture notearch-rails-appfor the Rails application component. - [x] Forgejo issue -- ldraney/landscaping-assistant#122, state: open
File Targets
- [x]
db/migrate/*_create_service_requests.rb(new) -- OK, no existing ServiceRequest migration found - [x]
db/migrate/*_add_monthly_price_to_services.rb(new) -- OK,servicestable exists (schema verified), nomonthly_pricecolumn present. ERD indocs/user-stories-auth.mdconfirms this addition. - [x]
app/models/service_request.rb(new) -- OK, no existing model. No references to ServiceRequest anywhere in codebase. - [x]
app/models/property.rb-- verified exists. Currently hashas_many :property_services,has_many :services,has_many :work_queue_items. Addinghas_many :service_requestsis straightforward. - [x]
db/seeds.rb-- verified exists. Currently seeds three services without prices. Addingmonthly_pricevalues is straightforward. - [x]
spec/models/service_request_spec.rb(new) -- OK,spec/models/directory exists with 8 existing model specs. Pattern is consistent.
Repo Placement
OK. Issue filed on
ldraney/landscaping-assistant, all file targets are in the same repo. Single-repo ticket.Dependencies
- #121 (parent spike) -- done (board item 1346 in
donecolumn). No blocker. - user_id FK problem -- The ticket specifies
user_idas a column on ServiceRequest, and the ERD indocs/user-stories-auth.mdshowsbigint user_id FK "Client who submitted". However, there is nouserstable in the database. The app uses Keycloak for auth and stores identity askeycloak_usernameoncrew_members. TheUsermodel is described in the ERD as a Phase 4 concept (multi-tenancy). The ticket needs to clarify: shoulduser_idbe a string column storing a Keycloak sub/username (matching the currentcrew_members.keycloak_usernamepattern), or is aUsermodel a prerequisite? This is a blocking ambiguity. - No Stripe gem or config -- The
stripe_payment_linkcolumn is fine as a plain string (just a URL), but there are zero Stripe references in the codebase. The ticket correctly says "No UI" and the Stripe integration is a separate ticket (#125). No dependency issue here. - Downstream consumers -- #123 (Client request UI) and #124 (Admin request management) both depend on this model. Both are in backlog, not blocked.
Acceptance Criteria
- AC1 (ServiceRequest model with listed columns) -- testable, columns clearly specified.
- AC2 (Service gains monthly_price) -- testable, clear.
- AC3 (Seeds updated with prices) -- testable, three service names match existing seeds.
- AC4 (Status transitions validated, no skipping steps) -- Underspecified. The valid transitions are not enumerated. For example: can a request go directly from
requestedtodeclined? Canquotedgo todeclined? The status values are listed (requested, quoted, paid, scheduled, completed, declined), but the allowed transition graph is not. The flow diagram indocs/user-stories-auth.mdimpliesdeclinedbranches from the admin decision point (afterrequested), but also afterquotedif the client doesn't pay? This needs explicit transition rules for an agent to implement correctly. - AC5 (Model specs) -- testable, clear.
Blast Radius
- Property model -- adding
has_many :service_requestsis low risk. No existing associations conflict. - Service model -- adding
monthly_pricecolumn is low risk. No existing code reads a price from services. - Seeds -- uses
find_or_create_by!, so updating to include prices needs care (may need to usefind_or_create_by!(name:).update!(monthly_price:)or similar to be idempotent). - No downstream breakage risk -- this is a new model with no UI. Existing tests should be unaffected.
Decomposition Assessment
6 file targets in 1 repo, 5 acceptance criteria. All files are in one repo and the work is cohesive (one model + one column addition + seeds + specs). Estimated agent work: under 5 minutes. No decomposition needed.
Recommendations
[BODY]Add### Feature Flagsection with value "none" (internal model change, no UI).[BODY]Clarifyuser_idcolumn: since there is nouserstable, specify whether this should be a string column storing the Keycloak sub/username (matchingcrew_members.keycloak_usernamepattern) or abigintFK tocrew_members. The ERD shows aUserentity that does not yet exist -- the ticket must resolve this ambiguity before implementation.[BODY]Add explicit status transition rules to AC4. Enumerate which transitions are valid (e.g.,requested -> quoted,requested -> declined,quoted -> declined,quoted -> paid,paid -> scheduled,scheduled -> completed). Without this, an agent cannot implement "no skipping steps" correctly.[SCOPE]Create architecture notearch-rails-appfor the Rails application component in pal-e-docs.