Compare commits

...

15 Commits

Author SHA1 Message Date
Chris Farhood 467b85abc7 fix(docker): use pnpm --filter for all monorepo package builds
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Successful in 27s
Use pnpm --filter consistently for all three package builds in the
Dockerfile instead of mixing filter and cd approaches. Also set
--project . explicitly on tsc invocations to ensure tsconfig resolution
from the package directory rather than workspace root.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:55:24 +00:00
Chris Farhood e417d8f6a7 fix(docker): use absolute tsconfig.json path for tsc
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Failing after 19s
tsc -p /app does not resolve to tsconfig.json at /app/tsconfig.json
without an explicit filename. Pass the full path.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:51:51 +00:00
Chris Farhood fc82e24ead fix(docker): use absolute tsconfig path for api build
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Image (pull_request) Failing after 20s
When pnpm --filter runs the api package build, tsc cannot find the
tsconfig.json. Use an absolute path to avoid any ambiguity about the
working directory context.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:49:56 +00:00
Chris Farhood c3c99ad6c4 fix(docker): use -p flag for explicit tsconfig path
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Failing after 20s
Both -p . and --project . should be equivalent, but the Docker build
appears to resolve them differently. Use -p for consistency.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:40:38 +00:00
Chris Farhood a205fe1138 fix(docker): cd into packages/db before building
CI / Lint & Typecheck (pull_request) Successful in 16s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Image (pull_request) Failing after 20s
pnpm --filter runs in the workspace root where tsc finds the root
tsconfig.json instead of packages/db/tsconfig.json. Change into the
package directory so tsc picks up the correct local tsconfig.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:37:10 +00:00
Chris Farhood 01069f8c6c fix(docker): use explicit tsconfig in db package build
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Failing after 20s
tsc without --project traverses up to workspace root, which has a
different tsconfig.json that lacks package-local paths. Fix both
@groombook/types and @groombook/db scripts consistently.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:33:26 +00:00
Chris Farhood 43f17dc612 fix(docker): use explicit tsconfig in api build command
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Failing after 22s
tsc without --project flag picks up tsconfig.json from the workspace
root, which lacks the packages/* paths needed for the monorepo build.
Explicit --project . ensures tsc uses the local tsconfig.json.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 12:29:40 +00:00
Chris Farhood d9bfed4424 fix(GRO-1350): add missing coatType and petSizeCategory to buildPet defaults
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Failing after 20s
PetRow (pets.$inferSelect) now includes these nullable columns after
the GRO-1174 migration, but buildPet's defaults were never updated.
Adding null defaults fixes the typecheck failure in CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 11:26:11 +00:00
Chris Farhood 1403517067 fix(GRO-1350): use explicit tsconfig path in packages/types build
CI / Lint & Typecheck (pull_request) Failing after 13s
CI / Test (pull_request) Successful in 21s
CI / Build & Push Docker Image (pull_request) Has been skipped
tsc without --project flag fails to find tsconfig.json when run from
a nested package directory inside a Docker COPY layer that overlays
files after deps install. Use explicit --project . to ensure tsc
finds the local tsconfig.json regardless of working directory context.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 11:16:50 +00:00
Chris Farhood 9c5e470737 Save petSizeCategory to pet record on booking creation
CI / Lint & Typecheck (pull_request) Failing after 15s
CI / Test (pull_request) Successful in 23s
CI / Build & Push Docker Image (pull_request) Has been skipped
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 05:25:59 +00:00
Chris Farhood f1258023ac feat(GRO-1174): add MedicalAlert/CoatType/AlertSeverity types to @groombook/types
Sync api packages/types with web workspace — add MedicalAlert, AlertSeverity,
CoatType, preferredCuts, medicalAlerts, temperamentScore, temperamentFlags.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 04:54:03 +00:00
Chris Farhood faf7def77d feat(GRO-1174): persist petSizeCategory and petCoatType from booking
- Add petSizeCategory and petCoatType to bookingSchema zod validator (optional)
- Save coatType to pets row on booking creation
- Add coatType and petSizeCategory columns to pets DB schema
- Add coatType and petSizeCategory to Pet interface in @groombook/types

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 04:40:42 +00:00
Chris Farhood 539ef21d89 fix(ci): use REGISTRY_TOKEN for Docker push auth
CI / Lint & Typecheck (pull_request) Successful in 18s
CI / Test (pull_request) Successful in 24s
CI / Build & Push Docker Image (pull_request) Failing after 21s
Use the org-level REGISTRY_TOKEN secret instead of gitea.token for
authenticating to the Gitea Container Registry. The gitea.token
does not have packages:write scope.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-20 03:41:52 +00:00
Scrubs McBarkley 4f981bbebd chore: remove legacy .github/workflows
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 20s
CI / Build & Push Docker Image (pull_request) Failing after 1m51s
2026-05-20 01:25:33 +00:00
Scrubs McBarkley d8f2135506 chore: migrate CI workflow to .gitea/workflows 2026-05-20 01:25:26 +00:00
9 changed files with 37 additions and 16 deletions
@@ -62,10 +62,6 @@ jobs:
name: Build & Push Docker Image name: Build & Push Docker Image
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [lint-typecheck, test] needs: [lint-typecheck, test]
permissions:
contents: read
packages: write
id-token: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -83,12 +79,12 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry - name: Log in to Gitea Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: git.farh.net
username: ${{ github.actor }} username: ${{ gitea.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push API image - name: Build and push API image
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
@@ -97,7 +93,7 @@ jobs:
file: Dockerfile file: Dockerfile
push: true push: true
tags: | tags: |
ghcr.io/groombook/api:${{ steps.version.outputs.tag }} git.farh.net/groombook/api:${{ steps.version.outputs.tag }}
${{ github.ref == 'refs/heads/main' && 'ghcr.io/groombook/api:latest' || '' }} ${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/api:latest' || '' }}
cache-from: type=gha cache-from: type=registry,ref=git.farh.net/groombook/cache:api
cache-to: type=gha,mode=max cache-to: type=registry,ref=git.farh.net/groombook/cache:api,mode=max
+1 -1
View File
@@ -16,7 +16,7 @@ COPY packages/ packages/
COPY src/ src/ COPY src/ src/
RUN pnpm --filter @groombook/types build && \ RUN pnpm --filter @groombook/types build && \
pnpm --filter @groombook/db build && \ pnpm --filter @groombook/db build && \
pnpm build pnpm --filter @groombook/api build
# Runtime # Runtime
FROM node:20-alpine AS runner FROM node:20-alpine AS runner
+1 -1
View File
@@ -5,7 +5,7 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "tsx watch src/index.ts", "dev": "tsx watch src/index.ts",
"build": "tsc", "build": "tsc --project .",
"start": "node dist/index.js", "start": "node dist/index.js",
"lint": "eslint src --ext .ts", "lint": "eslint src --ext .ts",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
+1 -1
View File
@@ -16,7 +16,7 @@
} }
}, },
"scripts": { "scripts": {
"build": "tsc", "build": "tsc --project .",
"generate": "drizzle-kit generate", "generate": "drizzle-kit generate",
"migrate": "drizzle-kit migrate", "migrate": "drizzle-kit migrate",
"seed": "tsx src/seed.ts", "seed": "tsx src/seed.ts",
+2
View File
@@ -99,6 +99,8 @@ export function buildPet(overrides: Partial<PetRow> & { clientId: string }): Pet
cutStyle: null, cutStyle: null,
shampooPreference: null, shampooPreference: null,
specialCareNotes: null, specialCareNotes: null,
coatType: null,
petSizeCategory: null,
customFields: {}, customFields: {},
photoKey: null, photoKey: null,
photoUploadedAt: null, photoUploadedAt: null,
+2
View File
@@ -142,6 +142,8 @@ export const pets = pgTable(
cutStyle: text("cut_style"), cutStyle: text("cut_style"),
shampooPreference: text("shampoo_preference"), shampooPreference: text("shampoo_preference"),
specialCareNotes: text("special_care_notes"), specialCareNotes: text("special_care_notes"),
coatType: text("coat_type"),
petSizeCategory: text("pet_size_category"),
customFields: jsonb("custom_fields").$type<Record<string, string>>().notNull().default({}), customFields: jsonb("custom_fields").$type<Record<string, string>>().notNull().default({}),
photoKey: text("photo_key"), photoKey: text("photo_key"),
photoUploadedAt: timestamp("photo_uploaded_at"), photoUploadedAt: timestamp("photo_uploaded_at"),
+1 -1
View File
@@ -12,7 +12,7 @@
} }
}, },
"scripts": { "scripts": {
"build": "tsc", "build": "tsc --project .",
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"devDependencies": { "devDependencies": {
+17
View File
@@ -39,6 +39,12 @@ export interface Pet {
cutStyle: string | null; cutStyle: string | null;
shampooPreference: string | null; shampooPreference: string | null;
specialCareNotes: string | null; specialCareNotes: string | null;
coatType: string | null;
petSizeCategory: string | null;
preferredCuts: string[];
medicalAlerts: MedicalAlert[];
temperamentScore?: number;
temperamentFlags?: string[];
customFields: Record<string, string>; customFields: Record<string, string>;
photoKey?: string; photoKey?: string;
photoUploadedAt?: string; photoUploadedAt?: string;
@@ -208,3 +214,14 @@ export interface PaginatedList<T> {
page: number; page: number;
pageSize: number; pageSize: number;
} }
export type AlertSeverity = "low" | "medium" | "high";
export interface MedicalAlert {
id: string;
type: string;
description: string;
severity: AlertSeverity;
}
export type CoatType = "smooth" | "double" | "curly" | "wire" | "long" | "hairless";
+4
View File
@@ -112,6 +112,8 @@ const bookingSchema = z.object({
petName: z.string().min(1).max(200), petName: z.string().min(1).max(200),
petSpecies: z.string().min(1).max(100), petSpecies: z.string().min(1).max(100),
petBreed: z.string().max(100).optional(), petBreed: z.string().max(100).optional(),
petSizeCategory: z.string().max(50).optional(),
petCoatType: z.string().max(50).optional(),
notes: z.string().max(2000).optional(), notes: z.string().max(2000).optional(),
}); });
@@ -191,6 +193,8 @@ bookRouter.post(
name: body.petName, name: body.petName,
species: body.petSpecies, species: body.petSpecies,
breed: body.petBreed ?? null, breed: body.petBreed ?? null,
coatType: body.petCoatType ?? null,
petSizeCategory: body.petSizeCategory ?? null,
}) })
.returning(); .returning();
const pet = petInserted[0]; const pet = petInserted[0];