Validation: Crew tab - admin oversight of team members and their daily lists
Verdict: PASS
Ticket
ldraney/landscaping-assistant#117 — Crew tab: admin oversight of team members and their daily lists. Board item #1339 on board-landscaping-assistant. Merged via PR #146.
Environment
Production cluster, namespace
landscaping-assistant, URL: https://landscaping-assistant.tail5b443a.ts.net. Image: harbor.tail5b443a.ts.net/landscaping-assistant/app:c89ac23068ff4adad41fdba4415a84d307d9404e. Pipeline #362 (success). Pod: landscaping-assistant-5c646869b9-px7fn — Running, 0 restarts.Checks
| # | Criterion | How Verified | Result | Evidence |
|---|---|---|---|---|
| 1 | Crew index shows list of all active crew members with their name and role badge | Inspected deployed view template via kubectl exec cat; confirmed role-badge CSS class and member.name rendering. Empty state renders correctly when no members seeded. | PASS | Template: <code><span class="role-badge role-badge-<%= member.role %>"><%= member.role.titleize %></span></code>. Browser snapshot shows /crew loads with heading "Crew" and empty state message. |
| 2 | Clicking a crew member navigates to their profile page (name, role, active status, Keycloak username) | Inspected show.html.erb template via kubectl; confirmed dl.crew-profile with fields: Role (badge), Status (active/inactive), Keycloak Username, Added date. Route confirmed: <code>resources :crew, only: [:index, :show]</code> | PASS | Show template renders all four required fields: name (h1), role (role-badge), status (status-indicator), keycloak_username (code tag). |
| 3 | Admin and super_admin can access Crew tab; all other roles get 404 | Controller source: <code>require_role :admin, :super_admin</code>. Browser test as lucas-super-admin loads /crew successfully. Unauthenticated curl returns 302 redirect. | PASS | Controller line 1: <code>require_role :admin, :super_admin</code>. curl /crew without auth: HTTP 302. Browser as super_admin: page loads with heading "Crew". |
| 4 | CrewMember model with validations and crew:sync rake task (idempotent, find_or_create_by!) | Rails runner queried validators: presence on name/keycloak_username/role, uniqueness on keycloak_username, inclusion on role. Rake task source uses find_or_create_by!. <code>rails -T crew</code> confirms task exists. | PASS | Validators: PresenceValidator[:name], PresenceValidator[:keycloak_username], UniquenessValidator[:keycloak_username], PresenceValidator[:role], InclusionValidator[:role]. Rake output: <code>bin/rails crew:sync # Sync crew members (idempotent)</code>. Task uses <code>CrewMember.find_or_create_by!(keycloak_username: ...)</code>. |
| 5 | Crew member list shows active/inactive status indicator | Inspected index.html.erb template: renders <code>status-indicator status-indicator-active/inactive</code> span with text "Active"/"Inactive". | PASS | Template: <code><span class="status-indicator status-indicator-<%= member.active? ? 'active' : 'inactive' %>"></code> |
Regression Check
Verified other routes still functional:
/uphealth check: HTTP 200/today: loads correctly with full property data (browser snapshot confirmed)- Bottom nav: all 6 tabs (Today, Week, Person, Platform, Properties, Crew) render correctly
- Pod status: 1/1 Running, 0 restarts, age 3h14m
- Pipeline #362: all 6 steps green (clone, database, bundle-install, lint, test, build-and-push)
Discovered Issues
None. Note:
crew:sync has not been run in production yet, so the crew list shows the empty state. This is expected — the rake task needs to be run manually to seed crew members from Keycloak. This is not a bug; the feature is fully deployed and functional, awaiting initial data seed.