diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b95ad64..1438d3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,8 @@ jobs: run: pnpm install --frozen-lockfile - name: Build all packages + env: + VITE_API_URL: "" run: pnpm build docker: @@ -340,7 +342,7 @@ jobs: name: Update Infra Image Tags runs-on: ubuntu-latest needs: [docker] - if: github.ref == 'refs/heads/main' && github.event_name == 'push' + if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev') && github.event_name == 'push' permissions: contents: write pull-requests: write diff --git a/.github/workflows/promote-to-uat.yml b/.github/workflows/promote-to-uat.yml index 083e013..22f5680 100644 --- a/.github/workflows/promote-to-uat.yml +++ b/.github/workflows/promote-to-uat.yml @@ -38,7 +38,7 @@ jobs: run: | echo "Updating UAT overlay image tags to: $TAG" cd /tmp/infra - UAT_KUST="apps/groombook/overlays/uat/kustomization.yaml" + UAT_KUST="apps/overlays/uat/kustomization.yaml" if [ ! -f "$UAT_KUST" ]; then echo "ERROR: UAT overlay not found at $UAT_KUST. Ensure GRO-427 has been completed." @@ -55,7 +55,7 @@ jobs: yq -i '(.images[] | select(.name == "ghcr.io/groombook/seed")).newTag = env(TAG)' "$UAT_KUST" # Update migrate Job name to include short SHA (immutable template fix) - MIGRATE_JOB="apps/groombook/base/migrate-job.yaml" + MIGRATE_JOB="apps/base/migrate-job.yaml" if [ -f "$MIGRATE_JOB" ]; then yq -i '.metadata.name = "migrate-schema-" + env(SHORT_SHA)' "$MIGRATE_JOB" yq -i '.metadata.annotations."groombook.app/deploy-version" = env(TAG)' "$MIGRATE_JOB" @@ -64,7 +64,7 @@ jobs: # Update seed Job name to include short SHA (immutable template fix) # NOTE: Do NOT update the image tag here — let the Kustomize images transformer # in the UAT overlay handle it via newTag. This avoids the immutable template issue. - SEED_JOB="apps/groombook/base/seed-job.yaml" + SEED_JOB="apps/base/seed-job.yaml" if [ -f "$SEED_JOB" ]; then yq -i '.metadata.name = "seed-test-data-" + env(SHORT_SHA)' "$SEED_JOB" yq -i '.metadata.annotations."groombook.app/deploy-version" = env(TAG)' "$SEED_JOB" @@ -81,7 +81,7 @@ jobs: git config user.name "groombook-engineer[bot]" git config user.email "3141748+groombook-engineer[bot]@users.noreply.github.com" git checkout -b "chore/update-uat-image-tags-${TAG}" - git add apps/groombook/overlays/uat/ apps/groombook/base/migrate-job.yaml apps/groombook/base/seed-job.yaml + git add apps/overlays/uat/ apps/base/migrate-job.yaml apps/base/seed-job.yaml git commit -m "chore: promote ${TAG} to UAT" git push -u origin "chore/update-uat-image-tags-${TAG}" diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index eb110fa..f551990 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -11,6 +11,8 @@ RUN pnpm install --frozen-lockfile # Build FROM deps AS builder +ARG VITE_API_URL= +ENV VITE_API_URL= COPY packages/types/ packages/types/ COPY apps/web/ apps/web/ RUN pnpm --filter @groombook/web build diff --git a/apps/web/src/lib/auth-client.ts b/apps/web/src/lib/auth-client.ts index 6a9939a..7c5db68 100644 --- a/apps/web/src/lib/auth-client.ts +++ b/apps/web/src/lib/auth-client.ts @@ -1,7 +1,7 @@ import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ - baseURL: import.meta.env.VITE_API_URL ?? "", + baseURL: import.meta.env.VITE_API_URL || window.location.origin, }); export const { signIn, signOut, useSession, changePassword } = authClient; \ No newline at end of file diff --git a/packages/db/src/seed.ts b/packages/db/src/seed.ts index 4563ce7..058b7c9 100644 --- a/packages/db/src/seed.ts +++ b/packages/db/src/seed.ts @@ -883,6 +883,7 @@ async function seed() { let appointmentCount = 0; let invoiceCount = 0; let visitLogCount = 0; + let paidInvoiceCounter = 0; // Process in batches per client to keep memory manageable const apptBatchSize = 100; @@ -977,8 +978,11 @@ async function seed() { const invoiceStatus = rand() < 0.95 ? "paid" as const : "pending" as const; const paidAt = invoiceStatus === "paid" ? new Date(endTime.getTime() + randInt(5, 30) * 60 * 1000) : null; + paidInvoiceCounter++; + const stripePaymentIntentId = invoiceStatus === "paid" + ? `pi_test_seed_${String(paidInvoiceCounter).padStart(6, "0")}` + : null; - const stripePaymentIntentId = invoiceStatus === "paid" && rand() < 0.2 ? `pi_test_${uuid().replace(/-/g, "").slice(0, 24)}` : null; invoiceBatch.push({ id: invoiceId, appointmentId: apptId, @@ -1094,14 +1098,16 @@ async function seed() { const taxCents = Math.round(effectivePrice * 0.08); const totalCents = effectivePrice + taxCents + tipCents; const paidAt = new Date(endTime.getTime() + randInt(5, 30) * 60 * 1000); - const stripePaymentIntentId = rand() < 0.2 ? `pi_test_${uuid().replace(/-/g, "").slice(0, 24)}` : null; + paidInvoiceCounter++; invoiceBatch.push({ id: invoiceId, appointmentId: apptId, clientId, subtotalCents: effectivePrice, taxCents, tipCents, totalCents, status: "paid" as const, paymentMethod: pick(["cash", "card", "card", "card", "check"]) as "cash" | "card" | "check", - paidAt, stripePaymentIntentId, notes: null, + paidAt, + stripePaymentIntentId: `pi_test_seed_${String(paidInvoiceCounter).padStart(6, "0")}`, + notes: null, }); lineItemBatch.push({ id: uuid(), invoiceId, description: svc.name, quantity: 1,