Files
honeyDueWeb/docs/02-core-crud.md
Trey t 5a50d77515 feat: complete Phase 3 — advanced features for Casera web app
Adds sharing (residence share codes, join, user management, .casera file
export/import), subscription status with feature comparison, notification
preferences with bell icon, profile settings (edit info, change password,
theme picker, delete account), onboarding wizard with create/join paths,
enhanced dashboard with stats cards, Recharts completion chart, recent
activity feed, and task report PDF download.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:31:29 -06:00

356 lines
12 KiB
Markdown

# Phase 2 — Core CRUD
Build the 4 primary domains: Residences, Tasks, Contractors, and Documents.
## Checklist
- [ ] Residences: list (with summary card), detail, create/edit form, delete
- [ ] Tasks: kanban board (drag-and-drop columns), create/edit form, task actions (complete, cancel, archive, in-progress)
- [ ] Task completion: form with file upload (photos), completion history with image viewer
- [ ] Task templates: autocomplete search + template browser
- [ ] Contractors: list (search, filter by favorite/specialty), detail (quick actions), create/edit form, delete
- [ ] Documents: tabbed view (warranties/documents), detail, create/edit form (type-specific fields), file upload/download, image gallery
---
## 1. Residences
### Screens
| Route | Screen | Description |
|-------|--------|-------------|
| `/app/residences` | Residence List | Grid of residence cards with summary data |
| `/app/residences/new` | Create Residence | Form: name, address, type, photo |
| `/app/residences/[id]` | Residence Detail | Summary dashboard, task/contractor/document counts, users |
| `/app/residences/[id]/edit` | Edit Residence | Same form as create, pre-filled |
### API Endpoints Used
| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/api/residences/my/` | User's residences with summaries |
| GET | `/api/residences/:id/` | Residence detail |
| POST | `/api/residences/` | Create residence |
| PUT | `/api/residences/:id/` | Update residence |
| DELETE | `/api/residences/:id/` | Delete residence |
### Components
- **ResidenceCard**: Summary card showing name, address, type icon, task counts (overdue, due soon, total)
- **ResidenceForm**: React Hook Form + Zod. Fields: name (required), address, residence type (dropdown from lookups), photo upload
- **ResidenceSummary**: Dashboard showing task breakdown, contractor count, document count
### TanStack Query Hooks
```typescript
useResidences() // GET /residences/my/
useResidence(id) // GET /residences/:id/
useCreateResidence() // POST /residences/
useUpdateResidence(id) // PUT /residences/:id/
useDeleteResidence(id) // DELETE /residences/:id/
```
### Cache Invalidation
After create/update/delete → invalidate `['residences']` and `['residence', id]` queries.
---
## 2. Tasks
### Screens
| Route | Screen | Description |
|-------|--------|-------------|
| `/app/tasks` | Kanban Board | All tasks across residences, grouped by column |
| `/app/residences/[id]/tasks` | Residence Kanban | Tasks for a specific residence |
| `/app/tasks/new` | Create Task | Full task form |
| `/app/tasks/[id]` | Task Detail | Full task info, completion history, actions |
| `/app/tasks/[id]/edit` | Edit Task | Same form as create, pre-filled |
| `/app/tasks/[id]/complete` | Complete Task | Completion form with photo upload |
### Kanban Board
Columns (from backend `TaskColumnsResponse`):
1. **Overdue** (red indicator)
2. **Due Today** (orange indicator)
3. **Due Soon** (yellow indicator, within 30 days)
4. **Upcoming** (blue indicator)
5. **In Progress** (green indicator)
6. **Completed** (gray indicator)
**Drag-and-drop**: Use `@dnd-kit/core` + `@dnd-kit/sortable` for dragging tasks between columns. Dropping a task triggers the appropriate API action:
- Drop on "In Progress" → `POST /tasks/:id/in-progress/`
- Drop on "Completed" → Opens completion form
- Other moves may just reorder (no API call)
**Board controls**:
- Filter by residence (dropdown)
- Filter by category, priority
- Search by title
### Task Form Fields
| Field | Type | Required | Source |
|-------|------|----------|--------|
| Title | Text / Autocomplete | Yes | Free text or template |
| Residence | Select | Yes | User's residences |
| Category | Select | No | Lookups (categories) |
| Priority | Select | No | Lookups (priorities) |
| Due Date | Date picker | No | Calendar |
| Frequency | Select | No | Lookups (frequencies) — for recurring tasks |
| Estimated Cost | Number | No | Currency input |
| Notes | Textarea | No | Free text |
| Assigned Contractor | Select | No | User's contractors |
### Task Actions
| Action | Endpoint | UI Trigger |
|--------|----------|------------|
| Complete | `POST /tasks/:id/complete/` | Button + completion form |
| Mark In Progress | `POST /tasks/:id/in-progress/` | Button or drag |
| Cancel | `POST /tasks/:id/cancel/` | Menu action |
| Archive | `POST /tasks/:id/archive/` | Menu action |
| Uncancel | `POST /tasks/:id/uncancel/` | Menu action |
| Unarchive | `POST /tasks/:id/unarchive/` | Menu action |
### Task Completion Form
| Field | Type | Required |
|-------|------|----------|
| Completed At | DateTime | Yes (default: now) |
| Actual Cost | Number | No |
| Notes | Textarea | No |
| Rating | Star rating (1-5) | No |
| Photos | File upload (multiple) | No |
File upload uses `FormData` with multipart, same as mobile's `submitFormWithBinaryData`.
### Task Templates
- **Autocomplete search**: As user types in title field, search `/api/task-templates/search/?q=...`
- **Template browser**: Modal with categorized templates, click to prefill form
- Template data populates: title, category, priority, estimated cost, frequency
### API Endpoints Used
| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/api/tasks/` | All user's tasks (kanban columns) |
| GET | `/api/tasks/by-residence/:id/` | Tasks for one residence |
| POST | `/api/tasks/` | Create task |
| PUT | `/api/tasks/:id/` | Update task |
| DELETE | `/api/tasks/:id/` | Delete task |
| POST | `/api/tasks/:id/complete/` | Complete task |
| POST | `/api/tasks/:id/in-progress/` | Mark in progress |
| POST | `/api/tasks/:id/cancel/` | Cancel task |
| POST | `/api/tasks/:id/archive/` | Archive task |
| POST | `/api/task-completions/` | Create completion (with images) |
| GET | `/api/task-completions/` | List completions |
| GET | `/api/task-templates/search/` | Search templates |
### TanStack Query Hooks
```typescript
useTasks() // GET /tasks/
useTasksByResidence(residenceId) // GET /tasks/by-residence/:id/
useTask(id) // GET /tasks/:id/
useCreateTask() // POST /tasks/
useUpdateTask(id) // PUT /tasks/:id/
useDeleteTask(id) // DELETE /tasks/:id/
useCompleteTask(id) // POST /tasks/:id/complete/
useTaskTemplateSearch(query) // GET /task-templates/search/?q=...
useCreateCompletion() // POST /task-completions/
```
---
## 3. Contractors
### Screens
| Route | Screen | Description |
|-------|--------|-------------|
| `/app/contractors` | Contractor List | Filterable list with search |
| `/app/contractors/new` | Create Contractor | Form with contact details |
| `/app/contractors/[id]` | Contractor Detail | Full info, quick actions, linked tasks |
| `/app/contractors/[id]/edit` | Edit Contractor | Same form as create, pre-filled |
### List Features
- **Search**: Filter by name, company
- **Filter**: By specialty (from lookups), by favorite
- **Sort**: By name, recently added
- **Quick actions**: Call, email, favorite toggle
### Contractor Form Fields
| Field | Type | Required | Source |
|-------|------|----------|--------|
| Name | Text | Yes | Free text |
| Company | Text | No | Free text |
| Phone | Phone | No | Tel input |
| Email | Email | No | Email input |
| Specialty | Select | No | Lookups (specialties) |
| Notes | Textarea | No | Free text |
| Is Favorite | Toggle | No | Boolean |
| Residence | Select | Yes | User's residences |
### Contractor Detail
- Contact info with click-to-call (`tel:`) and click-to-email (`mailto:`)
- Favorite toggle
- Linked tasks (tasks assigned to this contractor)
- Edit / delete actions
### API Endpoints Used
| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/api/contractors/` | User's contractors |
| GET | `/api/contractors/:id/` | Contractor detail |
| POST | `/api/contractors/` | Create contractor |
| PUT | `/api/contractors/:id/` | Update contractor |
| DELETE | `/api/contractors/:id/` | Delete contractor |
| POST | `/api/contractors/:id/favorite/` | Toggle favorite |
### TanStack Query Hooks
```typescript
useContractors() // GET /contractors/
useContractor(id) // GET /contractors/:id/
useCreateContractor() // POST /contractors/
useUpdateContractor(id) // PUT /contractors/:id/
useDeleteContractor(id) // DELETE /contractors/:id/
useToggleFavorite(id) // POST /contractors/:id/favorite/
```
---
## 4. Documents
### Screens
| Route | Screen | Description |
|-------|--------|-------------|
| `/app/documents` | Document List | Tabbed view: Warranties / Documents |
| `/app/documents/new` | Create Document | Form with type-specific fields |
| `/app/documents/[id]` | Document Detail | Full info, file viewer, image gallery |
| `/app/documents/[id]/edit` | Edit Document | Same form as create, pre-filled |
### Tabbed View
- **Warranties tab**: Documents with `is_warranty = true`. Shows expiry dates, status (active/expired/expiring soon)
- **Documents tab**: All other documents. Shows type, date added, file preview
### Document Form Fields
| Field | Type | Required | Source |
|-------|------|----------|--------|
| Title | Text | Yes | Free text |
| Residence | Select | Yes | User's residences |
| Type | Select | No | Document type options |
| Notes | Textarea | No | Free text |
| File | File upload | No | File picker |
| Is Warranty | Toggle | No | Boolean |
| Purchase Date | Date | Conditional | If warranty |
| Expiry Date | Date | Conditional | If warranty |
| Purchase Price | Number | Conditional | If warranty |
### Document Detail
- File preview (PDF viewer, image gallery)
- Download button
- Warranty status indicator (if warranty)
- Edit / delete actions
### API Endpoints Used
| Method | Endpoint | Purpose |
|--------|----------|---------|
| GET | `/api/documents/` | User's documents |
| GET | `/api/documents/:id/` | Document detail |
| POST | `/api/documents/` | Create document |
| PUT | `/api/documents/:id/` | Update document |
| DELETE | `/api/documents/:id/` | Delete document |
| POST | `/api/documents/:id/activate/` | Activate document |
| POST | `/api/documents/:id/deactivate/` | Deactivate document |
### TanStack Query Hooks
```typescript
useDocuments() // GET /documents/
useDocument(id) // GET /documents/:id/
useCreateDocument() // POST /documents/
useUpdateDocument(id) // PUT /documents/:id/
useDeleteDocument(id) // DELETE /documents/:id/
```
---
## Shared Patterns
### Form Pattern
Every CRUD form follows the same structure:
```typescript
// src/components/forms/TaskForm.tsx
const taskSchema = z.object({
title: z.string().min(1, 'Title is required'),
residenceId: z.number().min(1, 'Residence is required'),
categoryId: z.number().optional(),
// ...
});
type TaskFormData = z.infer<typeof taskSchema>;
export function TaskForm({ task, onSubmit }: Props) {
const form = useForm<TaskFormData>({
resolver: zodResolver(taskSchema),
defaultValues: task ? mapTaskToFormData(task) : defaults,
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* Fields */}
</form>
</Form>
);
}
```
### Mutation Pattern
```typescript
export function useCreateTask() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateTaskRequest) => api.tasks.createTask(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['tasks'] });
queryClient.invalidateQueries({ queryKey: ['residences'] }); // Summary counts change
},
});
}
```
### Loading / Error / Empty States
Every list and detail page handles three states:
1. **Loading**: Skeleton loader (shadcn Skeleton component)
2. **Error**: Error banner with retry button
3. **Empty**: Empty state illustration with CTA to create first item
## Deliverables
At the end of Phase 2, you should have:
1. Full CRUD for all 4 domains
2. Kanban board with drag-and-drop
3. Task completion with photo upload
4. Template search and autocomplete
5. All forms validated with Zod
6. Proper cache invalidation after mutations