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

View File

@@ -20,6 +20,7 @@ type DocumentUserResponse struct {
type DocumentResponse struct {
ID uint `json:"id"`
ResidenceID uint `json:"residence_id"`
Residence uint `json:"residence"` // Alias for residence_id (KMM compatibility)
CreatedByID uint `json:"created_by_id"`
CreatedBy *DocumentUserResponse `json:"created_by,omitempty"`
Title string `json:"title"`
@@ -41,13 +42,7 @@ type DocumentResponse struct {
UpdatedAt time.Time `json:"updated_at"`
}
// DocumentListResponse represents a paginated list of documents
type DocumentListResponse struct {
Count int `json:"count"`
Next *string `json:"next"`
Previous *string `json:"previous"`
Results []DocumentResponse `json:"results"`
}
// Note: Pagination removed - list endpoints now return arrays directly
// === Factory Functions ===
@@ -69,6 +64,7 @@ func NewDocumentResponse(d *models.Document) DocumentResponse {
resp := DocumentResponse{
ID: d.ID,
ResidenceID: d.ResidenceID,
Residence: d.ResidenceID, // Alias for KMM compatibility
CreatedByID: d.CreatedByID,
Title: d.Title,
Description: d.Description,
@@ -96,16 +92,11 @@ func NewDocumentResponse(d *models.Document) DocumentResponse {
return resp
}
// NewDocumentListResponse creates a DocumentListResponse from a slice of documents
func NewDocumentListResponse(documents []models.Document) DocumentListResponse {
// NewDocumentListResponse creates a list of document responses
func NewDocumentListResponse(documents []models.Document) []DocumentResponse {
results := make([]DocumentResponse, len(documents))
for i, d := range documents {
results[i] = NewDocumentResponse(&d)
}
return DocumentListResponse{
Count: len(documents),
Next: nil,
Previous: nil,
Results: results,
}
return results
}