Client request UI: My Property view with package and request form #123

Open
opened 2026-06-06 20:55:37 +00:00 by ldraney · 3 comments
Owner

Type

Feature

Lineage

Child of spike #121 (client request flow design). Part of Phase 3. Depends on #122 (ServiceRequest model — MERGED).

Repo

ldraney/landscaping-assistant

User Story

As a client, I want to see my current service package and submit requests (package changes or projects) so I can manage my landscaping service through the app — including getting an initial bid for mowing, weeding, or trimming & edging for my property.

Context

The My Property view (Person/Profile tab) is where clients interact with the app. They need to see their current package (which services, monthly price), active project requests and their status, and a form to submit new requests. Package changes and projects both use the same "Request a Change" form. Even the initial service bid (getting mowing/weeding/trimming for the first time) is treated as a service request.

This is the client-facing counterpart to #176 (admin display) and #179 (admin workflow). See docs/service-requests.md for the full architecture, status lifecycle, and data model.

File Targets

  • app/views/person/index.html.erb (update — add service package display and request list)
  • app/controllers/service_requests_controller.rb (new — create action for clients)
  • app/views/service_requests/_client_form.html.erb (new — request form partial)
  • app/views/service_requests/_client_request_list.html.erb (new — status list partial)
  • app/assets/stylesheets/application.css (add client request styles, status badges)
  • config/routes.rb (add service_requests resource)
  • spec/requests/service_requests_spec.rb (new)

Acceptance Criteria

  • My Property section shows current service package with service names and monthly total
  • Active ServiceRequests displayed with status badges (requested, quoted, accepted, paid, scheduled)
  • Completed/declined requests shown separately
  • "Request a Change" button opens form with type selector (package change / project)
  • Form has description field
  • Submitting creates ServiceRequest with status: requested and crew_member_id = current user
  • Client sees confirmation and request appears in their list (Turbo Stream, no reload)
  • Only the property's owning client can submit requests (owner_sub check)
  • When a request is in "quoted" status, client sees the price and Accept/Decline buttons
  • Works on mobile (44px touch targets, proper spacing)

Test Expectations

  • spec/requests/service_requests_spec.rb: create, authorization, validation errors, accept/decline
  • Run: bundle exec rspec

Constraints

  • CSS follows ~/ror-css-guide — no Tailwind, design tokens in :root
  • Turbo Frame for inline request submission (no full page reload)
  • Reference docs/service-requests.md for status values, transitions, and role access matrix

Feature Flag

None

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • #122 — ServiceRequest model (MERGED)
  • #176 — Admin property projects display (sibling ticket)
  • #179 — Admin project workflow (admin counterpart)
  • #121 — parent spike
  • #181 — Architecture doc
  • docs/service-requests.md — architecture reference
### Type Feature ### Lineage Child of spike #121 (client request flow design). Part of Phase 3. Depends on #122 (ServiceRequest model — MERGED). ### Repo `ldraney/landscaping-assistant` ### User Story As a client, I want to see my current service package and submit requests (package changes or projects) so I can manage my landscaping service through the app — including getting an initial bid for mowing, weeding, or trimming & edging for my property. ### Context The My Property view (Person/Profile tab) is where clients interact with the app. They need to see their current package (which services, monthly price), active project requests and their status, and a form to submit new requests. Package changes and projects both use the same "Request a Change" form. Even the initial service bid (getting mowing/weeding/trimming for the first time) is treated as a service request. This is the **client-facing** counterpart to #176 (admin display) and #179 (admin workflow). See `docs/service-requests.md` for the full architecture, status lifecycle, and data model. ### File Targets - `app/views/person/index.html.erb` (update — add service package display and request list) - `app/controllers/service_requests_controller.rb` (new — create action for clients) - `app/views/service_requests/_client_form.html.erb` (new — request form partial) - `app/views/service_requests/_client_request_list.html.erb` (new — status list partial) - `app/assets/stylesheets/application.css` (add client request styles, status badges) - `config/routes.rb` (add service_requests resource) - `spec/requests/service_requests_spec.rb` (new) ### Acceptance Criteria - [ ] My Property section shows current service package with service names and monthly total - [ ] Active ServiceRequests displayed with status badges (requested, quoted, accepted, paid, scheduled) - [ ] Completed/declined requests shown separately - [ ] "Request a Change" button opens form with type selector (package change / project) - [ ] Form has description field - [ ] Submitting creates ServiceRequest with status: requested and crew_member_id = current user - [ ] Client sees confirmation and request appears in their list (Turbo Stream, no reload) - [ ] Only the property's owning client can submit requests (owner_sub check) - [ ] When a request is in "quoted" status, client sees the price and Accept/Decline buttons - [ ] Works on mobile (44px touch targets, proper spacing) ### Test Expectations - `spec/requests/service_requests_spec.rb`: create, authorization, validation errors, accept/decline - Run: `bundle exec rspec` ### Constraints - CSS follows `~/ror-css-guide` — no Tailwind, design tokens in :root - Turbo Frame for inline request submission (no full page reload) - Reference `docs/service-requests.md` for status values, transitions, and role access matrix ### Feature Flag None ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - #122 — ServiceRequest model (MERGED) - #176 — Admin property projects display (sibling ticket) - #179 — Admin project workflow (admin counterpart) - #121 — parent spike - #181 — Architecture doc - `docs/service-requests.md` — architecture reference
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1348-2026-06-07

Template is complete and file targets verified, but several scope gaps will block or confuse the implementing agent.

Critical:

  • docs/service-requests.md does not exist -- referenced in Context and Constraints but never created. The agent has no architecture reference.
  • AC #2 status list says "accepted" but the merged ServiceRequest model has no such status. Actual statuses: requested, quoted, paid, scheduled, completed, declined.

Body fixes needed:

  • AC #6: Clarify how crew_member_id is resolved from Keycloak session (clients may not have a CrewMember record)
  • AC #9: "Accept" maps to quoted -> paid transition, not an "accepted" status
  • AC #8: Specify how to obtain current user's sub for owner_sub check (not in session hash currently)

Scope:

  • Create docs/service-requests.md with status lifecycle, transitions, and role access matrix
  • Create arch-rails-app note in pal-e-docs
## Scope Review: NEEDS_REFINEMENT Review note: `review-1348-2026-06-07` Template is complete and file targets verified, but several scope gaps will block or confuse the implementing agent. **Critical:** - `docs/service-requests.md` does not exist -- referenced in Context and Constraints but never created. The agent has no architecture reference. - AC #2 status list says "accepted" but the merged ServiceRequest model has no such status. Actual statuses: `requested, quoted, paid, scheduled, completed, declined`. **Body fixes needed:** - AC #6: Clarify how `crew_member_id` is resolved from Keycloak session (clients may not have a CrewMember record) - AC #9: "Accept" maps to `quoted -> paid` transition, not an "accepted" status - AC #8: Specify how to obtain current user's `sub` for `owner_sub` check (not in session hash currently) **Scope:** - Create `docs/service-requests.md` with status lifecycle, transitions, and role access matrix - Create `arch-rails-app` note in pal-e-docs
Author
Owner

Scope update (post review-1348-2026-06-07):

New dependency: #195 (auth prereqs — session sub, accepted status, CrewMember auto-create, current_crew_member helper).

Fixes for review findings:

  1. accepted status — added to ServiceRequest in #195. Flow: quoted → accepted → paid/scheduled
  2. crew_member_id resolutioncurrent_crew_member helper added in #195, CrewMember auto-created on login
  3. owner_sub matching — session now stores sub (Keycloak UUID) via #195, matches property.owner_sub
  4. docs/service-requests.md — exists once PR #182 merges

Property access model:

Role Properties visible Projects visible Can edit
Client Own only (owner_sub = session[:user][:sub]) On own property No
Member All All No
Lead All All Yes
Admin All All Yes
**Scope update (post review-1348-2026-06-07):** New dependency: #195 (auth prereqs — session sub, accepted status, CrewMember auto-create, current_crew_member helper). Fixes for review findings: 1. **`accepted` status** — added to ServiceRequest in #195. Flow: quoted → accepted → paid/scheduled 2. **crew_member_id resolution** — `current_crew_member` helper added in #195, CrewMember auto-created on login 3. **owner_sub matching** — session now stores `sub` (Keycloak UUID) via #195, matches property.owner_sub 4. **`docs/service-requests.md`** — exists once PR #182 merges **Property access model:** | Role | Properties visible | Projects visible | Can edit | |---|---|---|---| | Client | Own only (owner_sub = session[:user][:sub]) | On own property | No | | Member | All | All | No | | Lead | All | All | Yes | | Admin | All | All | Yes |
Author
Owner

Access update: Request creation is NOT client-only. Any role can create a service request:

  • Client — submits on own property
  • Member/Lead — submits on any property (e.g., client asks crew member on-site to submit for them)
  • Admin — submits on any property (phone call scenario)

Only admin can set a price/bid. Only the client (property owner) can accept a bid.

**Access update:** Request creation is NOT client-only. Any role can create a service request: - **Client** — submits on own property - **Member/Lead** — submits on any property (e.g., client asks crew member on-site to submit for them) - **Admin** — submits on any property (phone call scenario) Only **admin** can set a price/bid. Only the **client** (property owner) can accept a bid.
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#123
No description provided.