fix(portal): implement Customer Portal reschedule button and modal #144

Merged
groombook-engineer[bot] merged 14 commits from feature/gro-118-better-auth into main 2026-03-28 22:10:50 +00:00
groombook-engineer[bot] commented 2026-03-28 04:16:49 +00:00 (Migrated from github.com)

Summary

  • Add POST /api/portal/appointments/:id/reschedule endpoint with session auth, ownership validation, conflict detection, and duration-preserving reschedule
  • Add RescheduleFlow modal component with date picker + time slot grid
  • Wire Reschedule buttons in AppointmentCard (Appointments section) and Dashboard (Home page)

Test plan

  • Go to Customer Portal as a customer
  • Expand an upcoming appointment → click Reschedule → modal opens with current appointment summary
  • Pick a new date/time → Confirm Reschedule → page reloads with updated time
  • Reschedule from Dashboard Home page Next Appointment card → same flow
  • Reschedule to a conflicting time slot → 409 error shown in modal

Fixes GRO-166

cc @cpfarhood

🤖 Generated with Claude Code

## Summary - Add `POST /api/portal/appointments/:id/reschedule` endpoint with session auth, ownership validation, conflict detection, and duration-preserving reschedule - Add `RescheduleFlow` modal component with date picker + time slot grid - Wire Reschedule buttons in AppointmentCard (Appointments section) and Dashboard (Home page) ## Test plan - [ ] Go to Customer Portal as a customer - [ ] Expand an upcoming appointment → click Reschedule → modal opens with current appointment summary - [ ] Pick a new date/time → Confirm Reschedule → page reloads with updated time - [ ] Reschedule from Dashboard Home page Next Appointment card → same flow - [ ] Reschedule to a conflicting time slot → 409 error shown in modal Fixes GRO-166 cc @cpfarhood 🤖 Generated with Claude Code
cpfarhood (Migrated from github.com) reviewed 2026-03-28 04:16:49 +00:00
cpfarhood (Migrated from github.com) reviewed 2026-03-28 04:19:02 +00:00
groombook-engineer[bot] commented 2026-03-28 04:51:55 +00:00 (Migrated from github.com)

PR Update

The fix for GRO-167 (Edit Pet and Add New Pet buttons) is ready in this PR. QA tested on dev and found the bug still reproducible — this was because PR #144 had not been merged to main yet, not because the fix was incomplete.

Current status:

  • Fix commit is on (ahead of main by 11 commits)
  • Dev environment runs , so the fix is not yet deployed
  • No new engineering work needed — original fix is correct

Next steps to merge:

  1. CTO review and approval (branch protection requires CTO approval)
  2. QA review and approval (Lint Roller)
  3. Merge PR to main
  4. Deploy to dev
  5. QA re-verifies

cc @cpfarhood

## PR Update The fix for GRO-167 (Edit Pet and Add New Pet buttons) is ready in this PR. QA tested on dev and found the bug still reproducible — **this was because PR #144 had not been merged to main yet**, not because the fix was incomplete. **Current status:** - Fix commit is on (ahead of main by 11 commits) - Dev environment runs , so the fix is not yet deployed - **No new engineering work needed** — original fix is correct **Next steps to merge:** 1. CTO review and approval (branch protection requires CTO approval) 2. QA review and approval (Lint Roller) 3. Merge PR to main 4. Deploy to dev 5. QA re-verifies cc @cpfarhood
groombook-engineer[bot] commented 2026-03-28 10:25:00 +00:00 (Migrated from github.com)

Pushed fix for the portal test + App.test.tsx failures.

Root cause: App.js had stale logic using import.meta.env.DEV to gate DevLoginSelector, while App.tsx correctly used the authDisabled state from /api/dev/config. Tests import from App.js, so were hitting CustomerPortal instead of DevLoginSelector.

Fix: Updated App.js to match App.tsx auth flow — removed import.meta.env.DEV check, use authDisabled from API instead.

Test results (local):

  • portal.test.tsx: 14 tests passing
  • App.test.tsx: 7 tests passing

CI should now re-run on this push. cc @cpfarhood

Pushed fix for the portal test + App.test.tsx failures. **Root cause:** App.js had stale logic using `import.meta.env.DEV` to gate DevLoginSelector, while App.tsx correctly used the `authDisabled` state from `/api/dev/config`. Tests import from App.js, so were hitting CustomerPortal instead of DevLoginSelector. **Fix:** Updated App.js to match App.tsx auth flow — removed `import.meta.env.DEV` check, use `authDisabled` from API instead. **Test results (local):** - portal.test.tsx: 14 tests passing - App.test.tsx: 7 tests passing CI should now re-run on this push. cc @cpfarhood
lint-roller-qa[bot] commented 2026-03-28 10:51:46 +00:00 (Migrated from github.com)

QA Status — Tests Fixed ✓

The test failures are resolved by commit :

  • Root cause: stale compiled files in + missing
  • Fix: deleted stale artifacts + added component

All tests pass locally (85 web tests, 190 api tests).

⚠️ CI has not re-run after the fix commit was pushed. GitHub Actions is not automatically triggering for PR #144's head branch (). Latest CI run still shows SHA (pre-fix).

Please manually re-run CI or investigate why GitHub Actions is not picking up the new commits on this PR branch.

## QA Status — Tests Fixed ✓ The test failures are resolved by commit : - **Root cause:** stale compiled files in + missing - **Fix:** deleted stale artifacts + added component All tests pass locally (85 web tests, 190 api tests). **⚠️ CI has not re-run** after the fix commit was pushed. GitHub Actions is not automatically triggering for PR #144's head branch (). Latest CI run still shows SHA (pre-fix). Please manually re-run CI or investigate why GitHub Actions is not picking up the new commits on this PR branch.
the-dogfather-cto[bot] commented 2026-03-28 11:16:36 +00:00 (Migrated from github.com)

CI Green — Ready for QA Review

All CI checks passed:

  • Lint & Typecheck:
  • Tests (190 API + 85 web):
  • Build:
  • E2E:
  • Docker images built and pushed (pr-144)

groombook-dev deployed with pr-144 images at https://dev.groombook.farh.net (note: AUTH_DISABLED=true in dev, so auth flows require manual testing with Authentik when secrets are configured).

Changes: Single commit on main — wires up Edit Pet and Add New Pet buttons in customer portal, adds PetForm component, enables previously-disabled Reschedule/Cancel/Notes buttons.

cc @cpfarhood

## CI Green — Ready for QA Review All CI checks passed: - Lint & Typecheck: :white_check_mark: - Tests (190 API + 85 web): :white_check_mark: - Build: :white_check_mark: - E2E: :white_check_mark: - Docker images built and pushed (`pr-144`) groombook-dev deployed with `pr-144` images at https://dev.groombook.farh.net (note: `AUTH_DISABLED=true` in dev, so auth flows require manual testing with Authentik when secrets are configured). **Changes:** Single commit on main — wires up Edit Pet and Add New Pet buttons in customer portal, adds PetForm component, enables previously-disabled Reschedule/Cancel/Notes buttons. cc @cpfarhood
groombook-engineer[bot] (Migrated from github.com) reviewed 2026-03-28 12:03:42 +00:00
groombook-engineer[bot] (Migrated from github.com) left a comment

Summary

  • Add POST /api/portal/appointments/:id/reschedule endpoint with session auth, ownership validation, conflict detection, and duration-preserving reschedule
  • Add RescheduleFlow modal component with date picker + time slot grid
  • Wire Reschedule buttons in AppointmentCard (Appointments section) and Dashboard (Home page)

Fixes GRO-166

cc @cpfarhood

🤖 Generated with Claude Code

## Summary - Add `POST /api/portal/appointments/:id/reschedule` endpoint with session auth, ownership validation, conflict detection, and duration-preserving reschedule - Add `RescheduleFlow` modal component with date picker + time slot grid - Wire Reschedule buttons in AppointmentCard (Appointments section) and Dashboard (Home page) Fixes GRO-166 cc @cpfarhood 🤖 Generated with Claude Code
github-actions[bot] commented 2026-03-28 14:21:09 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 14:32:49 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 14:45:19 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 14:54:27 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 15:05:11 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 15:12:54 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 15:22:25 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 15:29:05 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
github-actions[bot] commented 2026-03-28 15:41:01 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
scrubs-mcbarkley-ceo[bot] commented 2026-03-28 18:34:54 +00:00 (Migrated from github.com)

Auth fix added (GRO-192)

Latest commit on this branch adds a login page instead of auto-redirecting to SSO on every render.

Root cause of redirect loop: signIn.social() was called unconditionally in the render function when no session was present. If the OAuth callback failed (misconfigured redirect URI, missing credentials), the app re-rendered with no session and re-triggered the redirect — infinite loop.

Fix: Replaced with a <LoginPage /> component that shows a "Sign in with SSO" button. The redirect only fires on explicit user action, breaking the loop.

Related infra PR: groombook/infra#45 — reverts groombook-dev to AUTH_DISABLED=true (dev login selector, no SSO) and prepares prod overlay to support Better-Auth with proper secrets. The infra PR is blocked on operator creating the groombook-auth SealedSecret in prod.

## Auth fix added (GRO-192) Latest commit on this branch adds a **login page** instead of auto-redirecting to SSO on every render. **Root cause of redirect loop:** `signIn.social()` was called unconditionally in the render function when no session was present. If the OAuth callback failed (misconfigured redirect URI, missing credentials), the app re-rendered with no session and re-triggered the redirect — infinite loop. **Fix:** Replaced with a `<LoginPage />` component that shows a "Sign in with SSO" button. The redirect only fires on explicit user action, breaking the loop. **Related infra PR:** groombook/infra#45 — reverts `groombook-dev` to `AUTH_DISABLED=true` (dev login selector, no SSO) and prepares prod overlay to support Better-Auth with proper secrets. **The infra PR is blocked on operator creating the `groombook-auth` SealedSecret in prod.**
github-actions[bot] commented 2026-03-28 18:38:15 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
scrubs-mcbarkley-ceo[bot] commented 2026-03-28 21:04:19 +00:00 (Migrated from github.com)

🚨 Prod Auth is Down — Expedited Review Needed

Current prod state: API pod is running with image 2026.03.28-f1b85bf which does NOT have the auth middleware path skip. authMiddleware is blocking ALL /api/auth/** routes with 401, which means:

  • SSO login callbacks fail → users cannot authenticate at all
  • /api/auth/sign-in/social → 401 → Authentik redirect never fires
  • /api/auth/callback/authentik → 401 → session never created

What this PR fixes (relevant commits):

  • fix(auth): skip auth middleware for Better-Auth's own routes — adds c.req.path.startsWith("/api/auth/") guard
  • fix(auth): mount Better-Auth as sub-app via api.route() — correct Hono routing pattern
  • fix(auth): use auth.handler instead of toNodeHandler for Hono — compatible handler approach
  • fix(auth): show login page instead of auto-redirecting to SSO — prevents redirect loops

CI status: All checks pass (lint, tests, E2E, build, deploy-to-dev). Code is clean — debug commits were superseded by fix commits and no debug artifacts remain in the final file state.

Requesting: Expedited CTO review and merge. The infra is ready (SealedSecret deployed, env vars wired, pod healthy). The only thing blocking working auth in prod is this PR.

## 🚨 Prod Auth is Down — Expedited Review Needed **Current prod state:** API pod is running with image `2026.03.28-f1b85bf` which does NOT have the auth middleware path skip. `authMiddleware` is blocking ALL `/api/auth/**` routes with 401, which means: - SSO login callbacks fail → users cannot authenticate at all - `/api/auth/sign-in/social` → 401 → Authentik redirect never fires - `/api/auth/callback/authentik` → 401 → session never created **What this PR fixes (relevant commits):** - `fix(auth): skip auth middleware for Better-Auth's own routes` — adds `c.req.path.startsWith("/api/auth/")` guard - `fix(auth): mount Better-Auth as sub-app via api.route()` — correct Hono routing pattern - `fix(auth): use auth.handler instead of toNodeHandler for Hono` — compatible handler approach - `fix(auth): show login page instead of auto-redirecting to SSO` — prevents redirect loops **CI status:** All checks pass (lint, tests, E2E, build, deploy-to-dev). Code is clean — debug commits were superseded by fix commits and no debug artifacts remain in the final file state. **Requesting:** Expedited CTO review and merge. The infra is ready (SealedSecret deployed, env vars wired, pod healthy). The only thing blocking working auth in prod is this PR.
the-dogfather-cto[bot] (Migrated from github.com) approved these changes 2026-03-28 21:08:24 +00:00
the-dogfather-cto[bot] (Migrated from github.com) left a comment

CTO review: auth fix is correct and P0-urgent. Approving for immediate merge.

Auth changes reviewed:

  • toNodeHandler → auth.handler(c.req.raw) via sub-app mount — fixes Hono 404s
  • authMiddleware + resolveStaffMiddleware skip /api/auth/ paths
  • OIDC_INTERNAL_BASE for split-horizon (hairpin NAT)
  • LoginPage replaces render-time signIn.social() (redirect loop fix)
  • Relative baseURL for deployed envs

All CI green. No debug artifacts in final state.

CTO review: auth fix is correct and P0-urgent. Approving for immediate merge. **Auth changes reviewed:** - toNodeHandler → auth.handler(c.req.raw) via sub-app mount — fixes Hono 404s - authMiddleware + resolveStaffMiddleware skip /api/auth/ paths - OIDC_INTERNAL_BASE for split-horizon (hairpin NAT) - LoginPage replaces render-time signIn.social() (redirect loop fix) - Relative baseURL for deployed envs All CI green. No debug artifacts in final state.
github-actions[bot] commented 2026-03-28 21:13:14 +00:00 (Migrated from github.com)

Deployed to groombook-dev

Images: pr-144
URL: https://dev.groombook.farh.net

Ready for UAT validation.

## Deployed to groombook-dev **Images:** `pr-144` **URL:** https://dev.groombook.farh.net Ready for UAT validation.
the-dogfather-cto[bot] commented 2026-03-28 21:14:14 +00:00 (Migrated from github.com)

CTO review complete — approved. All CI checks pass after branch update.

Blocker: Branch protection requires 2 approving reviews. @cpfarhood's earlier approval was dismissed when the branch was updated to include latest main. Need @cpfarhood or another write-access reviewer to re-approve so we can merge this P0 auth fix.

Prod auth is fully broken without this merge.

CTO review complete — **approved**. All CI checks pass after branch update. **Blocker:** Branch protection requires 2 approving reviews. @cpfarhood's earlier approval was dismissed when the branch was updated to include latest main. Need @cpfarhood or another write-access reviewer to re-approve so we can merge this P0 auth fix. Prod auth is fully broken without this merge.
lint-roller-qa[bot] (Migrated from github.com) approved these changes 2026-03-28 21:37:29 +00:00
lint-roller-qa[bot] (Migrated from github.com) left a comment

QA Approval — PR #144

Verified on https://groombook.dev.farh.net (commit cebf708 deployed):

  • Auth fix: Dev login selector renders correctly. Staff login (Ashley Chen) lands on /admin with full calendar — no redirect loop. /api/auth/** routes return 404 (not 401) for unauthenticated requests — middleware correctly defers to Better-Auth.
  • Reschedule flow (Dashboard): Next Appointment card shows Reschedule button → modal opens with appointment summary, date picker, Cancel and disabled Confirm. ✓
  • Reschedule flow (Appointments section): AppointmentCard expands to show details + Reschedule/Cancel/Add Notes buttons → Reschedule modal opens identically. ✓
  • Console errors: Only pre-existing static asset 404s (favicon.svg, pwa-192x192.png) — unrelated to this PR.
  • CI: All checks green (Lint, Test, E2E, Build, Deploy).

Approving. Handing off to UAT.

**QA Approval — PR #144** Verified on https://groombook.dev.farh.net (commit `cebf708` deployed): - **Auth fix:** Dev login selector renders correctly. Staff login (Ashley Chen) lands on /admin with full calendar — no redirect loop. /api/auth/** routes return 404 (not 401) for unauthenticated requests — middleware correctly defers to Better-Auth. - **Reschedule flow (Dashboard):** Next Appointment card shows Reschedule button → modal opens with appointment summary, date picker, Cancel and disabled Confirm. ✓ - **Reschedule flow (Appointments section):** AppointmentCard expands to show details + Reschedule/Cancel/Add Notes buttons → Reschedule modal opens identically. ✓ - **Console errors:** Only pre-existing static asset 404s (favicon.svg, pwa-192x192.png) — unrelated to this PR. - **CI:** All checks green (Lint, Test, E2E, Build, Deploy). Approving. Handing off to UAT.
This repo is archived. You cannot comment on pull requests.