Files
kevin-asprec cc8314f854 docs(04-03): complete expense tracking plan
Tasks completed: 2/2
- Task 1: Schema + COA additions + expense category seeding
- Task 2: VendorService, ExpenseService, API routes, migration, 15 tests

SUMMARY: .planning/phases/04-inventory-expenses-and-financial-reports/04-03-SUMMARY.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:53:50 +08:00

7.1 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established duration completed
04-inventory-expenses-and-financial-reports 03 expenses, accounting
expense-tracking
vendor-management
journal-entries
double-entry
approval-workflow
prisma
phase provides
02-subscriber-and-billing-core JournalEntryService, Chart of Accounts, accounting period management
phase provides
01-foundation Tenant provisioning, CASL permissions, withTenantContext
Vendor model and VendorService (CRUD)
ExpenseCategory model with 9 pre-seeded ISP categories
Expense model with ExpenseService (create, approve, post, void)
Automatic JE posting on expense post (DR expense account, CR cash/bank)
Optional approval workflow (DRAFT -> APPROVED -> POSTED)
API routes for expenses, categories, and vendors
COA accounts 5080 Fuel/Transportation, 5085 Rent Expense (31 total)
04-05-financial-reports
05-dashboard
added patterns
Expense JE pattern: DR category.accountCode, CR 1010/1020 based on paymentMethod
Optional approval workflow via requireApproval flag
ExpensePaymentMethod enum determines CR account (CASH->1010, BANK_TRANSFER/CHECK->1020)
created modified
src/lib/services/expense-service.ts
src/lib/services/vendor-service.ts
src/app/api/expenses/route.ts
src/app/api/expenses/[id]/route.ts
src/app/api/expenses/[id]/approve/route.ts
src/app/api/expenses/categories/route.ts
src/app/api/expenses/categories/[id]/route.ts
src/app/api/vendors/route.ts
src/app/api/vendors/[id]/route.ts
src/lib/__tests__/expense-service.test.ts
prisma/migrations/20260305_add_expense_vendor_models/migration.sql
prisma/schema.prisma
src/lib/tenant.ts
src/lib/accounting/chart-of-accounts.ts
src/lib/casl/types.ts
src/lib/casl/permissions.ts
ExpensePaymentMethod determines CR account: CASH->1010, BANK_TRANSFER/CHECK->1020
Default behavior is immediate post (no approval required); requireApproval flag enables DRAFT-only creation
System expense categories (isSystemCategory=true) cannot be deleted; custom categories can be deleted if no expenses reference them
Vendor subject added to CASL types; OFFICE_STAFF gets manage permissions for Expense and Vendor
COA now has 31 accounts (added 5080 Fuel/Transportation, 5085 Rent Expense)
Expense cleanup order: expenses -> vendors -> expenseCategories (non-system) -> journalEntryLines -> null reversesEntryId -> journalEntries -> accountingPeriods -> accounts -> ticketCategories -> expenseCategories (system) -> users -> tenant
Expense JE: DR category expense account (from accountCode), CR cash/bank account
Optional approval workflow pattern: requireApproval flag on create, approveExpense triggers post
Category-to-COA linking via accountCode field on ExpenseCategory
17min 2026-03-05

Phase 4 Plan 3: Expense Tracking Summary

Expense tracking with vendor management, 9 pre-seeded categories, optional approval workflow, and automatic double-entry JE posting on every expense

Performance

  • Duration: 17 min
  • Started: 2026-03-05T02:35:00Z
  • Completed: 2026-03-05T02:52:00Z
  • Tasks: 2
  • Files modified: 16

Accomplishments

  • Full expense lifecycle: create, approve, post, void with JE integration
  • 9 default ISP expense categories seeded at tenant creation (bandwidth, equipment, salary, etc.)
  • Vendor CRUD with unique name per tenant
  • Every posted expense creates balanced JE (DR expense account from category, CR cash/bank)
  • Optional approval workflow (DRAFT -> APPROVED -> POSTED when enabled)
  • 15 integration tests covering all expense scenarios

Task Commits

Each task was committed atomically:

  1. Task 1: Schema + COA + category seeding - fe4d22f (feat)
  2. Task 2: Services, API routes, migration, tests - b7bbc50 (feat)

Files Created/Modified

  • prisma/schema.prisma - Added Vendor, ExpenseCategory, Expense models + enums
  • src/lib/tenant.ts - Added expense category seeding in createTenant transaction
  • src/lib/accounting/chart-of-accounts.ts - Added 5080, 5085 expense accounts (31 total)
  • src/lib/casl/types.ts - Added Vendor subject
  • src/lib/casl/permissions.ts - Added Expense/Vendor permissions for OFFICE_STAFF
  • src/lib/services/vendor-service.ts - VendorService: create, update, list, get
  • src/lib/services/expense-service.ts - ExpenseService: create, approve, post, void, list, categories CRUD
  • src/app/api/expenses/route.ts - POST/GET expense endpoints
  • src/app/api/expenses/[id]/route.ts - GET expense detail
  • src/app/api/expenses/[id]/approve/route.ts - POST approve expense
  • src/app/api/expenses/categories/route.ts - GET/POST expense categories
  • src/app/api/expenses/categories/[id]/route.ts - PUT expense category
  • src/app/api/vendors/route.ts - GET/POST vendor endpoints
  • src/app/api/vendors/[id]/route.ts - GET/PUT vendor detail
  • src/lib/__tests__/expense-service.test.ts - 15 integration tests
  • prisma/migrations/20260305_add_expense_vendor_models/migration.sql - DB migration

Decisions Made

  • ExpensePaymentMethod determines CR account: CASH -> 1010 Cash on Hand, BANK_TRANSFER/CHECK -> 1020 Cash in Bank
  • Default behavior is immediate post (requireApproval=false); when enabled, expense stays DRAFT until approved
  • System expense categories protected from deletion; custom categories deletable only if no expenses reference them
  • Added Vendor as a new CASL subject (separate from Expense) for granular permissions
  • COA expanded to 31 accounts with Fuel/Transportation (5080) and Rent Expense (5085)

Deviations from Plan

Auto-fixed Issues

1. [Rule 2 - Missing Critical] Added Vendor to CASL types and OFFICE_STAFF permissions

  • Found during: Task 1 (Schema + permissions)
  • Issue: Plan specified API routes for vendors with ADMIN/OFFICE_STAFF access, but Vendor was not in AppSubjects and OFFICE_STAFF had no Expense/Vendor permissions
  • Fix: Added "Vendor" to AppSubjects type, added can("manage", "Expense") and can("manage", "Vendor") for OFFICE_STAFF role
  • Files modified: src/lib/casl/types.ts, src/lib/casl/permissions.ts
  • Verification: API routes compile with correct permission checks
  • Committed in: fe4d22f (Task 1 commit)

Total deviations: 1 auto-fixed (1 missing critical) Impact on plan: Essential for API route authorization. No scope creep.

Issues Encountered

  • Docker exec commands were unresponsive; switched to DATABASE_URL_LOCAL with prisma db push for migration (same result, different approach)

User Setup Required

None - no external service configuration required.

Next Phase Readiness

  • Expense tracking complete, all costs hit the double-entry ledger automatically
  • Financial reports in 04-05 can now include expense data alongside revenue
  • Ready for 04-04 (if exists) or 04-05 Financial Reports

Phase: 04-inventory-expenses-and-financial-reports Completed: 2026-03-05