Add PDF reports, file uploads, admin auth, and comprehensive tests

Features:
- PDF service for generating task reports with ReportLab-style formatting
- Storage service for file uploads (local and S3-compatible)
- Admin authentication middleware with JWT support
- Admin user model and repository

Infrastructure:
- Updated Docker configuration for admin panel builds
- Email service enhancements for task notifications
- Updated router with admin and file upload routes
- Environment configuration updates

Tests:
- Unit tests for handlers (auth, residence, task)
- Unit tests for models (user, residence, task)
- Unit tests for repositories (user, residence, task)
- Unit tests for services (residence, task)
- Integration test setup
- Test utilities for mocking database and services

Database:
- Admin user seed data
- Updated test data seeds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-27 23:36:20 -06:00
parent 2817deee3c
commit 469f21a833
50 changed files with 6795 additions and 582 deletions

20
seeds/003_admin_user.sql Normal file
View File

@@ -0,0 +1,20 @@
-- Seed admin users for MyCrib Admin Panel
-- Run with: ./dev.sh seed-admin (after running migrations)
-- Password is 'password123' hashed with bcrypt
-- Admin Users
-- bcrypt hash for 'password123': $2a$10$KB4rf2NNj0a80lwlwJhaFukE2/THJXbcGZMks7vR3zykyN4zkF6xi
INSERT INTO admin_users (id, email, password, first_name, last_name, role, is_active, created_at, updated_at)
VALUES
(1, 'admin@mycrib.com', '$2a$10$KB4rf2NNj0a80lwlwJhaFukE2/THJXbcGZMks7vR3zykyN4zkF6xi', 'Admin', 'User', 'super_admin', true, NOW(), NOW())
ON CONFLICT (id) DO UPDATE SET
email = EXCLUDED.email,
password = EXCLUDED.password,
first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
role = EXCLUDED.role,
is_active = EXCLUDED.is_active,
updated_at = NOW();
-- Reset sequence to avoid ID conflicts
SELECT setval('admin_users_id_seq', (SELECT COALESCE(MAX(id), 0) + 1 FROM admin_users), false);