Commit Graph

10 Commits

Author SHA1 Message Date
Ryan Moon
f9bf1c9bff Add rectangular logo upload to settings, support SVG content type
Settings page now shows a rectangular upload area for the store logo
instead of circular avatar. Uses authenticated image fetching with
blob URL cleanup. Accepts SVG in addition to JPEG/PNG/WebP. SVG
added to file serve content type map. Simplified to single logo
image (used on PDFs, sidebar, and login).
2026-03-29 16:27:02 -05:00
Ryan Moon
8d75586f8b Add store logo and app icon uploads to settings page
AvatarUpload component now supports custom category and placeholder
icon props. Settings page shows two upload circles: Store Logo (for
PDFs/invoices, uses ImageIcon placeholder) and App Icon (for sidebar/
login, uses Building placeholder). Added 'company' to allowed file
entity types.
2026-03-29 16:14:08 -05:00
Ryan Moon
d36c6f7135 Remove multi-tenant company_id scoping from entire codebase
Drop company_id column from all 22 domain tables via migration.
Remove companyId from JWT payload, auth plugins, all service method
signatures (~215 occurrences), all route handlers (~105 occurrences),
test runner, test suites, and frontend auth store/types.

The company table stays as store settings (name, timezone). Tenant
isolation in a SaaS deployment would be at the database level (one
DB per customer) not the application level.

All 107 API tests pass. Zero TSC errors across all packages.
2026-03-29 14:58:33 -05:00
Ryan Moon
72d0ff0a33 Fix security and quality issues from code review
Critical: Add company scoping to line item update/delete and note
delete via ownership verification through ticket join. Add companyId
validation to signed URL file serving. High: Paginate notes list
endpoint with search and sort support. Fix blob URL memory leaks in
AuthImage components with proper cleanup on unmount. Improve photo
upload error handling — count failures and show specific error count
instead of silently clearing form.
2026-03-29 12:16:17 -05:00
Ryan Moon
ba94adb8d7 Fix DELETE sending empty JSON body, add repair_note to allowed file entity types
API client no longer sets Content-Type: application/json on requests
without a body (fixes DELETE 400 errors). Added repair_note to the
allowed entityTypes whitelist for file uploads so photos can be
attached to repair notes.
2026-03-29 11:23:21 -05:00
Ryan Moon
bf2091365d Add signed URLs for file access, fix unauthorized file viewing
New /files/signed-url/:id endpoint generates a 15-minute JWT-signed URL
for any file. New /files/s/* endpoint serves files using the token from
the query string without requiring auth headers. This allows files to
open in new browser tabs without authentication issues. Photos and
documents in repair tickets now use signed URLs when clicked.
2026-03-29 11:02:24 -05:00
Ryan Moon
b9f78639e2 Add paginated users/roles, user status, frontend permissions, profile pictures, identifier file storage
- Users page: paginated, searchable, sortable with inline roles (no N+1)
- Roles page: paginated, searchable, sortable + /roles/all for dropdowns
- User is_active field with migration, PATCH toggle, auth check (disabled=401)
- Frontend permission checks: auth store loads permissions, sidebar/buttons conditional
- Profile pictures via file storage for users and members, avatar component
- Identifier images use file storage API instead of base64
- Fix TypeScript errors across admin UI
- 64 API tests passing (10 new)
2026-03-29 08:16:34 -05:00
Ryan Moon
4a1fc608f0 Implement RBAC with permissions, roles, and route guards
- permission, role, role_permission, user_role_assignment tables
- 42 system permissions across 13 domains
- 6 default roles: Admin, Manager, Sales Associate, Technician, Instructor, Viewer
- Permission inheritance: admin implies edit implies view
- requirePermission() Fastify decorator on ALL routes
- System permissions and roles seeded per company
- Test helpers and API test runner seed RBAC data
- All 42 API tests pass with permissions enforced
2026-03-28 17:00:42 -05:00
Ryan Moon
e65175ef19 Fix security issues: path traversal, typed errors, file validation
- Fix path traversal in file serve endpoint (validate company prefix, block ..)
- Add typed error classes: ValidationError, NotFoundError, ForbiddenError,
  ConflictError, StorageError
- Global error handler catches AppError subclasses with correct status codes
- 4xx logged as warn, 5xx as error with request ID
- File upload validates entityType whitelist, UUID format, category pattern
- Remove fragile string-matching error handling from routes
- Services throw typed errors instead of plain Error
- Health endpoint documented as intentionally public
2026-03-28 16:03:45 -05:00
Ryan Moon
760e995ae3 Implement file storage layer with local provider, upload/download API, tests
- StorageProvider interface with LocalProvider (S3 placeholder)
- File table with entity_type/entity_id references, content type, path
- POST /v1/files (multipart upload), GET /v1/files (list by entity),
  GET /v1/files/:id (metadata), GET /v1/files/serve/* (content),
  DELETE /v1/files/:id
- member_identifier drops base64 columns, uses file_id FKs
- File validation: type whitelist, size limits, per-entity max
- Fastify storage plugin injects provider into app
- 6 API tests for upload, list, get, delete, validation
- Test runner kills stale port before starting backend
2026-03-28 15:29:06 -05:00