Compare commits

..

40 Commits

Author SHA1 Message Date
Flea Flicker 2027d0c160 Promote uat → main (PROD): GRO-2572 SSO redirect fix (#93)
CI / Test (push) Successful in 24s
CI / Lint & Typecheck (push) Successful in 33s
CI / Build & Push Docker Image (push) Successful in 12s
2026-06-26 13:38:46 +00:00
Flea Flicker c7b0231eaf chore: promote uat → main (GRO-2516 + accumulated uat work) [frozen] (#90)
CI / Test (push) Successful in 22s
CI / Lint & Typecheck (push) Successful in 30s
CI / Build & Push Docker Image (push) Successful in 16s
chore: promote uat → main (GRO-2516 + accumulated uat work)

Includes: GRO-2516, GRO-2513, GRO-2373, GRO-2359 and older uat work.
Approved by: gb_dogfather (CTO)
2026-06-26 10:48:45 +00:00
Flea Flicker 758a7661f4 Promote uat → main (PROD): GRO-2513 Settings role-gate (#86)
CI / Test (push) Successful in 29s
CI / Lint & Typecheck (push) Successful in 39s
CI / Build & Push Docker Image (push) Successful in 15s
feat(GRO-2513): gate Settings nav+route to manager/super-user, eliminate groomer 403

All pre-merge gates green: CI, QA, UAT 8/8, Security, CTO review.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-25 03:04:33 +00:00
Flea Flicker a7db93f386 Promote uat → main (PROD): GRO-2373 in-portal chrome sign-out button (web) (#81)
CI / Test (push) Successful in 22s
CI / Lint & Typecheck (push) Successful in 29s
CI / Build & Push Docker Image (push) Failing after 10s
Promote uat → main (PROD): GRO-2373 in-portal chrome sign-out button (web) — cherry-pick of PR #78 (commit 532869f9). UAT_PLAYBOOK §3.2 (TC-WEB-5.25.6f) updated.

Refs: GRO-2360 (P3), GRO-2355 (parent), GRO-2357 (breakdown), GRO-2358 (P1), GRO-2359 (P2).
Co-authored-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
Co-committed-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
2026-06-13 02:52:46 +00:00
Flea Flicker 1480a37de1 docs: add AGENTS.md and CONTRIBUTING.md (GRO-2381) (#80)
CI / Test (push) Successful in 24s
CI / Lint & Typecheck (push) Successful in 30s
CI / Build & Push Docker Image (push) Failing after 8s
Co-authored-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
Co-committed-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
2026-06-12 17:00:39 +00:00
Flea Flicker f235dcad81 Promote uat → main (PROD): GRO-2359 OOBE portal-creation routing (web) (#79)
CI / Test (push) Successful in 18s
CI / Lint & Typecheck (push) Successful in 24s
CI / Build & Push Docker Image (push) Successful in 50s
Co-authored-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
Co-committed-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
2026-06-12 16:47:17 +00:00
Flea Flicker 661bd4f902 Promote uat → main (PROD): GRO-2358 logout on no-access screen (#74)
CI / Test (push) Successful in 18s
CI / Lint & Typecheck (push) Successful in 26s
CI / Build & Push Docker Image (push) Successful in 15s
Promote uat → main (PROD): GRO-2358 — restore logout on 'Portal access not configured' screen.

Squashed from uat-to-main/GRO-2358 (0d24fe0).

Cherry-pick of validated uat squash bfe3ccf.

Pre-merge gates green: CI (Lint+Typecheck 30s, Test 23s, Docker Build 11s); CTO Gitea review APPROVED (comment 13465); QA GRO-2362 done; UAT GRO-2363 4/4 PASS on git.farh.net/groombook/web:2026.06.11-bfe3ccf; Security GRO-2364 cleared.

Head branch uat-to-main/GRO-2358 retained for Flea's post-deploy verification.

Refs GRO-2358, GRO-2362, GRO-2363, GRO-2364, GRO-2367.

Co-authored-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
Co-committed-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
2026-06-11 15:43:32 +00:00
Flea Flicker fe565861b9 Promote uat → main (PROD): GRO-2319 portal StatusBadge palette (#71)
CI / Test (push) Successful in 20s
CI / Lint & Typecheck (push) Successful in 25s
CI / Build & Push Docker Image (push) Successful in 20s
Co-authored-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
Co-committed-by: Flea Flicker <22+gb_flea@noreply.git.farh.net>
2026-06-10 08:57:46 +00:00
Scrubs McBarkley 7ef270312c Merge pull request 'Promote uat → main (PROD): GRO-2160 route nav export + offline polish' (#68) from flea/uat-to-main-gro-2160 into main
CI / Test (push) Successful in 19s
CI / Lint & Typecheck (push) Successful in 27s
CI / Build & Push Docker Image (push) Successful in 15s
2026-06-09 05:27:25 +00:00
Flea Flicker f58a0e569b Promote dev → uat: GRO-2160 route nav export + offline polish (#67)
CI / Test (push) Successful in 20s
CI / Lint & Typecheck (push) Successful in 26s
CI / Build & Push Docker Image (push) Successful in 10s
CI / Test (pull_request) Successful in 21s
CI / Lint & Typecheck (pull_request) Successful in 28s
CI / Build & Push Docker Image (pull_request) Successful in 14s
2026-06-09 04:40:32 +00:00
Scrubs McBarkley 2a401a4584 Merge pull request 'Promote uat → main (PROD): GRO-2159 drag-to-reorder + re-optimize + GRO-2236 price/duration display fix'
CI / Test (push) Successful in 18s
CI / Lint & Typecheck (push) Successful in 25s
CI / Build & Push Docker Image (push) Successful in 12s
CEO prod merge. All gates cleared: CTO Phase 4 review #4573 approved, CI green on e93017b, QA PASS (GRO-2281, GRO-2256), post-deploy UAT regression PASS (GRO-2283, GRO-2276), security PASS (GRO-2284). Merging GRO-2159 + GRO-2236 to main.
2026-06-09 04:00:43 +00:00
Flea Flicker e93017b279 Promote dev → uat: GRO-2159 drag-to-reorder + re-optimize (#64)
CI / Test (push) Successful in 35s
CI / Lint & Typecheck (push) Successful in 44s
CI / Build & Push Docker Image (push) Successful in 11s
CI / Test (pull_request) Successful in 21s
CI / Lint & Typecheck (pull_request) Successful in 27s
CI / Build & Push Docker Image (pull_request) Successful in 12s
2026-06-09 03:10:17 +00:00
Scrubs McBarkley 27c59113e2 Merge pull request 'Promote uat → main (PROD): GRO-2158 route planner page' (#62) from flea/uat-to-main-gro-2158 into main
CI / Test (push) Successful in 22s
CI / Lint & Typecheck (push) Successful in 27s
CI / Build & Push Docker Image (push) Failing after 9s
Promote uat → main (PROD): GRO-2158 route planner page

Merged by CEO (gb_scrubs) — board-gated prod merge.
Validated SHA: 980615b (GRO-2272/2273/2274 all PASS).
CTO review: APPROVED (review #4567 by gb_dogfather).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-09 02:37:35 +00:00
Flea Flicker db11e5f2bd Merge pull request 'Promote dev → uat: GRO-2236 portal Book New service cards price + duration' (#58) from flea/dev-to-uat-gro-2236 into uat
CI / Test (push) Successful in 24s
CI / Lint & Typecheck (push) Successful in 30s
CI / Build & Push Docker Image (push) Successful in 48s
2026-06-09 02:13:08 +00:00
Flea Flicker 980615b8e6 Promote dev → uat: GRO-2158 route planner page (#61)
CI / Test (push) Successful in 18s
CI / Lint & Typecheck (push) Successful in 27s
CI / Build & Push Docker Image (push) Successful in 14s
CI / Test (pull_request) Successful in 20s
CI / Lint & Typecheck (pull_request) Successful in 30s
CI / Build & Push Docker Image (pull_request) Successful in 41s
2026-06-09 02:00:55 +00:00
Flea Flicker 95c688764b Merge pull request 'uat→main (PROD): GRO-2234 portal Book New fix + validated batch' (#59) from flea/uat-to-main-gro-2234-web into main
CI / Test (push) Successful in 21s
CI / Lint & Typecheck (push) Successful in 27s
CI / Build & Push Docker Image (push) Successful in 16s
2026-06-09 00:37:47 +00:00
The Dogfather f549101962 fix(GRO-2236): portal Book New service cards show price + duration (#57)
CI / Test (pull_request) Successful in 20s
CI / Lint & Typecheck (pull_request) Successful in 28s
CI / Build & Push Docker Image (pull_request) Successful in 14s
Co-authored-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
Co-committed-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
2026-06-08 23:32:19 +00:00
Flea Flicker 62dc85b560 Promote dev → uat: GRO-2211/2218/2207 + GRO-2234 portal Book New (cumulative) (#56)
CI / Lint & Typecheck (push) Successful in 28s
CI / Test (push) Successful in 28s
CI / Build & Push Docker Image (push) Successful in 41s
CI / Test (pull_request) Successful in 21s
CI / Lint & Typecheck (pull_request) Successful in 27s
CI / Build & Push Docker Image (pull_request) Successful in 47s
2026-06-08 19:58:43 +00:00
Flea Flicker 5bb8fbcb7d Merge pull request 'Promote uat → main (atomic): GRO-2105/2094/2099/2089/2180/2213 portal bundle' (#48) from uat into main
CI / Test (push) Successful in 19s
CI / Lint & Typecheck (push) Successful in 27s
CI / Build & Push Docker Image (push) Successful in 40s
2026-06-08 19:29:49 +00:00
Flea Flicker bc21d6de09 Promote dev → uat: GRO-2213 portal booking preferredTime HH:MM:SS fix (#52)
CI / Test (push) Successful in 21s
CI / Test (pull_request) Successful in 22s
CI / Lint & Typecheck (push) Successful in 26s
CI / Lint & Typecheck (pull_request) Successful in 28s
CI / Build & Push Docker Image (push) Successful in 25s
CI / Build & Push Docker Image (pull_request) Successful in 20s
2026-06-08 17:36:16 +00:00
Flea Flicker 32ef3bca4d Merge pull request 'Promote dev → uat: GRO-2180 portal Appointments ISO startTime fix' (#50) from dev into uat
CI / Lint & Typecheck (pull_request) Failing after 10m47s
CI / Test (push) Failing after 10m51s
CI / Lint & Typecheck (push) Failing after 10m52s
CI / Build & Push Docker Image (push) Has been skipped
CI / Test (pull_request) Failing after 15m38s
CI / Build & Push Docker Image (pull_request) Has been skipped
Merge PR #50: fix(GRO-2180) portal Appointments ISO startTime (dev → uat)

QA-approved (gb_lint); PR CI green after transient runner re-run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 10:28:50 +00:00
Flea Flicker 47c29ecbc2 Promote to UAT: GRO-2105 BookingFlow/RescheduleFlow availability fix (#47)
CI / Test (push) Successful in 17s
CI / Lint & Typecheck (push) Successful in 23s
CI / Build & Push Docker Image (push) Successful in 19s
CI / Test (pull_request) Failing after 10m34s
CI / Lint & Typecheck (pull_request) Failing after 10m34s
CI / Build & Push Docker Image (pull_request) Has been skipped
2026-06-02 19:17:03 +00:00
The Dogfather de7386e47a Promote to UAT: GRO-2094 React bootstrap error instrumentation (#45)
CI / Test (push) Successful in 23s
CI / Lint & Typecheck (push) Successful in 30s
CI / Build & Push Docker Image (push) Successful in 13s
Co-authored-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
Co-committed-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
2026-06-02 18:42:25 +00:00
Scrubs McBarkley fdff0977ad Merge pull request 'Promote uat → main: GRO-2012 RescheduleFlow portalSessionId fallback' (#40) from uat into main
CI / Test (push) Successful in 23s
CI / Lint & Typecheck (push) Successful in 29s
CI / Build & Push Docker Image (push) Successful in 16s
Promote uat → main: GRO-2012 RescheduleFlow portalSessionId fallback

Gate checks:
- UAT: GRO-2023 done (CTO verified, ec29f719)
- Security: GRO-2032 Barkley PASS
- UAT_PLAYBOOK.md: TC-WEB-5.26 present

Fix: CustomerPortal.tsx:329 sessionId={session?.id ?? portalSessionId}
Fix commit: f29f1828c8

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-01 19:10:08 +00:00
The Dogfather ec29f71974 Merge pull request 'Promote to UAT: GRO-2012 RescheduleFlow portalSessionId fallback' (#39) from dev into uat
CI / Test (push) Successful in 21s
CI / Lint & Typecheck (push) Successful in 30s
CI / Build & Push Docker Image (push) Successful in 10s
CI / Test (pull_request) Successful in 21s
CI / Lint & Typecheck (pull_request) Successful in 28s
CI / Build & Push Docker Image (pull_request) Successful in 13s
2026-06-01 17:46:35 +00:00
The Dogfather bd2a0d9516 Merge pull request 'Promote dev -> uat: GRO-2011 login-blank fix (+ GRO-1867)' (#37) from dev into uat
CI / Test (push) Successful in 19s
CI / Lint & Typecheck (push) Successful in 23s
CI / Build & Push Docker Image (push) Successful in 10s
2026-06-01 16:38:14 +00:00
The Dogfather 0e5e9d1f16 Merge pull request 'chore: promote dev → uat (GRO-1829 SW fix)' (#32) from dev into uat
CI / Test (push) Successful in 13s
CI / Lint & Typecheck (push) Successful in 23s
CI / Build & Push Docker Image (push) Successful in 15s
Merge: promote dev → uat (GRO-1829 SW fix)
2026-05-27 02:27:32 +00:00
The Dogfather 3b4d0f15f6 Merge pull request 'chore: promote dev → uat (GRO-1795 StatusBadge)' (#28) from dev into uat
CI / Lint & Typecheck (push) Successful in 17s
CI / Test (push) Successful in 13s
CI / Build & Push Docker Image (push) Successful in 34s
Merge PR #28: promote dev → uat (GRO-1795 StatusBadge)
2026-05-26 13:23:52 +00:00
The Dogfather 87939e5413 Merge pull request 'chore: promote dev → uat (GRO-1794 booking analytics)' (#27) from dev into uat
CI / Test (push) Successful in 19s
CI / Lint & Typecheck (push) Successful in 22s
CI / Build & Push Docker Image (push) Successful in 12s
Merge dev → uat: GRO-1794 booking funnel analytics events
2026-05-26 13:16:39 +00:00
The Dogfather 4e3a038bf3 Merge pull request 'Promote dev → uat (GRO-1793: dynamic time slots)' (#25) from dev into uat
CI / Test (push) Successful in 14s
CI / Lint & Typecheck (push) Successful in 16s
CI / Build & Push Docker Image (push) Failing after 6s
Promote dev → uat: GRO-1793 dynamic portal time slots (#25)
2026-05-26 13:02:16 +00:00
Scrubs McBarkley 2aad7cb6a0 Merge pull request 'promote: uat → main (GRO-1757 SSO auto-provision fix)' (#21) from uat into main
CI / Test (push) Successful in 13s
CI / Lint & Typecheck (push) Successful in 21s
CI / Build & Push Docker Image (push) Successful in 13s
2026-05-26 02:16:28 +00:00
Lint Roller 8349ea00de Merge pull request 'promote: dev → uat (GRO-1757 SSO auto-provision fix)' (#19) from dev into uat
CI / Test (push) Successful in 13s
CI / Lint & Typecheck (push) Successful in 33s
CI / Build & Push Docker Image (push) Successful in 14s
CI / Test (pull_request) Successful in 19s
CI / Lint & Typecheck (pull_request) Successful in 24s
CI / Build & Push Docker Image (pull_request) Successful in 15s
promote: dev → uat (GRO-1757 SSO auto-provision fix)
2026-05-25 23:48:10 +00:00
Chris Farhood 0c41640f59 Add .mcp.json
CI / Test (push) Successful in 20s
CI / Lint & Typecheck (push) Successful in 27s
CI / Build & Push Docker Image (push) Successful in 4m1s
2026-05-24 18:15:24 +00:00
The Dogfather 0306c7fbd9 Merge pull request 'chore(GRO-1592): promote dev→uat SSO session cookie fix' (#16) from promote-uat-gro1592 into uat
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 18s
CI / Build & Push Docker Image (push) Failing after 39s
2026-05-23 14:13:43 +00:00
Chris Farhood 93da2f1dd8 chore: promote dev→uat for GRO-1592 SSO session cookie fix
CI / Lint & Typecheck (pull_request) Successful in 17s
CI / Test (pull_request) Successful in 18s
CI / Build & Push Docker Image (pull_request) Failing after 41s
- Fixed frontend auth client baseURL fallback to use window.location.origin
- Added UAT test coverage (TC-AUTH-5.3.4)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-23 14:13:12 +00:00
The Dogfather 62cbfe4e43 Merge pull request 'promote: dev → uat (GRO-1173 buffer rules + GRO-1470 pet save persistence)' (#14) from dev into uat
CI / Test (push) Successful in 14s
CI / Lint & Typecheck (push) Successful in 19s
CI / Build & Push Docker Image (push) Successful in 9s
promote: dev → uat (GRO-1173 buffer rules + GRO-1470 pet save persistence) (#14)

Merged-By: The Dogfather (CTO)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-21 19:46:41 +00:00
The Dogfather db6a2a1bbf Merge pull request 'promote: dev → uat (Renovate config, GRO-1081)' (#11) from dev into uat
promote: dev → uat (Renovate config, GRO-1081)

Merge PR #11: dev → uat promotion
Includes: chore: add Renovate config (GRO-1081)
2026-05-20 12:42:04 +00:00
The Dogfather 032a3796ba Merge pull request 'chore: promote dev to uat (CI Docker registry fix)' (#10) from dev into uat
chore: promote dev to uat (CI Docker registry fix) (#10)

Promotes GRO-1348 CI registry fix to UAT.
2026-05-20 11:17:21 +00:00
the-dogfather-cto[bot] cac8fc947e chore(GRO-1289): promote dev to uat — add UAT_PLAYBOOK.md
chore(GRO-1289): promote dev to uat — add UAT_PLAYBOOK.md
2026-05-14 21:13:56 +00:00
the-dogfather-cto[bot] 592be1301c chore: promote dev to uat (#3)
chore: promote dev to uat
2026-05-11 13:19:33 +00:00
9 changed files with 270 additions and 5 deletions
+10
View File
@@ -6,3 +6,13 @@ dist/
playwright-report/ playwright-report/
test-results/ test-results/
*.log *.log
# Agent runtime artifacts — never commit
.gh-token
*.gh-token
**/.gh-token
.config/gh/
**/.config/gh/
**/AGENT_HOME/**
$AGENT_HOME/**
.claude/
.codex/
+54
View File
@@ -0,0 +1,54 @@
# AGENTS.md
This repository (`groombook/web`) is part of the GroomBook application stack. The
authoritative process, quality bar, and safety rules live in the shared
[`groombook/org`](https://git.farh.net/groombook/org) skills repository. Read
those first; this file is only a pointer.
## Authoritative skills
- **SDLC (branching, PRs, phases, handoffs):**
[`groombook/org/skills/sdlc/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/sdlc/SKILL.md)
- **Coding standards (priority ordering, PR discipline, tests, no-hardcoded-values, CalVer):**
[`groombook/org/skills/coding-standards/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/coding-standards/SKILL.md)
- **Safety (no plaintext secrets, no direct `kubectl apply` to `groombook`, no self-merge, board approval for destructive actions):**
[`groombook/org/skills/safety/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/safety/SKILL.md)
For human contributors and humans reviewing agent work, see
[`CONTRIBUTING.md`](./CONTRIBUTING.md) in this repo for the phase-by-phase PR
flow and the `uat→main` merge-gate policy summary.
## Non-negotiable operational rules
These mirror the org skills; they are restated here so any agent landing in
this repo sees them without a cross-repo fetch.
- **All changes go through a PR.** Never push directly to `dev`, `uat`, or `main`.
- **Branch strategy:** `feature/<name>``dev``uat``main`. Engineers
always target `dev` first.
- **No self-merge contract.** The engineer who opened a PR clicks merge only
after the named reviewer (CI / QA / UAT / Security / CTO per phase)
approves. Issue-thread QA / UAT / security approvals do **not** clear the
Gitea `required_approvals` gate on `uat→main` — only a Gitea **Approve**
click from a member of the `approvals_whitelist_username` does. On this
repo that whitelist is `["gb_flea", "gb_dogfather"]` (engineer team).
Board-level accounts cannot give the Approve click by policy.
- **Always include `cc @cpfarhood`** at the bottom of every PR body for
board visibility (not as a reviewer).
- **Secrets in code are forbidden.** Use Bitnami Sealed Secrets; never commit
plaintext. See the `safety` skill.
- **Production (`groombook` namespace) is Flux-managed.** Never
`kubectl apply` directly. Infrastructure changes go through PRs in
`groombook/infra`.
## Local development
See the repo's own README, package scripts, and CI workflow. The
authoritative pipeline (Gitea Actions, image build, deploy hooks) is the
shared `groombook/infra` overlay; do not reimplement it here.
## When uncertain
If a task conflicts with the org skills, **the org skills win**. Open an
issue in `groombook/org` to propose a change rather than encoding a local
exception.
+117
View File
@@ -0,0 +1,117 @@
# Contributing to `groombook/web`
Thanks for contributing. This document is the human-facing companion to
[`AGENTS.md`](./AGENTS.md) and the authoritative
[`groombook/org`](https://git.farh.net/groombook/org) skills. The org skills
govern; this file is a quick-reference for the human/agent PR flow in this
repo.
## Branch strategy
Three long-lived branches; one PR per promotion step.
| Branch | Environment | Who merges | Prerequisites for merge |
|---------|-------------|-----------|-------------------------|
| `dev` | Dev | Engineer | CI passes |
| `uat` | UAT | Engineer | QA code review approval |
| `main` | Production | Engineer | UAT validation + CTO Gitea Approve when the `uat→main` merge-gate policy applies (see below) |
Engineers always target `dev` first. Feature branches: `<agent-name>/<short-description>`.
## Phase-by-phase PR flow
### Phase 1 — Dev
1. Branch from `dev`: `git checkout -b <name>/<short-description> origin/dev`.
2. Write code + tests. Run unit tests, type check, and lint locally (or rely on CI).
3. Open a PR against `dev`:
```bash
tea pr create --base dev --title "..." --body "..."
```
Include `cc @cpfarhood` at the bottom of the body for board visibility.
4. CI must pass. CI green → engineer self-merges.
5. CI builds and deploys to Dev automatically.
### Phase 2 — UAT promotion
1. Open a PR from `dev` to `uat`.
2. CI must pass.
3. **QA (Lint Roller)** reviews and approves on the Gitea PR.
4. QA approved → engineer self-merges.
5. CI builds and deploys to UAT automatically.
### Phase 3 — UAT regression + Security review
1. **UAT (Shedward Scissorhands)** runs full regression against UAT — every
feature, old and new, no exceptions.
2. **Security (Barkley Trimsworth)** reviews the changes.
3. Failures in either gate bounce back to Phase 1.
### Phase 4 — Production promotion (`uat → main`)
This is the gate the org PR
[`groombook/org#13`](https://git.farh.net/groombook/org/pulls/13) defines.
The full rule is in
[`groombook/org/skills/sdlc/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/sdlc/SKILL.md)
and
[`groombook/org/skills/coding-standards/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/coding-standards/SKILL.md);
the summary is below.
**The CTO Gitea Approve click is NOT the default gate.** Once the four
pre-gates (QA, UAT deploy, UAT regression, security) are green, the engineer
self-merges.
**A CTO Gitea Approve click IS required** only for PRs in one of three
categories:
1. **Novel auth / session paths** — login, OIDC, OOBE, session middleware,
token issuance, password reset, MFA, new auth provider integrations.
Routine auth-gated UI (button styling, error messages, form layout) is
**not** in this category.
2. **Infra / prod-affecting merges** — deploys, infra manifests, secrets,
GitOps overlays, CI/CD, `main` branch protection, production
routing/ingress, prod state mutations. All Phase 5 infra overlay PRs in
`groombook/infra` require CTO Gitea Approve without exception.
3. **Risk-flagged merges** — `risk:cto-approve` label, or explicit CTO/CEO
sign-off request in the PR or issue thread.
The engineer opens the `uat→main` PR, classifies it against the three
categories above, and adds `cc @cpfarhood`. If the PR is in scope, the CTO
clicks Approve; once approved (and the four pre-gates are green), the
engineer merges.
### Phase 5 — Production deployment
A separate PR in `groombook/infra` bumps the overlay image tag for prod.
Handed to QA (Lint Roller) for review, then self-merged by the engineer.
## The four pre-gates (uat→main)
A `uat→main` PR is mergeable when **all four** are green:
1. **QA code review** — done on the dev→uat promotion PR.
2. **UAT deploy** — the UAT image built from the uat tip is live in UAT.
3. **UAT regression** — Shedward's full-feature UAT pass is green (no
pre-existing defects, no new defects).
4. **Security review** — Barkley's security code review is green.
Issue-thread QA / UAT / security approvals do **not** clear the Gitea
`required_approvals` gate. Only a Gitea **Approve** click from a member of
the `approvals_whitelist_username` for `main` clears it. In this repo that
whitelist is the engineer team (`gb_flea`, `gb_dogfather`).
## Style, tests, and quality bar
See
[`groombook/org/skills/coding-standards/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/coding-standards/SKILL.md)
for the engineering priority ordering, test requirements, no-hardcoded-values
rules, CalVer versioning policy, and the `git.farh.net` container registry
policy.
## Safety
See
[`groombook/org/skills/safety/SKILL.md`](https://git.farh.net/groombook/org/src/branch/main/skills/safety/SKILL.md)
for the non-negotiable rules: no plaintext secrets, no `kubectl apply` to
`groombook`, no self-merge, no direct `tofu` runs, board approval for
destructive actions, escalation protocol.
+10 -1
View File
@@ -86,7 +86,7 @@ export const { signIn, signOut, useSession, changePassword } = authClient;
| # | Scenario | Steps | Pass Criteria | Fail Criteria | | # | Scenario | Steps | Pass Criteria | Fail Criteria |
|---|----------|-------|---------------|---------------| |---|----------|-------|---------------|---------------|
| TC-WEB-SSO-1 | Sign-in page shows SSO button | Navigate to app root URL | Sign-in page displayed with "Sign in with SSO" button visible | No SSO button, 403 before page loads | | TC-WEB-SSO-1 | Sign-in page shows SSO button | Navigate to app root URL | Sign-in page displayed with "Sign in with SSO" button visible | No SSO button, 403 before page loads |
| TC-WEB-SSO-2 | Click SSO redirects to Authentik | Click "Sign in with SSO" button | Browser redirected to Authentik login at auth.farh.net | No redirect, error shown, button does nothing | | TC-WEB-SSO-2 | Click SSO redirects to Authentik (GRO-2572) | **Fresh session only (no pre-existing auth cookie).** Click "Sign in with SSO" button | Browser navigates to Authentik login at auth.farh.net within ~1 s — address bar changes to auth.farh.net URL | No redirect, error shown, button stays disabled, user remains on /login. Regression: prior to GRO-2572 fix the client never followed the `data.url` returned by Better Auth. Run from a clean incognito context to avoid a stale cookie masking the defect. |
| TC-WEB-SSO-3 | Valid OIDC credentials authenticate | At Authentik, enter valid credentials and authenticate | Redirected back to app with active session | Redirect loop, 403, session not established | | TC-WEB-SSO-3 | Valid OIDC credentials authenticate | At Authentik, enter valid credentials and authenticate | Redirected back to app with active session | Redirect loop, 403, session not established |
| TC-WEB-SSO-4 | Post-login dashboard accessible | After SSO flow completes, dashboard loads | Dashboard displays correctly with user identity shown | Blank page, 403, session not active | | TC-WEB-SSO-4 | Post-login dashboard accessible | After SSO flow completes, dashboard loads | Dashboard displays correctly with user identity shown | Blank page, 403, session not active |
| TC-WEB-SSO-5 | User identity displayed correctly | After SSO login, check header/nav | User name/email/initials shown in nav, role reflected in UI | No user indicator, wrong user shown | | TC-WEB-SSO-5 | User identity displayed correctly | After SSO login, check header/nav | User name/email/initials shown in nav, role reflected in UI | No user indicator, wrong user shown |
@@ -320,6 +320,15 @@ the seeded UAT customer (`uat-customer@groombook.dev`), not just unit-rendered.
| TC-WEB-5.16.2 | PWA install prompt | Load app on supported browser | Install prompt appears when criteria met | | TC-WEB-5.16.2 | PWA install prompt | Load app on supported browser | Install prompt appears when criteria met |
| TC-WEB-5.16.3 | Touch interactions | Use touch gestures on mobile | All interactions work with touch input | | TC-WEB-5.16.3 | Touch interactions | Use touch gestures on mobile | All interactions work with touch input |
#### 5.16a Portal Tab Rows — Mobile Overflow (GRO-730 / GRO-1026)
| # | Scenario | Steps | Expected |
|---|----------|-------|----------|
| TC-WEB-5.16.4 | My Pets tab row — horizontal scroll, no visible scrollbar | Sign in as customer → My Pets. Set viewport to 390px. If 3+ pets are seeded, the pet-selector row overflows. | Pet selector row scrolls horizontally; native scrollbar is **not** visible (`scrollbar-width: none` / `scrollbar-hide` applied). |
| TC-WEB-5.16.5 | My Pets section tab row — no visible scrollbar | On the same My Pets view, observe the tabs row (Basic Info / Medical / Grooming / History). | Tabs row scrolls horizontally when needed; native scrollbar is not visible. |
| TC-WEB-5.16.6 | Billing/Payments tab row — no wrap, no visible scrollbar | Sign in as customer → Billing/Payments at 390px. | Tab row (Invoices / Payment Methods / Packages) does **not** wrap to a second line; scrolls horizontally if needed; native scrollbar not visible. |
| TC-WEB-5.16.7 | Desktop — no visual regression | Open My Pets and Billing/Payments at ≥1024px. | No layout change; tab rows display identically to before the fix. |
### 5.17 Error & Empty States ### 5.17 Error & Empty States
| # | Scenario | Steps | Expected | | # | Scenario | Steps | Expected |
+6
View File
@@ -45,6 +45,12 @@ function LoginPage() {
if (result?.error) { if (result?.error) {
setError(result.error.message ?? "Sign-in failed"); setError(result.error.message ?? "Sign-in failed");
setIsLoading(false); setIsLoading(false);
return;
}
// Better Auth returns the IdP authorize URL in data.url with redirect:true rather than
// issuing an HTTP 30x — the client must follow it (GRO-2572).
if (result?.data?.url) {
window.location.href = result.data.url;
} }
}; };
+60
View File
@@ -1,5 +1,6 @@
import { describe, it, expect, vi, beforeEach } from "vitest"; import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, within, waitFor } from "@testing-library/react"; import { render, screen, within, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MemoryRouter } from "react-router-dom"; import { MemoryRouter } from "react-router-dom";
import { App } from "../App"; import { App } from "../App";
@@ -232,6 +233,7 @@ describe("Dev login selector", () => {
}); });
it("does not redirect when a dev user is already selected", async () => { it("does not redirect when a dev user is already selected", async () => {
localStorage.setItem("dev-user", JSON.stringify({ type: "staff", id: "s1", name: "Sarah" })); localStorage.setItem("dev-user", JSON.stringify({ type: "staff", id: "s1", name: "Sarah" }));
global.fetch = vi.fn((url: string) => { global.fetch = vi.fn((url: string) => {
@@ -269,3 +271,61 @@ describe("Dev login selector", () => {
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
}); });
describe("GRO-2572 — SSO button follows redirect URL", () => {
it("navigates to data.url when signIn.social returns a redirect", async () => {
// Mock signIn.social to return the redirect payload Better Auth sends
vi.mock("../lib/auth-client.js", () => ({
useSession: () => ({ data: null, isPending: false }),
signIn: {
social: vi.fn().mockResolvedValue({
data: { redirect: true, url: "https://auth.farh.net/application/o/authorize/?test=1" },
error: null,
}),
},
signOut: vi.fn(),
changePassword: vi.fn(),
}));
const assignMock = vi.fn();
Object.defineProperty(window, "location", {
value: { ...window.location, href: "", origin: "https://uat.groombook.dev" },
writable: true,
});
Object.defineProperty(window.location, "href", {
set: assignMock,
get: () => "",
});
global.fetch = vi.fn((url: string) => {
if (url === "/api/dev/config") {
return Promise.resolve({ ok: true, json: async () => ({ authDisabled: false }) } as Response);
}
if (url === "/api/auth/get-session") {
return Promise.resolve({ ok: true, json: async () => null } as unknown as Response);
}
if (url === "/api/setup/status") {
return Promise.resolve({ ok: true, json: async () => ({ needsSetup: false }) } as Response);
}
if (url === "/api/auth/providers") {
return Promise.resolve({ ok: true, json: async () => ({ providers: ["authentik"] }) } as Response);
}
return Promise.resolve({ ok: true, json: async () => [] } as Response);
}) as unknown as typeof fetch;
render(
<MemoryRouter initialEntries={["/login"]}>
<App />
</MemoryRouter>
);
const ssoButton = await screen.findByRole("button", { name: /sign in with sso/i });
await userEvent.click(ssoButton);
await waitFor(() => {
expect(assignMock).toHaveBeenCalledWith(
"https://auth.farh.net/application/o/authorize/?test=1"
);
});
});
});
+9
View File
@@ -78,6 +78,15 @@ input:focus, select:focus, textarea:focus {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
} }
/* ─── Scrollbar hide utility ─── */
.scrollbar-hide {
scrollbar-width: none;
-ms-overflow-style: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
/* ─── Scrollbar polish ─── */ /* ─── Scrollbar polish ─── */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; width: 6px;
+1 -1
View File
@@ -130,7 +130,7 @@ function BillingPaymentsInner({ sessionId, readOnly }: BillingPaymentsProps) {
</div> </div>
)} )}
<div className="flex gap-2 flex-wrap"> <div className="flex gap-2 overflow-x-auto scrollbar-hide">
{([ {([
{ id: "invoices" as const, label: "Invoices", icon: DollarSign }, { id: "invoices" as const, label: "Invoices", icon: DollarSign },
{ id: "payment" as const, label: "Payment Methods", icon: CreditCard }, { id: "payment" as const, label: "Payment Methods", icon: CreditCard },
+2 -2
View File
@@ -145,7 +145,7 @@ export function PetProfiles({ sessionId, readOnly }: Props) {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{/* Pet Selector */} {/* Pet Selector */}
<div className="flex gap-3 overflow-x-auto pb-1"> <div className="flex gap-3 overflow-x-auto pb-1 scrollbar-hide">
{pets.map(p => ( {pets.map(p => (
<button <button
key={p.id} key={p.id}
@@ -191,7 +191,7 @@ export function PetProfiles({ sessionId, readOnly }: Props) {
)} )}
{/* Tabs */} {/* Tabs */}
<div className="flex gap-1 bg-white rounded-xl border border-stone-200 p-1 overflow-x-auto"> <div className="flex gap-1 bg-white rounded-xl border border-stone-200 p-1 overflow-x-auto scrollbar-hide">
{([ {([
{ id: "info", label: "Basic Info", icon: PawPrint }, { id: "info", label: "Basic Info", icon: PawPrint },
{ id: "medical", label: "Medical", icon: Heart }, { id: "medical", label: "Medical", icon: Heart },