Phase 8
This commit is contained in:
82 files changed
+4903
-287
No files matched your search
+35
-50
@@ -4,10 +4,12 @@
|
||||
* every relation in the schema once, not a full demo dataset.
|
||||
*/
|
||||
import "dotenv/config";
|
||||
import { PrismaClient, Permission, Weekday, RewardType, NotificationType } from "../generated/prisma/client";
|
||||
import { PrismaClient, Weekday, RewardType, NotificationType, InstallationStatus } from "../generated/prisma/client";
|
||||
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
|
||||
import { buildMysqlPoolConfig } from "../src/lib/db/mysql-pool-config";
|
||||
import { notifySafely } from "../src/services/notifications/notification.service";
|
||||
import { OWNER_PERMISSIONS, BARBER_PERMISSIONS, syncRolePermissions } from "../src/lib/roles/default-permissions";
|
||||
import { INSTALLATION_SINGLETON_ID } from "../src/lib/installation/installation-state";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
/**
|
||||
@@ -29,52 +31,6 @@ function minutesFromNow(minutes: number): Date {
|
||||
const adapter = new PrismaMariaDb(buildMysqlPoolConfig(process.env.DATABASE_URL));
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
/**
|
||||
* `role.upsert`'s `update: {}` deliberately does nothing on an existing
|
||||
* role (see the two call sites below) — re-running the seed must still be
|
||||
* safe to call repeatedly without duplicating anything, but a plain
|
||||
* nested `permissions: { create: [...] }` only fires on the `create`
|
||||
* branch, so a permission added to OWNER_PERMISSIONS/BARBER_PERMISSIONS
|
||||
* after a business was first seeded would silently never reach an
|
||||
* already-seeded database. This syncs RolePermission rows to exactly
|
||||
* match the target list every run — found and fixed while adding Phase 6
|
||||
* permissions to a database seeded back in Phase 2.
|
||||
*/
|
||||
async function syncRolePermissions(roleId: string, permissions: Permission[]): Promise<void> {
|
||||
await prisma.rolePermission.deleteMany({ where: { roleId, permission: { notIn: permissions } } });
|
||||
await prisma.rolePermission.createMany({
|
||||
data: permissions.map((permission) => ({ roleId, permission })),
|
||||
skipDuplicates: true,
|
||||
});
|
||||
}
|
||||
|
||||
const OWNER_PERMISSIONS: Permission[] = [
|
||||
Permission.MANAGE_BUSINESS_PROFILE,
|
||||
Permission.MANAGE_BOOKING_RULES,
|
||||
Permission.MANAGE_SERVICES,
|
||||
Permission.MANAGE_STAFF,
|
||||
Permission.MANAGE_LOYALTY_PROGRAMME,
|
||||
Permission.MANAGE_NOTIFICATION_SETTINGS,
|
||||
Permission.VIEW_ALL_STAFF_APPOINTMENTS,
|
||||
Permission.MANAGE_ALL_APPOINTMENTS,
|
||||
Permission.MANAGE_OWN_APPOINTMENTS,
|
||||
Permission.CHECK_IN_CUSTOMERS,
|
||||
Permission.MANAGE_LOYALTY_STAMPS,
|
||||
Permission.MANAGE_OWN_AVAILABILITY,
|
||||
Permission.VIEW_CUSTOMER_DIRECTORY,
|
||||
Permission.BOOK_ON_BEHALF_OF_CUSTOMER,
|
||||
Permission.VIEW_REPORTING,
|
||||
];
|
||||
|
||||
const BARBER_PERMISSIONS: Permission[] = [
|
||||
Permission.MANAGE_OWN_APPOINTMENTS,
|
||||
Permission.CHECK_IN_CUSTOMERS,
|
||||
Permission.MANAGE_LOYALTY_STAMPS,
|
||||
Permission.MANAGE_OWN_AVAILABILITY,
|
||||
Permission.VIEW_CUSTOMER_DIRECTORY,
|
||||
Permission.BOOK_ON_BEHALF_OF_CUSTOMER,
|
||||
];
|
||||
|
||||
const WEEKDAYS: Weekday[] = [
|
||||
Weekday.MONDAY,
|
||||
Weekday.TUESDAY,
|
||||
@@ -112,7 +68,13 @@ async function main() {
|
||||
lateArrivalPolicy: "Arrivals more than 10 minutes late may need to be rescheduled.",
|
||||
},
|
||||
},
|
||||
bookingRule: { create: {} }, // all defaults from the schema
|
||||
// Guest booking defaults to false as of Phase 8 (see BookingRule in
|
||||
// prisma/schema.prisma) — the dev/demo fixture explicitly opts back
|
||||
// in so the guest-booking E2E journey and manual testing keep
|
||||
// working; a real installed business starts with it off (see
|
||||
// src/features/installation/installer.service.ts) until the owner
|
||||
// enables it themselves.
|
||||
bookingRule: { create: { allowGuestBooking: true } },
|
||||
hours: {
|
||||
create: [
|
||||
...WEEKDAYS.map((dayOfWeek) => ({
|
||||
@@ -146,7 +108,7 @@ async function main() {
|
||||
permissions: { create: OWNER_PERMISSIONS.map((permission) => ({ permission })) },
|
||||
},
|
||||
});
|
||||
await syncRolePermissions(ownerRole.id, OWNER_PERMISSIONS);
|
||||
await syncRolePermissions(prisma, ownerRole.id, OWNER_PERMISSIONS);
|
||||
|
||||
const barberRole = await prisma.role.upsert({
|
||||
where: { businessId_name: { businessId: business.id, name: "Barber" } },
|
||||
@@ -158,7 +120,7 @@ async function main() {
|
||||
permissions: { create: BARBER_PERMISSIONS.map((permission) => ({ permission })) },
|
||||
},
|
||||
});
|
||||
await syncRolePermissions(barberRole.id, BARBER_PERMISSIONS);
|
||||
await syncRolePermissions(prisma, barberRole.id, BARBER_PERMISSIONS);
|
||||
|
||||
const category = await prisma.serviceCategory.upsert({
|
||||
where: { id: `${business.id}-senior-barber` },
|
||||
@@ -1013,6 +975,29 @@ async function main() {
|
||||
});
|
||||
}
|
||||
|
||||
// Dev/demo fixtures bypass the installation wizard entirely (see
|
||||
// src/features/installation/installer.service.ts for the real,
|
||||
// production first-run path) — this upsert only exists so a freshly
|
||||
// seeded dev/CI/E2E database is treated as "installed" by the routing
|
||||
// gate in src/proxy.ts, exactly as if a real install had completed.
|
||||
// Never run alongside a real installation: the two are mutually
|
||||
// exclusive by construction (the installer's own transaction refuses
|
||||
// to start once this row exists — see ApplicationInstallation's model
|
||||
// header).
|
||||
await prisma.applicationInstallation.upsert({
|
||||
where: { id: INSTALLATION_SINGLETON_ID },
|
||||
update: {},
|
||||
create: {
|
||||
id: INSTALLATION_SINGLETON_ID,
|
||||
status: InstallationStatus.INSTALLED,
|
||||
installedAt: new Date(),
|
||||
installedVersion: "dev-seed",
|
||||
initialAdminUserId: ownerUser.id,
|
||||
primaryBusinessId: business.id,
|
||||
metadata: { source: "prisma/seed.ts" },
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Seed complete:", {
|
||||
business: business.name,
|
||||
roles: [ownerRole.name, barberRole.name],
|
||||
|
||||
Reference in new issue
Block a user