Compare commits

..

13 Commits

Author SHA1 Message Date
Flea Flicker b3b2113daa fix(db): add missing extended pet profile fields to buildPet factory
CI / Lint & Typecheck (pull_request) Successful in 9s
CI / Test (pull_request) Successful in 9s
CI / Build & Push Docker Images (pull_request) Successful in 47s
Lint Roller (QA) flagged that buildPet in factories.ts was missing the
4 fields added to the pets table schema, causing TS2739 in the Docker
build job (run 1701, job 3717).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 18:31:52 +00:00
Flea Flicker 8c184dddbd fix(schema): add missing extended pet profile fields to packages/db
CI / Test (pull_request) Successful in 10s
CI / Lint & Typecheck (pull_request) Successful in 12s
CI / Build & Push Docker Images (pull_request) Failing after 24s
Add temperamentScore, temperamentFlags, medicalAlerts, and preferredCuts
to the pets table in packages/db/src/schema.ts to match the API schema.

These columns already exist in the database via migration
0030_extended_pet_profile.sql (confirmed by GRO-1748).

Refs: GRO-1752

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 18:19:25 +00:00
The Dogfather 4e8c66f3ca fix: add network=host to buildx driver-opts for DinD DNS resolution
CI / Test (push) Successful in 43s
CI / Lint & Typecheck (push) Successful in 44s
CI / Build & Push Docker Images (push) Failing after 39s
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-23 00:52:59 +00:00
The Dogfather ea28095434 Merge pull request 'fix(GRO-1566): bypass auth for /api/health endpoint on UAT' (#61) from fix/gro-1566-api-health-auth-bypass into dev
CI / Test (push) Failing after 1m33s
CI / Lint & Typecheck (push) Failing after 1m39s
CI / Build & Push Docker Images (push) Has been skipped
2026-05-22 22:39:41 +00:00
Flea Flicker 3b9c72c2c4 fix(GRO-1566): bypass auth for /api/health endpoint on UAT
CI / Lint & Typecheck (pull_request) Failing after 1m27s
CI / Test (pull_request) Failing after 1m38s
CI / Build & Push Docker Images (pull_request) Has been skipped
The /api/health endpoint returns 401 on UAT because authMiddleware
was not skipping it — the health check was registered on the Hono app
instance (not the api sub-router), placing it below authMiddleware on
the base app. The fix adds /api/health to the auth skip list alongside
/api/auth/.

The /health endpoint (registered at app level, above all middleware)
correctly returns 200. The /api/health endpoint must also be public
since the task requires confirming it returns 200.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-22 22:36:15 +00:00
The Dogfather 62dfc7776b Merge pull request 'fix(GRO-1544): register health endpoint at /api/health not /health' (#52) from fix/gro-1544-api-health-endpoint into dev
CI / Lint & Typecheck (push) Failing after 1m29s
CI / Test (push) Failing after 1m29s
CI / Build & Push Docker Images (push) Has been skipped
fix(GRO-1544): register health endpoint at /api/health not /health

Merge PR #52 to dev. Unblocks GRO-1485 UAT regression chain.
2026-05-22 21:49:55 +00:00
The Dogfather 68df697cf3 Merge pull request 'fix(GRO-1533): fix migration 0031 for empty databases' (#57) from fix/gro-1533-migration-0031-coat-type into dev
CI / Test (push) Successful in 16s
CI / Lint & Typecheck (push) Successful in 17s
CI / Build & Push Docker Images (push) Successful in 30s
fix(GRO-1533): fix migration 0031 for empty databases (#57)

Adds ADD COLUMN IF NOT EXISTS for coat_type and pet_size_category before ALTER TYPE casts, making migration safe for both fresh and existing databases.

Reviewed-by: gb_lint (QA)
Approved-by: CTO
2026-05-22 15:20:50 +00:00
Chris Farhood 174d1c667b fix(GRO-1533): add missing coat_type/pet_size_category columns in migration 0031
CI / Lint & Typecheck (pull_request) Successful in 10s
CI / Test (pull_request) Successful in 10s
CI / Build & Push Docker Images (pull_request) Successful in 40s
Migration 0031 tries to ALTER the coat_type and pet_size_category columns
on the pets table to use new enum types, but no prior migration adds
these columns. On a fresh DB (after the reset CronJob wiped all tables),
this causes the entire migration chain to fail and roll back.

Added ADD COLUMN IF NOT EXISTS before the ALTER TYPE so the migration
works both on fresh databases and existing ones with the columns.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-22 15:12:07 +00:00
The Dogfather 9fe6e15012 Merge pull request 'fix(GRO-1533): add missing 0032_staff_read_at.sql migration file' (#55) from fix/gro-1533-missing-migration-0032 into dev
CI / Lint & Typecheck (push) Successful in 9s
CI / Test (push) Successful in 10s
CI / Build & Push Docker Images (push) Successful in 21s
fix(GRO-1533): add missing 0032_staff_read_at.sql migration file

Merged by CTO after QA approval (Review #3513).
Unblocks UAT migration pipeline.
2026-05-22 14:38:34 +00:00
Chris Farhood 002e6575ba fix(GRO-1533): add missing 0032_staff_read_at.sql migration file
CI / Test (pull_request) Successful in 2m30s
CI / Lint & Typecheck (pull_request) Successful in 2m32s
CI / Build & Push Docker Images (pull_request) Successful in 4m6s
The migration journal references 0032_staff_read_at but the SQL file
was never committed. drizzle-kit migrate fails with "No file
./migrations/0032_staff_read_at.sql found" which blocks all subsequent
migrations including the 0033 default_buffer_minutes fix.

Added as a no-op since the staff table schema has no readAt column.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-22 14:28:48 +00:00
The Dogfather f9c679b392 Merge pull request 'fix(GRO-1533): add missing default_buffer_minutes migration' (#53) from fix/gro-1533-missing-migration-journal into dev
CI / Lint & Typecheck (push) Failing after 3s
CI / Test (push) Successful in 9s
CI / Build & Push Docker Images (push) Has been skipped
Merge fix/gro-1533-missing-migration-journal into dev: add missing default_buffer_minutes migration (GRO-1533)
2026-05-22 14:08:55 +00:00
Flea Flicker 7b2b533c16 docs(api): update UAT_PLAYBOOK.md §4.0 — new health endpoint path
CI / Test (pull_request) Successful in 9s
CI / Lint & Typecheck (pull_request) Successful in 10s
CI / Build & Push Docker Images (pull_request) Failing after 46s
Added TC-API-0.1 for GET /api/health (unauthenticated).
Corrected path from /health to /api/health (GRO-1544).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 13:49:15 +00:00
Flea Flicker 55894c6ff2 fix(GRO-1544): register health endpoint at /api/health not /health
The health check was registered on `app` at `/health`, but the HTTPRoute
routes `/api/*` to the API pod. Since auth middleware protects the /api
basePath, GET /api/health fell through to authMiddleware → 401.

Now registered on `api` before auth middleware at /api/health.

Updated UAT_PLAYBOOK.md §GRO-1485 — new health endpoint path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 13:49:15 +00:00
8 changed files with 26 additions and 4 deletions
+2
View File
@@ -78,6 +78,8 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- name: Log in to Gitea Container Registry
uses: docker/login-action@v3
+8
View File
@@ -21,6 +21,14 @@ GroomBook API is a Hono-based REST service (TypeScript/Node.js) powering the pet
## Test Cases
### 4.0 Health Check
| # | Scenario | Steps | Expected |
|---|----------|-------|----------|
| TC-API-0.1 | Unauthenticated health check | GET /api/health | 200 OK, `{"status":"ok"}` |
> **Note (GRO-1544):** Health endpoint registered on `api` basePath before auth middleware at `/api/health`. The old path `/health` was incorrect (routed to web pod via HTTPRoute `/*` rule).
### 4.1 Authentication
| # | Scenario | Steps | Expected |
+3 -1
View File
@@ -6,8 +6,10 @@
CREATE TYPE "pet_size_category" AS ENUM ('small', 'medium', 'large', 'xlarge');
CREATE TYPE "coat_type" AS ENUM ('smooth', 'double', 'wire', 'curly', 'long', 'hairless');
-- ─── Alter pets columns to use new enums ─────────────────────────────────────
-- ─── Add columns to pets if missing, then cast to enums ──────────────────────
ALTER TABLE "pets" ADD COLUMN IF NOT EXISTS "coat_type" text;
ALTER TABLE "pets" ADD COLUMN IF NOT EXISTS "pet_size_category" text;
ALTER TABLE "pets" ALTER COLUMN "coat_type" TYPE "coat_type" USING "coat_type"::text::"coat_type";
ALTER TABLE "pets" ALTER COLUMN "pet_size_category" TYPE "pet_size_category" USING "pet_size_category"::text::"pet_size_category";
@@ -0,0 +1 @@
-- no-op: journal entry exists but no schema change was needed
+4
View File
@@ -105,6 +105,10 @@ export function buildPet(overrides: Partial<PetRow> & { clientId: string }): Pet
photoKey: null,
photoUploadedAt: null,
image: null,
temperamentScore: null,
temperamentFlags: [],
medicalAlerts: [],
preferredCuts: [],
createdAt: new Date("2025-01-01T00:00:00Z"),
updatedAt: new Date("2025-01-01T00:00:00Z"),
};
+5
View File
@@ -11,6 +11,7 @@ import {
unique,
uuid,
} from "drizzle-orm/pg-core";
import type { MedicalAlert } from "@groombook/types";
// ─── Enums ────────────────────────────────────────────────────────────────────
@@ -164,6 +165,10 @@ export const pets = pgTable(
specialCareNotes: text("special_care_notes"),
coatType: coatTypeEnum("coat_type"),
petSizeCategory: petSizeCategoryEnum("pet_size_category"),
temperamentScore: integer("temperament_score"),
temperamentFlags: jsonb("temperament_flags").$type<string[]>().default([]),
medicalAlerts: jsonb("medical_alerts").$type<MedicalAlert[]>().default([]),
preferredCuts: jsonb("preferred_cuts").$type<string[]>().default([]),
customFields: jsonb("custom_fields").$type<Record<string, string>>().notNull().default({}),
photoKey: text("photo_key"),
photoUploadedAt: timestamp("photo_uploaded_at"),
+2 -2
View File
@@ -58,8 +58,8 @@ app.use(
})
);
// Health check (no auth required)
app.get("/health", (c) => c.json({ status: "ok" }));
// Health check no auth required, registered on app at full path before auth middleware
app.get("/api/health", (c) => c.json({ status: "ok" }));
// Public booking routes — no auth required, must be registered before auth middleware
app.route("/api/book", bookRouter);
+1 -1
View File
@@ -23,7 +23,7 @@ if (process.env.AUTH_DISABLED === "true") {
}
export const authMiddleware: MiddlewareHandler = async (c, next) => {
if (c.req.path.startsWith("/api/auth/")) {
if (c.req.path.startsWith("/api/auth/") || c.req.path === "/api/health") {
await next();
return;
}