- Add Collection and Remittance to AppSubjects union type
- Grant OFFICE_STAFF manage:Collection and manage:Remittance
- Grant COLLECTOR create/read:Collection and create/read:Remittance
- Update all 8 collection/remittance route handlers from Subscriber to
their dedicated CASL subjects (Collection or Remittance)
- Update JSDoc comments in route files to reflect new subject names
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ExpenseStatus and ExpensePaymentMethod enums
- Add Vendor model (@@unique([tenantId, name]))
- Add ExpenseCategory model with accountCode linking to COA
- Add Expense model with approval workflow and JE reference
- Add User relations: createdExpenses, approvedExpenses
- Add COA accounts 5080 Fuel/Transportation, 5085 Rent Expense (31 total)
- Seed 9 default expense categories in createTenant transaction
- Add Vendor subject to CASL types, Expense/Vendor permissions for OFFICE_STAFF
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- InventoryService: registerItem, recordMovement, getStockLevels, getItemMovements, listItems
- RECEIVED movements auto-post JE (DR 1200 Equipment Inventory, CR 2010 AP)
- Stock levels derived from movement aggregation (no mutable quantity column)
- All 5 movement types validated with type-specific rules
- API routes: POST/GET items, GET item detail, POST/GET movements, GET stock-levels
- CASL: OFFICE_STAFF gets manage Inventory permission
- Migration applied: add_inventory_models (4 enums, 2 tables)
- 13 tests: registration, all movement types, stock derivation, JE posting, history
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Zone model (id, tenantId, name, description, isActive)
- Add ZoneAssignment model (collector-to-zone join table)
- Replace Subscriber.zone String? with Subscriber.zoneId FK to Zone
- Add Zone + ZoneAssignment to TENANT_SCOPED_MODELS with full operation blocks
- Add "Zone" to AppSubjects in types.ts
- Grant OFFICE_STAFF manage Zone, COLLECTOR read Zone in permissions.ts
- Migration 20260305000000_add_zones applied to DB
- Create src/lib/middleware/authorize.ts with withPermission() HOF
- Returns 401 for unauthenticated, 403 for unauthorized access
- Passes ability + user to authorized handlers for fine-grained checks
- Add authorize() convenience alias for handler-first usage pattern
- Create src/lib/__tests__/rbac.test.ts with 66 unit tests covering:
- Admin full access to all subjects
- Office Staff: can manage billing, blocked from Chart of Accounts
- Collector: can record payments, blocked from invoice management
- Technician: blocked from billing/payments (critical security boundary)
- Client: scoped to own data only
- Multi-role additive union (TECHNICIAN+COLLECTOR gets both sets)
- Super-admin bypasses all permission checks
- Fix CASL MongoAbility type: use createMongoAbility throughout
- Fix condition casting for string-based subjects (no Prisma models yet)
- Fix ability merging: cannot() rules excluded for multi-role union
- Install @casl/ability for role-based access control
- Create src/lib/casl/types.ts with AppAbility, AppSubjects, AppActions types
- Create src/lib/casl/permissions.ts with permission matrix for all 5 roles
- Create src/lib/casl/ability.ts with defineAbilityFor() factory function
- Support multi-role users via additive union of permissions
- Super-admin bypasses all permission checks via can("manage", "all")