Commit Graph

20 Commits

Author SHA1 Message Date
Ryan Moon
5f5ba9e4a2 Build inventory frontend and stock management features
- Full inventory UI: product list with search/filter, product detail with
  tabs (details, units, suppliers, stock receipts, price history)
- Product filters: category, type (serialized/rental/repair), low stock,
  active/inactive — all server-side with URL-synced state
- Product-supplier junction: link products to multiple suppliers with
  preferred flag, joined supplier details in UI
- Stock receipts: record incoming stock with supplier, qty, cost per unit,
  invoice number; auto-increments qty_on_hand for non-serialized products
- Price history tab on product detail page
- categories/all endpoint to avoid pagination limit on dropdown fetches
- categoryId filter on product list endpoint
- Repair parts and additional inventory items in music store seed data
- isDualUseRepair corrected: instruments set to false, strings/parts true
- Product-supplier links and stock receipts in seed data
- Price history seed data simulating cost increases over past year
- 37 API tests covering categories, suppliers, products, units,
  product-suppliers, and stock receipts
- alert-dialog and checkbox UI components
- sync-and-deploy.sh script for rsync + remote deploy
2026-03-30 20:12:07 -05:00
Ryan Moon
7680a73d88 Add Phase 8: lesson plan templates with deep-copy instantiation
- New tables: lesson_plan_template, lesson_plan_template_section, lesson_plan_template_item
- skill_level enum: beginner, intermediate, advanced, all_levels
- Templates are reusable curriculum definitions independent of any member/enrollment
- POST /lesson-plan-templates/:id/create-plan deep-copies the template into a member plan
- Instantiation uses template name as default plan title, accepts custom title override
- Instantiation deactivates any existing active plan on the enrollment (one-active rule)
- Plan items are independent copies — renaming the template does not affect existing plans
- 11 new integration tests
2026-03-30 10:37:30 -05:00
Ryan Moon
2cc8f24535 Add Phase 7: grade history and session-plan item linking
- New tables: lesson_plan_item_grade_history (append-only), lesson_session_plan_item
- Grading an item updates current_grade_value and creates immutable history record
- Grading a not_started item auto-transitions it to in_progress
- Linking items to a session also auto-transitions not_started items
- Link operation is idempotent — re-linking same items produces no duplicates
- Endpoints: POST/GET /lesson-plan-items/:id/grades, GET /lesson-plan-items/:id/grade-history
- Endpoints: POST/GET /lesson-sessions/:id/plan-items
- 8 new integration tests
2026-03-30 10:33:21 -05:00
Ryan Moon
5cd2d05983 Add Phase 4b: instructor blocked dates, store closures, and substitute instructors
- New tables: instructor_blocked_date, store_closure (migration 0034)
- substitute_instructor_id column added to lesson_session
- Session generation skips blocked instructor dates and store closure periods
- Substitute assignment validates sub is not blocked and has no conflicting slot
- Routes: POST/GET/DELETE /instructors/:id/blocked-dates, POST/GET/DELETE /store-closures
- 15 new integration tests covering blocked dates, store closures, and sub validation
2026-03-30 10:29:13 -05:00
Ryan Moon
aae5a022a8 Add lessons Phase 6: lesson plans with curriculum tracking
Structured lesson plans with nested sections and items per enrollment.
Deep create in one request, one-active-per-enrollment constraint,
auto-set startedDate/masteredDate on status transitions, progress %
calculation (skipped items excluded). 8 new tests (84 total).
2026-03-30 09:40:41 -05:00
Ryan Moon
31f661ff4f Add lessons Phase 5: grading scales with nested levels
Custom grading scales with ordered levels (value, label, numeric score,
color). Supports one-default-per-store constraint, deep create with
nested levels, lookup endpoint for dropdowns, and search/pagination.
12 new tests (76 total lessons tests).
2026-03-30 09:36:48 -05:00
Ryan Moon
73360cd478 Add lessons Phase 4: lesson sessions with hybrid calendar generation
Individual lesson occurrences generated from schedule slot patterns.
Idempotent session generation with configurable rolling window.
Post-lesson notes workflow with auto-set notesCompletedAt. Status
tracking (scheduled/attended/missed/makeup/cancelled) and date/time
filtering. 13 new tests (64 total lessons tests).
2026-03-30 09:29:03 -05:00
Ryan Moon
93405af3b2 Add lessons Phase 3: enrollments with capacity and time conflict checks
Links members to schedule slots via enrollments. Enforces max_students
capacity on slots and prevents members from double-booking the same
day/time. Supports status transitions and filtering. 11 new tests
(51 total lessons tests).
2026-03-30 09:23:43 -05:00
Ryan Moon
f777ce5184 Add lessons Phase 2: schedule slots with conflict detection
Recurring weekly time slots linking instructors to lesson types.
Includes day/time overlap detection, instructor and day-of-week
filtering, and 17 new integration tests (40 total lessons tests).
2026-03-30 09:20:03 -05:00
Ryan Moon
5dbe837c08 Add lessons domain Phase 1: instructor and lesson type entities
Foundation tables for the lessons module with full CRUD, pagination,
search, and sorting. Includes migration, Drizzle schema, Zod validation,
services, routes, and 23 integration tests.
2026-03-30 09:17:32 -05:00
Ryan Moon
7eac03f6c2 Add repair notes journal with running feed, visibility, and status tagging
New repair_note table for timestamped journal entries on tickets. Each
note captures author, content, visibility (internal or customer-facing),
and the ticket status at time of writing. Notes display as a running
feed on the ticket detail page with newest first. Internal notes have
a lock icon, customer-visible notes highlighted in blue. Supports add
and delete with appropriate permission gating.
2026-03-29 10:27:39 -05:00
Ryan Moon
f17bbff02c Add repairs domain with tickets, line items, batches, and service templates
Full-stack implementation of instrument repair tracking: DB schema with
repair_ticket, repair_line_item, repair_batch, and repair_service_template
tables. Backend services and routes with pagination/search/sort. 20 API
tests covering CRUD, status workflow, line items, and batch operations.
Admin frontend with ticket list, detail with status progression, line item
management, batch list/detail with approval workflow, and new ticket form
with searchable account picker and intake photo uploads.
2026-03-29 09:12:40 -05:00
Ryan Moon
c7b460c0bf Add member identifiers table for ID documents (DL, passport, school ID)
member_identifier table with type, value, issuing authority, expiry,
front/back image storage (base64 in Postgres), primary flag. CRUD
endpoints under /members/:memberId/identifiers. Zod schemas with
constrained type enum.
2026-03-28 09:38:01 -05:00
Ryan Moon
0a2d6e23af Add lookup tables, payment methods, tax exemptions, and processor link APIs
Replace unit_status and item_condition pgEnums with company-scoped lookup
tables that support custom values. Add account_payment_method table,
tax_exemption table with approve/revoke workflow, and CRUD routes for
processor links. Validate inventory unit status/condition against lookup
tables at service layer.
2026-03-27 20:53:30 -05:00
Ryan Moon
750dcf4046 Refactor all list APIs for server-side pagination, search, and sort
All list endpoints now return paginated responses:
  { data: [...], pagination: { page, limit, total, totalPages } }

Query params: ?page=1&limit=25&q=search&sort=name&order=asc

Changes:
- Added PaginationSchema in @forte/shared for consistent param parsing
- Added pagination utils (withPagination, withSort, buildSearchCondition,
  paginatedResponse) in backend
- Refactored all services: AccountService, MemberService, CategoryService,
  SupplierService, ProductService, InventoryUnitService
- Merged separate /search endpoints into list endpoints via ?q= param
- Removed AccountSearchSchema and ProductSearchSchema (replaced by
  PaginationSchema)
- Added pagination test (5 items, page 1 limit 2, expect totalPages=3)
- Updated CLAUDE.md with API conventions
- 34 tests passing
2026-03-27 19:53:59 -05:00
Ryan Moon
1132e0999b Add products, inventory units, stock receipts, and price history
- product table (catalog definition, no cost column — cost tracked
  per receipt/unit)
- inventory_unit table (serialized items with serial number,
  condition, status)
- stock_receipt table (FIFO cost tracking — records every stock
  receive event with cost_per_unit, supplier, date)
- price_history table (logs every retail price change for margin
  analysis over time)
- product_supplier join table (many-to-many, tracks supplier SKU
  and preferred supplier)
- Full CRUD routes + search (name, SKU, UPC, brand)
- Inventory unit routes nested under products
- Price changes auto-logged on product update
- 33 tests passing
2026-03-27 18:22:39 -05:00
Ryan Moon
77a3a6baa9 Add categories and suppliers with CRUD routes
- category table with hierarchical parent_id, sort ordering, soft-delete
- supplier table with contact info, account number, payment terms
- CRUD routes for both with search on suppliers
- Zod validation schemas in @forte/shared
- Products will link to suppliers via join table (many-to-many)
- 26 tests passing
2026-03-27 18:07:46 -05:00
Ryan Moon
5ff31ad782 Add accounts, members, and processor-agnostic payment linking
- account table (billing entity, soft-delete, company-scoped)
- member table (people on an account, is_minor from DOB)
- account_processor_link table (maps accounts to any payment
  processor — stripe, global_payments — instead of stripe_customer_id
  directly on account)
- Full CRUD routes + search (name, email, phone, account_number)
- Member routes nested under accounts with isMinor auto-calculation
- Zod validation schemas in @forte/shared
- 19 tests passing
2026-03-27 17:41:33 -05:00
Ryan Moon
979a9a2c00 Add user auth with JWT, switch to bun test
- User table with company_id FK, unique email, role enum
- Register/login routes with bcrypt + JWT token generation
- Auth plugin with authenticate decorator and role guards
- Login uses globally unique email (no company header needed)
- Dev-auth plugin kept as fallback when JWT_SECRET not set
- Switched from vitest to bun:test (vitest had ESM resolution
  issues with zod in Bun's module structure)
- Upgraded to zod 4
- Added Dockerfile.dev and API service to docker-compose
- 8 tests passing (health + auth)
2026-03-27 17:33:05 -05:00
Ryan Moon
c1cddd6b74 Phase 1: Monorepo scaffold, database, and dev environment
Turborepo monorepo with @forte/shared and @forte/backend workspaces.
Docker Compose dev env with PostgreSQL 16 + Valkey 8.
Fastify server with Pino JSON logging, request ID tracing, and
health endpoint. Drizzle ORM with company + location tables.

Includes:
- Root config (turbo, tsconfig, eslint, prettier)
- @forte/shared: types, schemas, currency/date utils
- @forte/backend: Fastify entry, plugins (database, redis, cors,
  error-handler, dev-auth), health route, Drizzle schema + migration
- Dev auth bypass via X-Dev-Company/Location/User headers
- Vitest integration test with clean DB per test (forte_test)
- Seed script for dev company + location
2026-03-27 14:51:46 -05:00