refactor: inline packages/db and packages/types into api package
Phase 2 extraction: groombook/api from groombook/app monorepo. Changes: - Move packages/db content to apps/api/src/db/ - Move packages/types content to apps/api/src/types/ - Inline database schema and migrations into api package - Update Dockerfile to build single package - Update CI workflow for single-package structure - Fix vitest.config.ts aliases Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -77,11 +77,8 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Build packages
|
- name: Build
|
||||||
run: |
|
run: pnpm --filter @groombook/api build
|
||||||
pnpm --filter @groombook/types build
|
|
||||||
pnpm --filter @groombook/db build
|
|
||||||
pnpm --filter @groombook/api build
|
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
name: Build & Push Docker Images
|
name: Build & Push Docker Images
|
||||||
|
|||||||
+6
-15
@@ -3,32 +3,23 @@ RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
COPY apps/api/package.json apps/api/
|
COPY apps/api/package.json apps/api/
|
||||||
COPY packages/db/package.json packages/db/
|
|
||||||
COPY packages/types/package.json packages/types/
|
|
||||||
RUN pnpm install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
FROM deps AS builder
|
FROM deps AS builder
|
||||||
RUN mkdir -p /home/node/.cache/node/corepack
|
RUN mkdir -p /home/node/.cache/node/corepack
|
||||||
COPY packages/ packages/
|
|
||||||
COPY apps/api/ apps/api/
|
COPY apps/api/ apps/api/
|
||||||
RUN pnpm --filter @groombook/types build && \
|
RUN pnpm --filter @groombook/api build
|
||||||
pnpm --filter @groombook/db build && \
|
|
||||||
pnpm --filter @groombook/api build
|
|
||||||
|
|
||||||
FROM node:20-alpine AS runner
|
FROM node:20-alpine AS runner
|
||||||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
COPY --from=builder /app/apps/api/package.json apps/api/
|
COPY --from=builder /app/apps/api/package.json apps/api/
|
||||||
COPY --from=builder /app/apps/api/dist apps/api/dist
|
COPY --from=builder /app/apps/api/dist apps/api/dist
|
||||||
COPY --from=builder /app/packages/db/package.json packages/db/
|
|
||||||
COPY --from=builder /app/packages/db/dist packages/db/dist
|
|
||||||
COPY --from=builder /app/packages/types/package.json packages/types/
|
|
||||||
COPY --from=builder /app/packages/types/dist packages/types/dist
|
|
||||||
RUN pnpm install --frozen-lockfile --prod
|
RUN pnpm install --frozen-lockfile --prod
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
@@ -38,10 +29,10 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|||||||
CMD ["node", "apps/api/dist/index.js"]
|
CMD ["node", "apps/api/dist/index.js"]
|
||||||
|
|
||||||
FROM builder AS migrate
|
FROM builder AS migrate
|
||||||
CMD ["pnpm", "--filter", "@groombook/db", "db:migrate"]
|
CMD ["pnpm", "--filter", "@groombook/api", "db:migrate"]
|
||||||
|
|
||||||
FROM builder AS seed
|
FROM builder AS seed
|
||||||
CMD ["pnpm", "--filter", "@groombook/db", "db:seed"]
|
CMD ["pnpm", "--filter", "@groombook/api", "db:seed"]
|
||||||
|
|
||||||
FROM builder AS reset
|
FROM builder AS reset
|
||||||
CMD ["pnpm", "--filter", "@groombook/db", "db:reset"]
|
CMD ["pnpm", "--filter", "@groombook/api", "db:reset"]
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
FROM node:20-alpine AS base
|
|
||||||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Install deps
|
|
||||||
FROM base AS deps
|
|
||||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
|
||||||
COPY apps/api/package.json apps/api/
|
|
||||||
COPY packages/db/package.json packages/db/
|
|
||||||
COPY packages/types/package.json packages/types/
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# Build
|
|
||||||
FROM deps AS builder
|
|
||||||
RUN mkdir -p /home/node/.cache/node/corepack
|
|
||||||
COPY packages/ packages/
|
|
||||||
COPY apps/api/ apps/api/
|
|
||||||
RUN pnpm --filter @groombook/types build && \
|
|
||||||
pnpm --filter @groombook/db build && \
|
|
||||||
pnpm --filter @groombook/api build
|
|
||||||
|
|
||||||
# Runtime
|
|
||||||
FROM node:20-alpine AS runner
|
|
||||||
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
|
|
||||||
WORKDIR /app
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
|
|
||||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
|
|
||||||
COPY --from=builder /app/apps/api/package.json apps/api/
|
|
||||||
COPY --from=builder /app/apps/api/dist apps/api/dist
|
|
||||||
COPY --from=builder /app/packages/db/package.json packages/db/
|
|
||||||
COPY --from=builder /app/packages/db/dist packages/db/dist
|
|
||||||
COPY --from=builder /app/packages/types/package.json packages/types/
|
|
||||||
COPY --from=builder /app/packages/types/dist packages/types/dist
|
|
||||||
RUN pnpm install --frozen-lockfile --prod
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
RUN apk add --no-cache curl
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
||||||
CMD curl -f http://localhost:3000/health || exit 1
|
|
||||||
CMD ["node", "apps/api/dist/index.js"]
|
|
||||||
|
|
||||||
# Migrate stage — runs drizzle-kit migrate against the database
|
|
||||||
FROM builder AS migrate
|
|
||||||
CMD ["pnpm", "db:migrate"]
|
|
||||||
|
|
||||||
# Seed stage — populates the database with test data
|
|
||||||
FROM builder AS seed
|
|
||||||
CMD ["pnpm", "db:seed"]
|
|
||||||
|
|
||||||
# Reset stage — drops all tables, re-runs migrations, and re-seeds
|
|
||||||
FROM builder AS reset
|
|
||||||
CMD ["pnpm", "db:reset"]
|
|
||||||
@@ -9,22 +9,26 @@
|
|||||||
"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",
|
||||||
"test": "vitest run"
|
"test": "vitest run",
|
||||||
|
"db:generate": "drizzle-kit generate",
|
||||||
|
"db:migrate": "drizzle-kit migrate",
|
||||||
|
"db:seed": "tsx src/db/seed.ts",
|
||||||
|
"db:reset": "tsx src/db/reset.ts && drizzle-kit migrate && tsx src/db/seed.ts",
|
||||||
|
"db:studio": "drizzle-kit studio"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.800.0",
|
"@aws-sdk/client-s3": "^3.800.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.800.0",
|
"@aws-sdk/s3-request-presigner": "^3.800.0",
|
||||||
"@groombook/db": "workspace:*",
|
|
||||||
"@groombook/types": "workspace:*",
|
|
||||||
"@hono/node-server": "^1.13.7",
|
"@hono/node-server": "^1.13.7",
|
||||||
"@hono/zod-validator": "^0.7.6",
|
"@hono/zod-validator": "^0.7.6",
|
||||||
"better-auth": "^1.5.6",
|
"better-auth": "^1.5.6",
|
||||||
|
"drizzle-orm": "^0.38.4",
|
||||||
"hono": "^4.6.17",
|
"hono": "^4.6.17",
|
||||||
"node-cron": "^3.0.3",
|
"node-cron": "^3.0.3",
|
||||||
"nodemailer": "^6.9.16",
|
"nodemailer": "^6.9.16",
|
||||||
|
"postgres": "^3.4.5",
|
||||||
"stripe": "^22.0.0",
|
"stripe": "^22.0.0",
|
||||||
"telnyx": "^1.23.0",
|
"telnyx": "^1.23.0",
|
||||||
|
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -32,6 +36,7 @@
|
|||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@vitest/coverage-v8": "^3.2.4",
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
|
"drizzle-kit": "^0.30.4",
|
||||||
"eslint": "^9.18.0",
|
"eslint": "^9.18.0",
|
||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ let dbSelectResult: unknown[] = [];
|
|||||||
const mockEq = vi.fn((_col: unknown, _val: unknown) => ({ col: _col, val: _val }));
|
const mockEq = vi.fn((_col: unknown, _val: unknown) => ({ col: _col, val: _val }));
|
||||||
const mockDecryptSecret = vi.fn((s: string) => `decrypted:${s}`);
|
const mockDecryptSecret = vi.fn((s: string) => `decrypted:${s}`);
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
const authProviderConfig = new Proxy(
|
const authProviderConfig = new Proxy(
|
||||||
{ _name: "auth_provider_config" },
|
{ _name: "auth_provider_config" },
|
||||||
{
|
{
|
||||||
@@ -40,7 +40,7 @@ vi.mock("./packages/db", () => {
|
|||||||
|
|
||||||
async function reimportAuth() {
|
async function reimportAuth() {
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
vi.doMock("./packages/db", () => ({
|
vi.doMock("./db", () => ({
|
||||||
getDb: () => ({
|
getDb: () => ({
|
||||||
select: () => ({
|
select: () => ({
|
||||||
from: () => ({
|
from: () => ({
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const mockGroomer: MockStaff = { id: "staff-3", role: "groomer", isSuperUser: fa
|
|||||||
|
|
||||||
// ─── Mock db module ───────────────────────────────────────────────────────────
|
// ─── Mock db module ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
const authProviderConfig = new Proxy(
|
const authProviderConfig = new Proxy(
|
||||||
{ _name: "auth_provider_config" },
|
{ _name: "auth_provider_config" },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function resetMock() {
|
|||||||
deletedId = null;
|
deletedId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
function makeChainable(data: unknown[]): unknown {
|
function makeChainable(data: unknown[]): unknown {
|
||||||
const arr = [...data];
|
const arr = [...data];
|
||||||
const chain = new Proxy(arr, {
|
const chain = new Proxy(arr, {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function resetMock() {
|
|||||||
lastUpdate = {};
|
lastUpdate = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
const appointments = new Proxy(
|
const appointments = new Proxy(
|
||||||
{ _name: "appointments" },
|
{ _name: "appointments" },
|
||||||
{ get: (t, p) => (p === "_name" ? "appointments" : { table: "appointments", column: p }) }
|
{ get: (t, p) => (p === "_name" ? "appointments" : { table: "appointments", column: p }) }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||||
import { encryptSecret, decryptSecret } from "./packages/db";
|
import { encryptSecret, decryptSecret } from "../db/index.js";
|
||||||
|
|
||||||
describe("encryptSecret / decryptSecret", () => {
|
describe("encryptSecret / decryptSecret", () => {
|
||||||
const originalEnv = process.env.BETTER_AUTH_SECRET;
|
const originalEnv = process.env.BETTER_AUTH_SECRET;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
buildPet,
|
buildPet,
|
||||||
buildService,
|
buildService,
|
||||||
buildAppointment,
|
buildAppointment,
|
||||||
} from "./packages/db/factories";
|
} from "../db/factories.js";
|
||||||
|
|
||||||
describe("resetFactoryCounters", () => {
|
describe("resetFactoryCounters", () => {
|
||||||
it("resets all counters so IDs restart from 1", () => {
|
it("resets all counters so IDs restart from 1", () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import type { AppEnv, StaffRow } from "../middleware/rbac.js";
|
import type { AppEnv, StaffRow } from "../middleware/rbac.js";
|
||||||
import { buildStaff } from "./packages/db/factories";
|
import { buildStaff } from "../db/factories.js";
|
||||||
|
|
||||||
// ─── Mock data (built with factories for schema-safe defaults) ────────────────
|
// ─── Mock data (built with factories for schema-safe defaults) ────────────────
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ function makeChainableResult(data: unknown[]): unknown {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
function makeTable(name: string) {
|
function makeTable(name: string) {
|
||||||
return new Proxy(
|
return new Proxy(
|
||||||
{ _name: name },
|
{ _name: name },
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function resetDb() {
|
|||||||
|
|
||||||
// ─── Module mocks ─────────────────────────────────────────────────────────────
|
// ─── Module mocks ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
const pets = new Proxy(
|
const pets = new Proxy(
|
||||||
{ _name: "pets" },
|
{ _name: "pets" },
|
||||||
{ get(t, p) { return p === "_name" ? "pets" : {}; } }
|
{ get(t, p) { return p === "_name" ? "pets" : {}; } }
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ function resetMock() {
|
|||||||
updatedValues = [];
|
updatedValues = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
function makeChainable(data: unknown[]): unknown {
|
function makeChainable(data: unknown[]): unknown {
|
||||||
const arr = [...data];
|
const arr = [...data];
|
||||||
const chain = new Proxy(arr, {
|
const chain = new Proxy(arr, {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const GROOMER: StaffRow = {
|
|||||||
let staffLookupResult: StaffRow | null = null;
|
let staffLookupResult: StaffRow | null = null;
|
||||||
let managerFallbackResult: StaffRow | null = MANAGER;
|
let managerFallbackResult: StaffRow | null = MANAGER;
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
const staff = new Proxy(
|
const staff = new Proxy(
|
||||||
{ _name: "staff" },
|
{ _name: "staff" },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const PET_ROW = {
|
|||||||
let clientResults: typeof ACTIVE_CLIENT[] = [];
|
let clientResults: typeof ACTIVE_CLIENT[] = [];
|
||||||
let petResults: typeof PET_ROW[] = [];
|
let petResults: typeof PET_ROW[] = [];
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
// Proxy objects for table/column references — values don't matter for tests
|
// Proxy objects for table/column references — values don't matter for tests
|
||||||
const tableProxy = (name: string) =>
|
const tableProxy = (name: string) =>
|
||||||
new Proxy(
|
new Proxy(
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function clearAuthEnv() {
|
|||||||
|
|
||||||
// ─── Mock db module ───────────────────────────────────────────────────────────
|
// ─── Mock db module ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
const authProviderConfig = new Proxy(
|
const authProviderConfig = new Proxy(
|
||||||
{ _name: "auth_provider_config" },
|
{ _name: "auth_provider_config" },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function resetMock() {
|
|||||||
updatedValues = [];
|
updatedValues = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
vi.mock("./packages/db", () => {
|
vi.mock("./db", () => {
|
||||||
function makeChainable(data: unknown[]): unknown {
|
function makeChainable(data: unknown[]): unknown {
|
||||||
const arr = [...data];
|
const arr = [...data];
|
||||||
const chain = new Proxy(arr, {
|
const chain = new Proxy(arr, {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* readable values (e.g. "staff-1", "client-2") without needing crypto.
|
* readable values (e.g. "staff-1", "client-2") without needing crypto.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* import { buildStaff, buildClient, buildPet } from "@groombook/db/factories";
|
* import { buildStaff, buildClient, buildPet } from "./db/factories";
|
||||||
*
|
*
|
||||||
* const manager = buildStaff({ role: "manager" });
|
* const manager = buildStaff({ role: "manager" });
|
||||||
* const client = buildClient({ name: "Alice Smith" });
|
* const client = buildClient({ name: "Alice Smith" });
|
||||||
@@ -22,7 +22,7 @@ import { searchRouter } from "./routes/search.js";
|
|||||||
import { getObject } from "./lib/s3.js";
|
import { getObject } from "./lib/s3.js";
|
||||||
import { calendarRouter } from "./routes/calendar.js";
|
import { calendarRouter } from "./routes/calendar.js";
|
||||||
import { setupRouter } from "./routes/setup.js";
|
import { setupRouter } from "./routes/setup.js";
|
||||||
import { getDb, businessSettings, eq, staff } from "./packages/db";
|
import { getDb, businessSettings, eq, staff } from "./db";
|
||||||
import { authMiddleware } from "./middleware/auth.js";
|
import { authMiddleware } from "./middleware/auth.js";
|
||||||
import { resolveStaffMiddleware, requireRole, requireRoleOrSuperUser, requireSuperUser } from "./middleware/rbac.js";
|
import { resolveStaffMiddleware, requireRole, requireRoleOrSuperUser, requireSuperUser } from "./middleware/rbac.js";
|
||||||
import { devRouter } from "./routes/dev.js";
|
import { devRouter } from "./routes/dev.js";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||||
import { genericOAuth } from "better-auth/plugins";
|
import { genericOAuth } from "better-auth/plugins";
|
||||||
import { getDb, authProviderConfig, eq } from "./packages/db";
|
import { getDb, authProviderConfig, eq } from "./db";
|
||||||
import { decryptSecret } from "./packages/db";
|
import { decryptSecret } from "./db";
|
||||||
import { sendEmail } from "../services/email.js";
|
import { sendEmail } from "../services/email.js";
|
||||||
|
|
||||||
const BETTER_AUTH_SECRET = process.env.BETTER_AUTH_SECRET;
|
const BETTER_AUTH_SECRET = process.env.BETTER_AUTH_SECRET;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { MiddlewareHandler } from "hono";
|
import type { MiddlewareHandler } from "hono";
|
||||||
import { getDb, impersonationAuditLogs } from "./packages/db";
|
import { getDb, impersonationAuditLogs } from "../db";
|
||||||
import type { PortalEnv } from "./portalSession.js";
|
import type { PortalEnv } from "./portalSession.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { MiddlewareHandler } from "hono";
|
import type { MiddlewareHandler } from "hono";
|
||||||
import { and, eq, getDb, impersonationSessions } from "./packages/db";
|
import { and, eq, getDb, impersonationSessions } from "../db";
|
||||||
|
|
||||||
export interface PortalEnv {
|
export interface PortalEnv {
|
||||||
Variables: {
|
Variables: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { MiddlewareHandler } from "hono";
|
import type { MiddlewareHandler } from "hono";
|
||||||
import { and, eq, getDb, sql, staff } from "./packages/db";
|
import { and, eq, getDb, sql, staff } from "../db";
|
||||||
|
|
||||||
export type StaffRole = "groomer" | "receptionist" | "manager";
|
export type StaffRole = "groomer" | "receptionist" | "manager";
|
||||||
export type StaffRow = typeof staff.$inferSelect;
|
export type StaffRow = typeof staff.$inferSelect;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { eq, getDb, staff, clients, pets, services } from "./packages/db";
|
import { eq, getDb, staff, clients, pets, services } from "./db";
|
||||||
|
|
||||||
export const adminSeedRouter = new Hono();
|
export const adminSeedRouter = new Hono();
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
pets,
|
pets,
|
||||||
services,
|
services,
|
||||||
staff,
|
staff,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const appointmentGroupsRouter = new Hono<AppEnv>();
|
export const appointmentGroupsRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
reminderLogs,
|
reminderLogs,
|
||||||
services,
|
services,
|
||||||
staff,
|
staff,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import { buildConfirmationEmail, sendEmail } from "../services/email.js";
|
import { buildConfirmationEmail, sendEmail } from "../services/email.js";
|
||||||
import { notifyWaitlistForAppointment } from "../services/waitlistNotify.js";
|
import { notifyWaitlistForAppointment } from "../services/waitlistNotify.js";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { eq, getDb, authProviderConfig, encryptSecret } from "./packages/db";
|
import { eq, getDb, authProviderConfig, encryptSecret } from "../db";
|
||||||
import { requireSuperUser } from "../middleware/rbac.js";
|
import { requireSuperUser } from "../middleware/rbac.js";
|
||||||
import { reinitAuth } from "../lib/auth.js";
|
import { reinitAuth } from "../lib/auth.js";
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
appointments,
|
appointments,
|
||||||
clients,
|
clients,
|
||||||
pets,
|
pets,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import {
|
import {
|
||||||
generateAvailableSlots,
|
generateAvailableSlots,
|
||||||
BUSINESS_START_HOUR,
|
BUSINESS_START_HOUR,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
pets,
|
pets,
|
||||||
services,
|
services,
|
||||||
staff,
|
staff,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
|
|
||||||
export const calendarRouter = new Hono();
|
export const calendarRouter = new Hono();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { and, eq, exists, getDb, or, clients, appointments } from "./packages/db";
|
import { and, eq, exists, getDb, or, clients, appointments } from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const clientsRouter = new Hono<AppEnv>();
|
export const clientsRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { getDb, staff, clients, eq, sql } from "./packages/db";
|
import { getDb, staff, clients, eq, sql } from "../db";
|
||||||
|
|
||||||
const devRouter = new Hono();
|
const devRouter = new Hono();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { and, desc, eq, getDb, groomingVisitLogs, appointments, or } from "./packages/db";
|
import { and, desc, eq, getDb, groomingVisitLogs, appointments, or } from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const groomingLogsRouter = new Hono<AppEnv>();
|
export const groomingLogsRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
impersonationAuditLogs,
|
impersonationAuditLogs,
|
||||||
clients,
|
clients,
|
||||||
desc,
|
desc,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const impersonationRouter = new Hono<AppEnv>();
|
export const impersonationRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
services,
|
services,
|
||||||
clients,
|
clients,
|
||||||
sql,
|
sql,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const invoicesRouter = new Hono<AppEnv>();
|
export const invoicesRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { and, eq, exists, getDb, or, pets, appointments } from "./packages/db";
|
import { and, eq, exists, getDb, or, pets, appointments } from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
import {
|
import {
|
||||||
getPresignedUploadUrl,
|
getPresignedUploadUrl,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { eq, inArray } from "./packages/db";
|
import { eq, inArray } from "../db";
|
||||||
import { getDb, appointments, impersonationSessions, waitlistEntries, clients, pets, services, staff, invoices, invoiceLineItems } from "./packages/db";
|
import { getDb, appointments, impersonationSessions, waitlistEntries, clients, pets, services, staff, invoices, invoiceLineItems } from "../db";
|
||||||
import { validatePortalSession } from "../middleware/portalSession.js";
|
import { validatePortalSession } from "../middleware/portalSession.js";
|
||||||
import { portalAudit } from "../middleware/portalAudit.js";
|
import { portalAudit } from "../middleware/portalAudit.js";
|
||||||
import type { PortalEnv } from "../middleware/portalSession.js";
|
import type { PortalEnv } from "../middleware/portalSession.js";
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
invoiceTipSplits,
|
invoiceTipSplits,
|
||||||
services,
|
services,
|
||||||
staff,
|
staff,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
|
|
||||||
export const reportsRouter = new Hono();
|
export const reportsRouter = new Hono();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { and, eq, getDb, clients, ilike, or, pets } from "./packages/db";
|
import { and, eq, getDb, clients, ilike, or, pets } from "../db";
|
||||||
|
|
||||||
export const searchRouter = new Hono();
|
export const searchRouter = new Hono();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { eq, getDb, services } from "./packages/db";
|
import { eq, getDb, services } from "../db";
|
||||||
|
|
||||||
export const servicesRouter = new Hono();
|
export const servicesRouter = new Hono();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { eq, getDb, businessSettings } from "./packages/db";
|
import { eq, getDb, businessSettings } from "../db";
|
||||||
import { getPresignedUploadUrl, deleteObject, putObject, getObject } from "../lib/s3.js";
|
import { getPresignedUploadUrl, deleteObject, putObject, getObject } from "../lib/s3.js";
|
||||||
import { requireSuperUser } from "../middleware/rbac.js";
|
import { requireSuperUser } from "../middleware/rbac.js";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { and, eq, getDb, sql, staff, businessSettings, authProviderConfig, encryptSecret } from "./packages/db";
|
import { and, eq, getDb, sql, staff, businessSettings, authProviderConfig, encryptSecret } from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
const RATE_LIMIT_WINDOW_MS = 60_000;
|
const RATE_LIMIT_WINDOW_MS = 60_000;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Hono } from "hono";
|
|||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { randomBytes } from "node:crypto";
|
import { randomBytes } from "node:crypto";
|
||||||
import { and, eq, getDb, ne, staff, appointments } from "./packages/db";
|
import { and, eq, getDb, ne, staff, appointments } from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const staffRouter = new Hono<AppEnv>();
|
export const staffRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import Stripe from "stripe";
|
import Stripe from "stripe";
|
||||||
import { z } from "zod/v3";
|
import { z } from "zod/v3";
|
||||||
import { eq, getDb, invoices } from "./packages/db";
|
import { eq, getDb, invoices } from "../db";
|
||||||
import { getStripeClient } from "../services/payment.js";
|
import { getStripeClient } from "../services/payment.js";
|
||||||
|
|
||||||
export const webhooksRouter = new Hono();
|
export const webhooksRouter = new Hono();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
clients,
|
clients,
|
||||||
pets,
|
pets,
|
||||||
services,
|
services,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import type { AppEnv } from "../middleware/rbac.js";
|
import type { AppEnv } from "../middleware/rbac.js";
|
||||||
|
|
||||||
export const waitlistRouter = new Hono<AppEnv>();
|
export const waitlistRouter = new Hono<AppEnv>();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Stripe from "stripe";
|
import Stripe from "stripe";
|
||||||
import { getDb, clients, eq, inArray, invoices } from "./packages/db";
|
import { getDb, clients, eq, inArray, invoices } from "../db";
|
||||||
|
|
||||||
let _stripe: Stripe | null | undefined;
|
let _stripe: Stripe | null | undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
staff,
|
staff,
|
||||||
reminderLogs,
|
reminderLogs,
|
||||||
session,
|
session,
|
||||||
} from "./packages/db";
|
} from "../db";
|
||||||
import {
|
import {
|
||||||
buildReminderEmail,
|
buildReminderEmail,
|
||||||
sendEmail,
|
sendEmail,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { and, eq, getDb, waitlistEntries, clients, pets, services } from "./packages/db";
|
import { and, eq, getDb, waitlistEntries, clients, pets, services } from "../db";
|
||||||
import { buildWaitlistNotificationEmail, sendEmail } from "./email.js";
|
import { buildWaitlistNotificationEmail, sendEmail } from "./email.js";
|
||||||
|
|
||||||
export async function notifyWaitlistForAppointment(
|
export async function notifyWaitlistForAppointment(
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import { defineConfig } from "vitest/config";
|
import { defineConfig } from "vitest/config";
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
"@groombook/db/factories": path.resolve(__dirname, "../../packages/db/src/factories.ts"),
|
|
||||||
"@groombook/db": path.resolve(__dirname, "../../packages/db/src/index.ts"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
test: {
|
test: {
|
||||||
coverage: {
|
coverage: {
|
||||||
provider: "v8",
|
provider: "v8",
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@groombook/db",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"main": "./dist/index.js",
|
|
||||||
"types": "./src/index.ts",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"default": "./dist/index.js",
|
|
||||||
"types": "./src/index.ts"
|
|
||||||
},
|
|
||||||
"./factories": {
|
|
||||||
"default": "./src/factories.ts",
|
|
||||||
"types": "./src/factories.ts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "tsc",
|
|
||||||
"generate": "drizzle-kit generate",
|
|
||||||
"migrate": "drizzle-kit migrate",
|
|
||||||
"seed": "tsx src/seed.ts",
|
|
||||||
"reset": "tsx src/reset.ts && drizzle-kit migrate && tsx src/seed.ts",
|
|
||||||
"studio": "drizzle-kit studio",
|
|
||||||
"typecheck": "tsc --noEmit"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"drizzle-orm": "^0.38.4",
|
|
||||||
"postgres": "^3.4.5"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^22.10.7",
|
|
||||||
"drizzle-kit": "^0.30.4",
|
|
||||||
"tsx": "^4.19.0",
|
|
||||||
"typescript": "^5.7.3"
|
|
||||||
},
|
|
||||||
"license": "AGPL-3.0-only"
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2022",
|
|
||||||
"module": "NodeNext",
|
|
||||||
"moduleResolution": "NodeNext",
|
|
||||||
"strict": true,
|
|
||||||
"noUncheckedIndexedAccess": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"outDir": "./dist",
|
|
||||||
"rootDir": "./src"
|
|
||||||
},
|
|
||||||
"include": ["src"]
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@groombook/types",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"main": "./dist/index.js",
|
|
||||||
"types": "./src/index.ts",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"default": "./dist/index.js",
|
|
||||||
"types": "./src/index.ts"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "tsc",
|
|
||||||
"typecheck": "tsc --noEmit"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"typescript": "^5.7.3"
|
|
||||||
},
|
|
||||||
"license": "AGPL-3.0-only"
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2022",
|
|
||||||
"module": "NodeNext",
|
|
||||||
"moduleResolution": "NodeNext",
|
|
||||||
"strict": true,
|
|
||||||
"noUncheckedIndexedAccess": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"outDir": "./dist",
|
|
||||||
"rootDir": "./src"
|
|
||||||
},
|
|
||||||
"include": ["src"]
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user