promote: dev → uat (UAT Tester seed fix + TypeScript CI compliance)
promote: dev → uat (UAT Tester seed fix + TypeScript CI compliance)
This commit was merged in pull request #8.
This commit is contained in:
+27
-6
@@ -94,11 +94,6 @@ function pick<T>(arr: T[]): T {
|
||||
return arr[Math.floor(rand() * arr.length)]!;
|
||||
}
|
||||
|
||||
/** Return n distinct random elements from an array. */
|
||||
function pickN<T>(arr: T[], n: number): T[] {
|
||||
const shuffled = [...arr].sort(() => rand() - 0.5);
|
||||
return shuffled.slice(0, n);
|
||||
}
|
||||
|
||||
function randInt(min: number, max: number): number {
|
||||
return Math.floor(rand() * (max - min + 1)) + min;
|
||||
@@ -459,6 +454,32 @@ async function seedKnownUsers() {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Staff: UAT Tester (oidcSub from SEED_UAT_TESTER_OIDC_SUB env var) ──
|
||||
const uatTesterOidcSub = process.env.SEED_UAT_TESTER_OIDC_SUB;
|
||||
if (uatTesterOidcSub) {
|
||||
const UAT_TESTER_STAFF_ID = "00000000-0000-0000-0000-000000000007";
|
||||
const [existingUatTester] = await db
|
||||
.select()
|
||||
.from(schema.staff)
|
||||
.where(eq(schema.staff.email, "uat-tester@groombook.dev"))
|
||||
.limit(1);
|
||||
|
||||
if (existingUatTester) {
|
||||
console.log(`✓ Staff 'UAT Tester' already exists — skipping`);
|
||||
} else {
|
||||
await db.insert(schema.staff).values({
|
||||
id: UAT_TESTER_STAFF_ID,
|
||||
name: "UAT Tester",
|
||||
email: "uat-tester@groombook.dev",
|
||||
oidcSub: uatTesterOidcSub,
|
||||
role: "groomer",
|
||||
isSuperUser: false,
|
||||
active: true,
|
||||
});
|
||||
console.log(`✓ Created staff 'UAT Tester' (oidcSub: ${uatTesterOidcSub})`);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Staff: UAT Groomer Personas (SEED_UAT_GROOMER_EMAILS + SEED_UAT_GROOMER_NAMES) ──
|
||||
const groomerEmails = process.env.SEED_UAT_GROOMER_EMAILS?.split(",").map((e) => e.trim()).filter(Boolean) ?? [];
|
||||
const groomerNames = process.env.SEED_UAT_GROOMER_NAMES?.split(",").map((n) => n.trim()).filter(Boolean) ?? [];
|
||||
@@ -1079,7 +1100,7 @@ async function seed() {
|
||||
const groomer = pick(groomers);
|
||||
const bather = bathers.length > 0 && rand() < 0.6 ? pick(bathers) : null;
|
||||
|
||||
let startTime = randDate(appointmentsBackDate, now);
|
||||
const startTime = randDate(appointmentsBackDate, now);
|
||||
startTime.setHours(randInt(8, 16), pick([0, 15, 30, 45]), 0, 0);
|
||||
const endTime = new Date(startTime.getTime() + svc.dur * 60 * 1000);
|
||||
const effectivePrice = svc.price;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { searchRouter } from "./routes/search.js";
|
||||
import { getObject } from "./lib/s3.js";
|
||||
import { calendarRouter } from "./routes/calendar.js";
|
||||
import { setupRouter } from "./routes/setup.js";
|
||||
import { getDb, businessSettings, eq, staff } from "./db";
|
||||
import { getDb, businessSettings, eq, staff } from "./db/index.js";
|
||||
import { authMiddleware } from "./middleware/auth.js";
|
||||
import { resolveStaffMiddleware, requireRole, requireRoleOrSuperUser, requireSuperUser } from "./middleware/rbac.js";
|
||||
import { devRouter } from "./routes/dev.js";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { genericOAuth } from "better-auth/plugins";
|
||||
import { getDb, authProviderConfig, eq } from "./db";
|
||||
import { decryptSecret } from "./db";
|
||||
import { getDb, authProviderConfig, eq } from "../db/index.js";
|
||||
import { decryptSecret } from "../db/index.js";
|
||||
import { sendEmail } from "../services/email.js";
|
||||
|
||||
const BETTER_AUTH_SECRET = process.env.BETTER_AUTH_SECRET;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { getDb, impersonationAuditLogs } from "../db";
|
||||
import { getDb, impersonationAuditLogs } from "../db/index.js";
|
||||
import type { PortalEnv } from "./portalSession.js";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { and, eq, getDb, impersonationSessions } from "../db";
|
||||
import { and, eq, getDb, impersonationSessions } from "../db/index.js";
|
||||
|
||||
export interface PortalEnv {
|
||||
Variables: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
import { and, eq, getDb, sql, staff } from "../db";
|
||||
import { and, eq, getDb, sql, staff } from "../db/index.js";
|
||||
|
||||
export type StaffRole = "groomer" | "receptionist" | "manager";
|
||||
export type StaffRow = typeof staff.$inferSelect;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import { Hono } from "hono";
|
||||
import { eq, getDb, staff, clients, pets, services } from "./db";
|
||||
import { eq, getDb, staff, clients, pets, services } from "../../db/index.js";
|
||||
|
||||
export const adminSeedRouter = new Hono();
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
pets,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const appointmentGroupsRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
reminderLogs,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import { buildConfirmationEmail, sendEmail } from "../services/email.js";
|
||||
import { notifyWaitlistForAppointment } from "../services/waitlistNotify.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, authProviderConfig, encryptSecret } from "../db";
|
||||
import { eq, getDb, authProviderConfig, encryptSecret } from "../db/index.js";
|
||||
import { requireSuperUser } from "../middleware/rbac.js";
|
||||
import { reinitAuth } from "../lib/auth.js";
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
appointments,
|
||||
clients,
|
||||
pets,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import {
|
||||
generateAvailableSlots,
|
||||
BUSINESS_START_HOUR,
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
pets,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
|
||||
export const calendarRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, eq, exists, getDb, or, clients, appointments } from "../db";
|
||||
import { and, eq, exists, getDb, or, clients, appointments } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const clientsRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Hono } from "hono";
|
||||
import { getDb, staff, clients, eq, sql } from "../db";
|
||||
import { getDb, staff, clients, eq, sql } from "../db/index.js";
|
||||
|
||||
const devRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, desc, eq, getDb, groomingVisitLogs, appointments, or } from "../db";
|
||||
import { and, desc, eq, getDb, groomingVisitLogs, appointments, or } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const groomingLogsRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
impersonationAuditLogs,
|
||||
clients,
|
||||
desc,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const impersonationRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
services,
|
||||
clients,
|
||||
sql,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const invoicesRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, eq, exists, getDb, or, pets, appointments } from "../db";
|
||||
import { and, eq, exists, getDb, or, pets, appointments } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
import {
|
||||
getPresignedUploadUrl,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, inArray } from "../db";
|
||||
import { getDb, appointments, impersonationSessions, waitlistEntries, clients, pets, services, staff, invoices, invoiceLineItems } from "../db";
|
||||
import { eq, inArray } from "../db/index.js";
|
||||
import { getDb, appointments, impersonationSessions, waitlistEntries, clients, pets, services, staff, invoices, invoiceLineItems } from "../db/index.js";
|
||||
import { validatePortalSession } from "../middleware/portalSession.js";
|
||||
import { portalAudit } from "../middleware/portalAudit.js";
|
||||
import type { PortalEnv } from "../middleware/portalSession.js";
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
invoiceTipSplits,
|
||||
services,
|
||||
staff,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
|
||||
export const reportsRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Hono } from "hono";
|
||||
import { and, eq, getDb, clients, ilike, or, pets } from "../db";
|
||||
import { and, eq, getDb, clients, ilike, or, pets } from "../db/index.js";
|
||||
|
||||
export const searchRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, services } from "../db";
|
||||
import { eq, getDb, services } from "../db/index.js";
|
||||
|
||||
export const servicesRouter = new Hono();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, businessSettings } from "../db";
|
||||
import { eq, getDb, businessSettings } from "../db/index.js";
|
||||
import { getPresignedUploadUrl, deleteObject, putObject, getObject } from "../lib/s3.js";
|
||||
import { requireSuperUser } from "../middleware/rbac.js";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { and, eq, getDb, sql, staff, businessSettings, authProviderConfig, encryptSecret } from "../db";
|
||||
import { and, eq, getDb, sql, staff, businessSettings, authProviderConfig, encryptSecret } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
const RATE_LIMIT_WINDOW_MS = 60_000;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Hono } from "hono";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { z } from "zod/v3";
|
||||
import { randomBytes } from "node:crypto";
|
||||
import { and, eq, getDb, ne, staff, appointments } from "../db";
|
||||
import { and, eq, getDb, ne, staff, appointments } from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const staffRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hono } from "hono";
|
||||
import Stripe from "stripe";
|
||||
import { z } from "zod/v3";
|
||||
import { eq, getDb, invoices } from "../db";
|
||||
import { eq, getDb, invoices } from "../db/index.js";
|
||||
import { getStripeClient } from "../services/payment.js";
|
||||
|
||||
export const webhooksRouter = new Hono();
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
clients,
|
||||
pets,
|
||||
services,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import type { AppEnv } from "../middleware/rbac.js";
|
||||
|
||||
export const waitlistRouter = new Hono<AppEnv>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Stripe from "stripe";
|
||||
import { getDb, clients, eq, inArray, invoices } from "../db";
|
||||
import { getDb, clients, eq, inArray, invoices } from "../db/index.js";
|
||||
|
||||
let _stripe: Stripe | null | undefined;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
staff,
|
||||
reminderLogs,
|
||||
session,
|
||||
} from "../db";
|
||||
} from "../db/index.js";
|
||||
import {
|
||||
buildReminderEmail,
|
||||
sendEmail,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { and, eq, getDb, waitlistEntries, clients, pets, services } from "../db";
|
||||
import { and, eq, getDb, waitlistEntries, clients, pets, services } from "../db/index.js";
|
||||
import { buildWaitlistNotificationEmail, sendEmail } from "./email.js";
|
||||
|
||||
export async function notifyWaitlistForAppointment(
|
||||
|
||||
Reference in New Issue
Block a user