ServiceRequest model + migration #122

Closed
opened 2026-06-06 20:55:26 +00:00 by ldraney · 3 comments
Owner

Type

Feature

Lineage

Child of spike #121 (client request flow design). Part of Phase 3 (Property Features).

Repo

ldraney/landscaping-assistant

User Story

As admin, I need a data model to track client requests (package changes and projects) so I can quote prices and manage the approval workflow.

Context

Clients request package changes ("add trimming") and projects ("build a retaining wall") through a unified flow. Both need the same lifecycle: requested → quoted → accepted → paid → scheduled → completed (or declined at eligible stages). The ServiceRequest model captures this with a request_type field to distinguish the two.

Also adds monthly_price to the existing Service model for package pricing.

File Targets

  • db/migrate/*_create_service_requests.rb (new)
  • db/migrate/*_add_monthly_price_to_services.rb (new)
  • app/models/service_request.rb (new)
  • app/models/property.rb (add has_many :service_requests)
  • app/models/crew_member.rb (add has_many :service_requests)
  • db/seeds.rb (add prices to existing services)
  • spec/models/service_request_spec.rb (new)

Acceptance Criteria

  • ServiceRequest model with: property_id (FK → properties), crew_member_id (FK → crew_members), request_type (package_change/project), description, status, price (decimal), stripe_payment_link (string, nullable), paid_at (datetime, nullable), completed_at (datetime, nullable)
  • Service model gains monthly_price (decimal, nullable)
  • Seeds updated with prices for Mowing, Weeding, Edging & Trimming
  • Status transitions validated per graph below — no skipping steps

Status Transition Graph (as delivered)

requested → quoted     (admin reviews and sets a price)
requested → declined   (admin declines the request)
quoted    → accepted   (client accepts the quote)
accepted  → paid       (client pays via Stripe)
accepted  → scheduled  (admin schedules — payment handled outside Stripe)
paid      → scheduled  (admin schedules the work)
scheduled → completed  (work is done)

Note: The accepted state was added during implementation (not in original spec) to separate "client agrees to price" from "client has paid." This is the correct business workflow for landscaping where payment may be handled in person.

Known gap: quoted → declined and accepted → declined transitions are missing — tracked in #206.

No other transitions are valid. declined and completed are terminal states.

Test Expectations

  • spec/models/service_request_spec.rb: validations, status transitions, associations
  • Run: bundle exec rspec

Constraints

  • No UI in this ticket — model only
  • Status values: requested, quoted, accepted, paid, scheduled, completed, declined
  • crew_member_id references crew_members table (clients are crew_members with role=client)

Feature Flag

None

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • #121 — parent spike
  • #107 — auth parent
  • #206 — missing decline transitions (bug)
  • docs/user-stories-auth.md — ServiceRequest ERD
### Type Feature ### Lineage Child of spike #121 (client request flow design). Part of Phase 3 (Property Features). ### Repo `ldraney/landscaping-assistant` ### User Story As admin, I need a data model to track client requests (package changes and projects) so I can quote prices and manage the approval workflow. ### Context Clients request package changes ("add trimming") and projects ("build a retaining wall") through a unified flow. Both need the same lifecycle: requested → quoted → accepted → paid → scheduled → completed (or declined at eligible stages). The ServiceRequest model captures this with a `request_type` field to distinguish the two. Also adds `monthly_price` to the existing Service model for package pricing. ### File Targets - `db/migrate/*_create_service_requests.rb` (new) - `db/migrate/*_add_monthly_price_to_services.rb` (new) - `app/models/service_request.rb` (new) - `app/models/property.rb` (add has_many :service_requests) - `app/models/crew_member.rb` (add has_many :service_requests) - `db/seeds.rb` (add prices to existing services) - `spec/models/service_request_spec.rb` (new) ### Acceptance Criteria - [x] ServiceRequest model with: property_id (FK → properties), crew_member_id (FK → crew_members), request_type (package_change/project), description, status, price (decimal), stripe_payment_link (string, nullable), paid_at (datetime, nullable), completed_at (datetime, nullable) - [x] Service model gains monthly_price (decimal, nullable) - [x] Seeds updated with prices for Mowing, Weeding, Edging & Trimming - [x] Status transitions validated per graph below — no skipping steps ### Status Transition Graph (as delivered) ``` requested → quoted (admin reviews and sets a price) requested → declined (admin declines the request) quoted → accepted (client accepts the quote) accepted → paid (client pays via Stripe) accepted → scheduled (admin schedules — payment handled outside Stripe) paid → scheduled (admin schedules the work) scheduled → completed (work is done) ``` **Note:** The `accepted` state was added during implementation (not in original spec) to separate "client agrees to price" from "client has paid." This is the correct business workflow for landscaping where payment may be handled in person. **Known gap:** `quoted → declined` and `accepted → declined` transitions are missing — tracked in #206. No other transitions are valid. `declined` and `completed` are terminal states. ### Test Expectations - `spec/models/service_request_spec.rb`: validations, status transitions, associations - Run: `bundle exec rspec` ### Constraints - No UI in this ticket — model only - Status values: requested, quoted, accepted, paid, scheduled, completed, declined - `crew_member_id` references `crew_members` table (clients are crew_members with role=client) ### Feature Flag None ### Checklist - [x] PR opened - [x] Tests pass - [x] No unrelated changes ### Related - #121 — parent spike - #107 — auth parent - #206 — missing decline transitions (bug) - `docs/user-stories-auth.md` — ServiceRequest ERD
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1347-2026-06-07
Three issues must be resolved before this ticket is agent-ready.

  • user_id column has no backing table. There is no users table in the database. The app stores identity as keycloak_username on crew_members. The ERD's User entity is a Phase 4 concept. Clarify whether user_id should be a string column (Keycloak sub/username) or a FK to crew_members.
  • Status transition rules not enumerated. AC4 says "no skipping steps" but the allowed transitions are not defined. Which statuses can transition to declined? The flow diagram is ambiguous. Add an explicit transition table.
  • Feature Flag section missing. Template requires it -- value should be "none" for this internal model change.
  • [SCOPE] arch-rails-app architecture note does not exist in pal-e-docs.

File targets, repo placement, dependencies (#121 done), and decomposition all check out.

## Scope Review: NEEDS_REFINEMENT Review note: `review-1347-2026-06-07` Three issues must be resolved before this ticket is agent-ready. - **`user_id` column has no backing table.** There is no `users` table in the database. The app stores identity as `keycloak_username` on `crew_members`. The ERD's `User` entity is a Phase 4 concept. Clarify whether `user_id` should be a string column (Keycloak sub/username) or a FK to `crew_members`. - **Status transition rules not enumerated.** AC4 says "no skipping steps" but the allowed transitions are not defined. Which statuses can transition to `declined`? The flow diagram is ambiguous. Add an explicit transition table. - **Feature Flag section missing.** Template requires it -- value should be "none" for this internal model change. - **[SCOPE]** `arch-rails-app` architecture note does not exist in pal-e-docs. File targets, repo placement, dependencies (#121 done), and decomposition all check out.
Author
Owner

Scope refinement (post review-1347-2026-06-07):

  • user_idcrew_member_id: Changed to FK on crew_members — clients are crew_members with role=client. No users table exists.
  • Status transition graph added: Explicit valid transitions enumerated. declined reachable from requested and quoted only.
  • Feature Flag section added: None (model-only change).
  • File targets updated: Added crew_member.rb for the has_many association.
**Scope refinement (post review-1347-2026-06-07):** - **`user_id` → `crew_member_id`**: Changed to FK on `crew_members` — clients are crew_members with `role=client`. No `users` table exists. - **Status transition graph added**: Explicit valid transitions enumerated. `declined` reachable from `requested` and `quoted` only. - **Feature Flag section added**: None (model-only change). - **File targets updated**: Added `crew_member.rb` for the `has_many` association.
Author
Owner

Scope Review: APPROVED (re-review)

Review note: review-1347-2026-06-07-r2

All three issues from the initial review have been resolved:

  • crew_member_id FK -- user_id replaced with crew_member_id referencing existing crew_members table. Verified table exists in committed schema.
  • Status transition graph -- Explicit 6-transition graph added with terminal states documented. Unambiguous for implementation.
  • Feature Flag section -- Added with value "None".

Template is complete, all 7 file targets verified against codebase, acceptance criteria are testable, no decomposition needed. Ticket is ready for implementation.

Carried forward (non-blocking): [SCOPE] Create arch-rails-app architecture note in pal-e-docs.

## Scope Review: APPROVED (re-review) Review note: `review-1347-2026-06-07-r2` All three issues from the initial review have been resolved: - **crew_member_id FK** -- `user_id` replaced with `crew_member_id` referencing existing `crew_members` table. Verified table exists in committed schema. - **Status transition graph** -- Explicit 6-transition graph added with terminal states documented. Unambiguous for implementation. - **Feature Flag section** -- Added with value "None". Template is complete, all 7 file targets verified against codebase, acceptance criteria are testable, no decomposition needed. Ticket is ready for implementation. Carried forward (non-blocking): `[SCOPE]` Create `arch-rails-app` architecture note in pal-e-docs.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/landscaping-assistant#122
No description provided.