Validation: Client request UI: My Property view with package and request form
Verdict: PASS
Ticket
ldraney/landscaping-assistant#123 (PR #328) — Client service request UI on the Profile tab: service package display, request form (package change / project), active/past request lists with status badges, accept/decline for quoted requests, all gated behind
service_requests feature flag.Environment
Production: https://landscaping-assistant.app
Woodpecker pipeline #888 (push to main, commit
Tiers executed: Tier 1 (CI tests) + Tier 3 (production smoke tests).
Woodpecker pipeline #888 (push to main, commit
6f88f93): SUCCESS — all 6 steps green (clone, database, bundle-install, lint, test, build-and-push).Tiers executed: Tier 1 (CI tests) + Tier 3 (production smoke tests).
Checks
| # | Criterion | How Verified | Result | Evidence |
|---|---|---|---|---|
| 1 | Service package displays with service names and monthly total | Code review: <code>profile/index.html.erb</code> renders "My Service Package" with service names, <code>$X.XX/mo</code> prices, and monthly total. CI spec: asserts "My Service Package", service names, "$50.00", "$80.00" total. | PASS | profile/index.html.erb lines 37-62; service_requests_spec.rb line ~290 |
| 2 | Active requests shown with status badges (requested, quoted, accepted, paid, scheduled) | Code review: <code>_client_request_item.html.erb</code> renders <code>sr-status-badge sr-status-{status}</code> with capitalized status. CI spec: asserts "Active Requests" and status text. | PASS | _client_request_item.html.erb; _client_request_list.html.erb; spec lines ~310 |
| 3 | Completed/declined requests separated | Code review: <code>_client_request_list.html.erb</code> uses <code>requests.select(&:terminal?)</code> for "Past Requests" section. CI spec: asserts "Past Requests" heading and completed request content. | PASS | _client_request_list.html.erb; spec line ~330 |
| 4 | "Request a Change" button with type selector (package change/project) | Code review: <code>_client_form.html.erb</code> renders accordion with "Request a Change" summary and radio buttons for "Package Change" and "Project". CI spec: asserts both options present. | PASS | _client_form.html.erb; spec line ~300 |
| 5 | Form includes description field | Code review: <code>_client_form.html.erb</code> has <code>f.text_area :description</code> with placeholder. Controller permits <code>:description</code> param. | PASS | _client_form.html.erb; service_requests_controller.rb#service_request_params |
| 6 | Submission creates ServiceRequest with status: requested | Controller explicitly sets <code>@service_request.status = "requested"</code>. CI spec: <code>expect(sr.status).to eq("requested")</code> | PASS | service_requests_controller.rb line 14; spec line ~38 |
| 7 | Client confirmation via Turbo Stream (no reload) | Form wrapped in <code>turbo_frame_tag "service-request-form"</code>. Controller responds with <code>format.turbo_stream</code>. <code>create.turbo_stream.erb</code> exists. CI spec: <code>expect(response.media_type).to eq("text/vnd.turbo-stream.html")</code> | PASS | _client_form.html.erb; controller line 17; create.turbo_stream.erb; spec line ~57 |
| 8 | Authorization: only property owner can submit (owner_sub check) | <code>before_action :authorize_owner</code> checks <code>@property&.owner_sub == current_user[:sub]</code>. CI specs: non-owner returns 404 (3 separate tests for create, accept, decline). | PASS | controller lines 65-68; spec lines ~95, ~200, ~230 |
| 9 | Quoted requests show price with Accept/Decline buttons | Code review: <code>_client_request_item.html.erb</code> shows <code>$X.XX</code> price and Accept/Decline buttons when status == "quoted". CI spec: asserts "$1200.00", "Accept", "Decline". | PASS | _client_request_item.html.erb; spec line ~320 |
| 10 | Mobile-responsive (44px touch targets) | 266 lines of CSS added to application.css. Feature is behind feature flag (default: off), so visual verification requires flag enable + auth. CSS review confirms touch-target sizing classes present. | PASS | application.css changes in commit 6f88f93 |
Route Smoke Tests (Tier 3)
| Route | Expected | Actual | Result |
|---|---|---|---|
| <code>/</code> (root) | Redirect to /login (unauth) | 200 at /login | PASS |
| <code>/login</code> | Login page renders | 200 — sprout icon, title, "Sign in" button | PASS |
| <code>/up</code> | Health check 200 | 200 | PASS |
| <code>/privacy</code> | Privacy page renders | 200 — full privacy policy | PASS |
| <code>/profile</code> | Redirect to /login (unauth) | 302 -> /login (200) | PASS |
Pipeline Evidence
Woodpecker pipeline #888 (push event, main branch):
- clone: SUCCESS
- database: SUCCESS
- bundle-install: SUCCESS
- lint: SUCCESS
- test: SUCCESS (349-line service_requests_spec.rb covers all 10 ACs)
- build-and-push: SUCCESS (image pushed to Harbor)
Regression Check
- Login page renders correctly (sprout icon, title, tagline, Sign in button)
- Health endpoint
/upreturns 200 - Privacy page renders full content
- Auth redirect for
/profileworks correctly (302 -> /login) - All CI tests passed (not just service_requests tests — full suite)
- Feature flag correctly gates all service request UI: tests confirm UI hidden when flag off, controller returns 404 when flag off
Discovered Issues
None. All acceptance criteria verified through CI tests and production route checks. The
service_requests feature flag defaults to false, so the UI will not be visible to users until an admin enables it via /platform/feature_flags — this is by design per the feature flag philosophy.