Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
import { Router, Request, Response, NextFunction } from "express";
|
|
|
|
|
import { z } from "zod";
|
|
|
|
|
import bcrypt from "bcryptjs";
|
|
|
|
|
import { prisma } from "../lib/prisma.js";
|
|
|
|
|
import { requireAuth, requireRole } from "../middleware/auth.js";
|
|
|
|
|
import { AppError } from "../middleware/errorHandler.js";
|
|
|
|
|
import { parsePage, paginatedResponse } from "../lib/pagination.js";
|
|
|
|
|
import { AuthenticatedRequest } from "../types/index.js";
|
|
|
|
|
|
|
|
|
|
const router = Router();
|
|
|
|
|
const auth = requireAuth as unknown as (r: Request, s: Response, n: NextFunction) => void;
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const vendorUp = requireRole("admin", "vendor") as unknown as (r: Request, s: Response, n: NextFunction) => void;
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
|
|
|
|
|
// Strip passwordHash from any user object before sending
|
|
|
|
|
function safe<T extends { passwordHash?: string }>(u: T): Omit<T, "passwordHash"> {
|
|
|
|
|
const { passwordHash: _, ...rest } = u;
|
|
|
|
|
return rest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CreateUserSchema = z.object({
|
|
|
|
|
email: z.string().email(),
|
|
|
|
|
password: z.string().min(8),
|
|
|
|
|
name: z.string().min(1).max(100),
|
|
|
|
|
roleId: z.string().min(1),
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
vendorId: z.string().min(1).optional(), // admin can assign to any vendor
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const UpdateUserSchema = z.object({
|
|
|
|
|
name: z.string().min(1).max(100).optional(),
|
|
|
|
|
roleId: z.string().min(1).optional(),
|
|
|
|
|
password: z.string().min(8).optional(),
|
|
|
|
|
});
|
|
|
|
|
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
// GET /api/v1/users — admin sees all users; vendor sees their own vendor
|
|
|
|
|
router.get("/", auth, vendorUp, async (req: Request, res: Response, next: NextFunction) => {
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
try {
|
|
|
|
|
const authReq = req as AuthenticatedRequest;
|
|
|
|
|
const { page, limit, skip } = parsePage(req.query as Record<string, unknown>);
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const isAdmin = authReq.auth.roleName === "admin";
|
|
|
|
|
const where = isAdmin ? {} : { vendorId: authReq.auth.vendorId };
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
|
|
|
|
|
const [users, total] = await Promise.all([
|
|
|
|
|
prisma.user.findMany({
|
|
|
|
|
where,
|
|
|
|
|
skip,
|
|
|
|
|
take: limit,
|
|
|
|
|
orderBy: { createdAt: "desc" },
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
include: { role: true, vendor: { select: { id: true, name: true } } },
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
}),
|
|
|
|
|
prisma.user.count({ where }),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
res.json(paginatedResponse(users.map(safe), total, { page, limit, skip }));
|
|
|
|
|
} catch (err) {
|
|
|
|
|
next(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// GET /api/v1/users/roles/list — must be before /:id
|
|
|
|
|
router.get("/roles/list", auth, async (_req: Request, res: Response, next: NextFunction) => {
|
|
|
|
|
try {
|
|
|
|
|
const roles = await prisma.role.findMany({ orderBy: { name: "asc" } });
|
|
|
|
|
res.json(roles);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
next(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// GET /api/v1/users/:id
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
router.get("/:id", auth, vendorUp, async (req: Request, res: Response, next: NextFunction) => {
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
try {
|
|
|
|
|
const authReq = req as AuthenticatedRequest;
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const isAdmin = authReq.auth.roleName === "admin";
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
const user = await prisma.user.findFirst({
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
where: { id: req.params.id, ...(isAdmin ? {} : { vendorId: authReq.auth.vendorId }) },
|
|
|
|
|
include: { role: true, vendor: { select: { id: true, name: true } } },
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
});
|
|
|
|
|
if (!user) throw new AppError(404, "NOT_FOUND", "User not found");
|
|
|
|
|
res.json(safe(user));
|
|
|
|
|
} catch (err) {
|
|
|
|
|
next(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// POST /api/v1/users
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
router.post("/", auth, vendorUp, async (req: Request, res: Response, next: NextFunction) => {
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
try {
|
|
|
|
|
const authReq = req as AuthenticatedRequest;
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const isAdmin = authReq.auth.roleName === "admin";
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
const body = CreateUserSchema.parse(req.body);
|
|
|
|
|
|
|
|
|
|
const existing = await prisma.user.findUnique({ where: { email: body.email } });
|
|
|
|
|
if (existing) throw new AppError(409, "CONFLICT", "Email already in use");
|
|
|
|
|
|
|
|
|
|
const role = await prisma.role.findUnique({ where: { id: body.roleId } });
|
|
|
|
|
if (!role) throw new AppError(400, "BAD_REQUEST", "Invalid role");
|
|
|
|
|
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
// Vendors cannot create admin accounts
|
|
|
|
|
if (authReq.auth.roleName === "vendor" && role.name === "admin") {
|
|
|
|
|
throw new AppError(403, "FORBIDDEN", "Vendors cannot create admin accounts");
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
}
|
|
|
|
|
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const targetVendorId = isAdmin && body.vendorId ? body.vendorId : authReq.auth.vendorId;
|
|
|
|
|
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
const user = await prisma.user.create({
|
|
|
|
|
data: {
|
|
|
|
|
email: body.email,
|
|
|
|
|
passwordHash: await bcrypt.hash(body.password, 10),
|
|
|
|
|
name: body.name,
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
vendorId: targetVendorId,
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
roleId: body.roleId,
|
|
|
|
|
},
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
include: { role: true, vendor: { select: { id: true, name: true } } },
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.status(201).json(safe(user));
|
|
|
|
|
} catch (err) {
|
|
|
|
|
next(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// PUT /api/v1/users/:id
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
router.put("/:id", auth, vendorUp, async (req: Request, res: Response, next: NextFunction) => {
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
try {
|
|
|
|
|
const authReq = req as AuthenticatedRequest;
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const isAdmin = authReq.auth.roleName === "admin";
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
const body = UpdateUserSchema.parse(req.body);
|
|
|
|
|
|
|
|
|
|
const existing = await prisma.user.findFirst({
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
where: { id: req.params.id, ...(isAdmin ? {} : { vendorId: authReq.auth.vendorId }) },
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
include: { role: true },
|
|
|
|
|
});
|
|
|
|
|
if (!existing) throw new AppError(404, "NOT_FOUND", "User not found");
|
|
|
|
|
|
|
|
|
|
if (body.roleId) {
|
|
|
|
|
const role = await prisma.role.findUnique({ where: { id: body.roleId } });
|
|
|
|
|
if (!role) throw new AppError(400, "BAD_REQUEST", "Invalid role");
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
if (authReq.auth.roleName === "vendor" && role.name === "admin") {
|
|
|
|
|
throw new AppError(403, "FORBIDDEN", "Vendors cannot assign admin role");
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updateData: Record<string, unknown> = {};
|
|
|
|
|
if (body.name) updateData.name = body.name;
|
|
|
|
|
if (body.roleId) updateData.roleId = body.roleId;
|
|
|
|
|
if (body.password) updateData.passwordHash = await bcrypt.hash(body.password, 10);
|
|
|
|
|
|
|
|
|
|
const user = await prisma.user.update({
|
|
|
|
|
where: { id: req.params.id },
|
|
|
|
|
data: updateData,
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
include: { role: true, vendor: { select: { id: true, name: true } } },
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
res.json(safe(user));
|
|
|
|
|
} catch (err) {
|
|
|
|
|
next(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// DELETE /api/v1/users/:id
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
router.delete("/:id", auth, vendorUp, async (req: Request, res: Response, next: NextFunction) => {
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
try {
|
|
|
|
|
const authReq = req as AuthenticatedRequest;
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
const isAdmin = authReq.auth.roleName === "admin";
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
if (req.params.id === authReq.auth.userId) {
|
|
|
|
|
throw new AppError(400, "BAD_REQUEST", "Cannot delete your own account");
|
|
|
|
|
}
|
|
|
|
|
const existing = await prisma.user.findFirst({
|
Rename roles, add multi-vendor support, and Events system
Roles: owner→admin, manager→vendor, cashier→user across all routes,
seed, and client UI. Role badge colours updated in UsersPage.
Multi-vendor:
- GET /vendors and GET /users now return all records for admin role;
vendor/user roles remain scoped to their vendorId
- POST /users: admin can specify vendorId to assign user to any vendor
- vendors/users now include vendor name in responses for admin context
Events (new):
- Prisma schema: Event, EventTax, EventProduct models; Transaction.eventId
- POST/GET/PUT/DELETE /api/v1/events — full CRUD, vendor-scoped
- PUT /events/:id/taxes + DELETE — upsert/remove per-event tax rate overrides
- POST/GET/DELETE /events/:id/products — product allowlist (empty=all)
- GET /events/:id/transactions — paginated list scoped to event
- GET /events/:id/reports/summary — revenue, avg tx, top products for event
- Transactions: eventId accepted in both single POST and batch POST
- Catalog sync: active/upcoming events included in /catalog/sync response
Client:
- Layout nav filtered by role (user role sees Catalog only)
- Dashboard cards filtered by role
- Events page: list, create/edit modal, detail modal with Configuration
(tax overrides + product allowlist) and Reports tabs
DB: DATABASE_URL updated to file:./prisma/dev.db in .env.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 07:27:30 -05:00
|
|
|
where: { id: req.params.id, ...(isAdmin ? {} : { vendorId: authReq.auth.vendorId }) },
|
Add Milestones 1 & 2: full-stack POS foundation with admin UI
- Node/Express/TypeScript API under /api/v1 with JWT auth (login, refresh, logout, /me)
- Prisma schema: vendors, users, roles, products, categories, taxes, transactions
- SQLite for local dev; Postgres via docker-compose for production
- Full CRUD routes for vendors, users, categories, taxes, products with Zod validation and RBAC
- Paginated list endpoints scoped per vendor; refresh token rotation
- React/TypeScript admin SPA (Vite): login, protected routing, sidebar layout
- Pages: Dashboard, Catalog (tabbed Products/Categories/Taxes), Users, Vendor Settings
- Shared UI: Table, Modal, FormField, Btn, PageHeader components
- Multi-stage Dockerfile; docker-compose with Postgres healthcheck
- Seed script with demo vendor and owner account
- INSTRUCTIONS.md, ROADMAP.md, .claude/launch.json for dev server config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 23:18:04 -05:00
|
|
|
});
|
|
|
|
|
if (!existing) throw new AppError(404, "NOT_FOUND", "User not found");
|
|
|
|
|
|
|
|
|
|
await prisma.user.delete({ where: { id: req.params.id } });
|
|
|
|
|
res.status(204).send();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
next(err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default router;
|