Merge branch 'main' into feature/gro-118-better-auth
This commit is contained in:
@@ -17,6 +17,7 @@ const MANAGER: StaffRow = {
|
||||
oidcSub: "oidc-manager-sub",
|
||||
userId: null,
|
||||
role: "manager",
|
||||
isSuperUser: true,
|
||||
name: "Manager McManager",
|
||||
email: "manager@example.com",
|
||||
active: true,
|
||||
|
||||
@@ -9,6 +9,7 @@ const MANAGER: StaffRow = {
|
||||
oidcSub: "oidc-manager-sub",
|
||||
userId: null,
|
||||
role: "manager",
|
||||
isSuperUser: true,
|
||||
name: "Manager McManager",
|
||||
email: "manager@example.com",
|
||||
active: true,
|
||||
|
||||
@@ -10,6 +10,7 @@ const MANAGER: StaffRow = {
|
||||
oidcSub: "oidc-manager-sub",
|
||||
userId: "ba-user-manager",
|
||||
role: "manager",
|
||||
isSuperUser: true,
|
||||
name: "Manager McManager",
|
||||
email: "manager@example.com",
|
||||
active: true,
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
CREATE TYPE "public"."waitlist_status" AS ENUM('active', 'notified', 'expired', 'cancelled');--> statement-breakpoint
|
||||
CREATE TABLE "account" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"account_id" text NOT NULL,
|
||||
"provider_id" text NOT NULL,
|
||||
"user_id" text NOT NULL,
|
||||
"access_token" text,
|
||||
"refresh_token" text,
|
||||
"id_token" text,
|
||||
"access_token_expires_at" timestamp,
|
||||
"refresh_token_expires_at" timestamp,
|
||||
"scope" text,
|
||||
"password" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "session" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"expires_at" timestamp NOT NULL,
|
||||
"token" text NOT NULL,
|
||||
"ip_address" text,
|
||||
"user_agent" text,
|
||||
"user_id" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "session_token_unique" UNIQUE("token")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "user" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"email_verified" boolean DEFAULT false NOT NULL,
|
||||
"image" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "user_email_unique" UNIQUE("email")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "verification" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"identifier" text NOT NULL,
|
||||
"value" text NOT NULL,
|
||||
"expires_at" timestamp NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "waitlist_entries" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"client_id" uuid NOT NULL,
|
||||
"pet_id" uuid NOT NULL,
|
||||
"service_id" uuid NOT NULL,
|
||||
"preferred_date" text NOT NULL,
|
||||
"preferred_time" text NOT NULL,
|
||||
"status" "waitlist_status" DEFAULT 'active' NOT NULL,
|
||||
"notified_at" timestamp,
|
||||
"expires_at" timestamp,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "appointments" ADD COLUMN "confirmation_status" text DEFAULT 'pending' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "appointments" ADD COLUMN "confirmed_at" timestamp;--> statement-breakpoint
|
||||
ALTER TABLE "appointments" ADD COLUMN "cancelled_at" timestamp;--> statement-breakpoint
|
||||
ALTER TABLE "appointments" ADD COLUMN "confirmation_token" text;--> statement-breakpoint
|
||||
ALTER TABLE "appointments" ADD COLUMN "customer_notes" text;--> statement-breakpoint
|
||||
ALTER TABLE "pets" ADD COLUMN "photo_key" text;--> statement-breakpoint
|
||||
ALTER TABLE "pets" ADD COLUMN "photo_uploaded_at" timestamp;--> statement-breakpoint
|
||||
ALTER TABLE "staff" ADD COLUMN "user_id" text;--> statement-breakpoint
|
||||
ALTER TABLE "staff" ADD COLUMN "is_super_user" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "staff" ADD COLUMN "ical_token" text;--> statement-breakpoint
|
||||
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "waitlist_entries" ADD CONSTRAINT "waitlist_entries_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "waitlist_entries" ADD CONSTRAINT "waitlist_entries_pet_id_pets_id_fk" FOREIGN KEY ("pet_id") REFERENCES "public"."pets"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "waitlist_entries" ADD CONSTRAINT "waitlist_entries_service_id_services_id_fk" FOREIGN KEY ("service_id") REFERENCES "public"."services"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX "idx_waitlist_client_id" ON "waitlist_entries" USING btree ("client_id");--> statement-breakpoint
|
||||
CREATE INDEX "idx_waitlist_preferred_date" ON "waitlist_entries" USING btree ("preferred_date");--> statement-breakpoint
|
||||
CREATE INDEX "idx_waitlist_status" ON "waitlist_entries" USING btree ("status");--> statement-breakpoint
|
||||
ALTER TABLE "staff" ADD CONSTRAINT "staff_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "appointments" ADD CONSTRAINT "appointments_confirmation_token_unique" UNIQUE("confirmation_token");--> statement-breakpoint
|
||||
ALTER TABLE "staff" ADD CONSTRAINT "staff_ical_token_unique" UNIQUE("ical_token");
|
||||
@@ -52,6 +52,7 @@ export function buildStaff(overrides: Partial<StaffRow> = {}): StaffRow {
|
||||
oidcSub: `oidc-${id}`,
|
||||
userId: null,
|
||||
role: "groomer",
|
||||
isSuperUser: false,
|
||||
active: true,
|
||||
icalToken: null,
|
||||
createdAt: new Date("2025-01-01T00:00:00Z"),
|
||||
|
||||
@@ -159,6 +159,8 @@ export const staff = pgTable("staff", {
|
||||
// Better-Auth user ID — links staff business record to auth identity
|
||||
userId: text("user_id").references(() => user.id, { onDelete: "set null" }),
|
||||
role: staffRoleEnum("role").notNull().default("groomer"),
|
||||
// Super users bypass appointment-booking restrictions and access admin panels
|
||||
isSuperUser: boolean("is_super_user").notNull().default(false),
|
||||
active: boolean("active").notNull().default(true),
|
||||
// Token for iCal calendar feed subscription (no auth required)
|
||||
icalToken: text("ical_token").unique(),
|
||||
|
||||
+10
-8
@@ -287,6 +287,7 @@ async function seedKnownUsers() {
|
||||
email: "demo-manager@groombook.dev",
|
||||
oidcSub: "demo-manager-001",
|
||||
role: "manager",
|
||||
isSuperUser: true,
|
||||
active: true,
|
||||
});
|
||||
console.log("✓ Created staff 'Demo Manager' (oidcSub: demo-manager-001)");
|
||||
@@ -384,24 +385,24 @@ async function seed() {
|
||||
// ── Staff ──
|
||||
// Deterministic staff IDs so they can be referenced in scripts/tests
|
||||
const managerStaff = [
|
||||
{ id: uuid(), name: "Jordan Lee", email: "jordan@groombook.dev", role: "manager" as const },
|
||||
{ id: uuid(), name: "Jordan Lee", email: "jordan@groombook.dev", role: "manager" as const, isSuperUser: true },
|
||||
];
|
||||
|
||||
const receptionistStaff = [
|
||||
{ id: uuid(), name: "Sam Rivera", email: "sam@groombook.dev", role: "receptionist" as const },
|
||||
{ id: uuid(), name: "Sam Rivera", email: "sam@groombook.dev", role: "receptionist" as const, isSuperUser: false },
|
||||
];
|
||||
|
||||
const groomers = [
|
||||
{ id: uuid(), name: "Sarah Mitchell", email: "sarah@groombook.dev", role: "groomer" as const },
|
||||
{ id: uuid(), name: "James Park", email: "james@groombook.dev", role: "groomer" as const },
|
||||
{ id: uuid(), name: "Maria Gonzalez", email: "maria@groombook.dev", role: "groomer" as const },
|
||||
{ id: uuid(), name: "Sarah Mitchell", email: "sarah@groombook.dev", role: "groomer" as const, isSuperUser: false },
|
||||
{ id: uuid(), name: "James Park", email: "james@groombook.dev", role: "groomer" as const, isSuperUser: false },
|
||||
{ id: uuid(), name: "Maria Gonzalez", email: "maria@groombook.dev", role: "groomer" as const, isSuperUser: false },
|
||||
];
|
||||
|
||||
// Bathers are groomers by role but serve as the secondary staff (bather) on appointments
|
||||
const bathers = [
|
||||
{ id: uuid(), name: "Tyler Johnson", email: "tyler@groombook.dev", role: "groomer" as const },
|
||||
{ id: uuid(), name: "Ashley Chen", email: "ashley@groombook.dev", role: "groomer" as const },
|
||||
{ id: uuid(), name: "Devon Williams", email: "devon@groombook.dev", role: "groomer" as const },
|
||||
{ id: uuid(), name: "Tyler Johnson", email: "tyler@groombook.dev", role: "groomer" as const, isSuperUser: false },
|
||||
{ id: uuid(), name: "Ashley Chen", email: "ashley@groombook.dev", role: "groomer" as const, isSuperUser: false },
|
||||
{ id: uuid(), name: "Devon Williams", email: "devon@groombook.dev", role: "groomer" as const, isSuperUser: false },
|
||||
];
|
||||
|
||||
const allStaff = [...managerStaff, ...receptionistStaff, ...groomers, ...bathers];
|
||||
@@ -411,6 +412,7 @@ async function seed() {
|
||||
name: s.name,
|
||||
email: s.email,
|
||||
role: s.role,
|
||||
isSuperUser: s.isSuperUser,
|
||||
active: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ export interface Staff {
|
||||
name: string;
|
||||
email: string;
|
||||
role: "groomer" | "receptionist" | "manager";
|
||||
isSuperUser: boolean;
|
||||
active: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
Reference in New Issue
Block a user