Make contractor residence optional with visibility rules

- Make residence_id nullable in contractor model
- Add created_by_id field to track contractor creator
- Update access control: personal contractors visible only to creator,
  residence contractors visible to all residence users
- Add database migration for schema changes
- Update admin panel DTOs and handlers for optional residence
- Fix test utilities for new model structure

🤖 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-29 18:42:11 -06:00
parent 9e91e274e8
commit 4e9b31377b
13 changed files with 123 additions and 97 deletions

View File

@@ -2,33 +2,35 @@
-- Run with: ./dev.sh seed
-- Residence Types (only has: id, created_at, updated_at, name)
-- Ordered A-Z by name
INSERT INTO residence_residencetype (id, created_at, updated_at, name)
VALUES
(1, NOW(), NOW(), 'House'),
(2, NOW(), NOW(), 'Apartment'),
(3, NOW(), NOW(), 'Condo'),
(4, NOW(), NOW(), 'Townhouse'),
(5, NOW(), NOW(), 'Duplex'),
(6, NOW(), NOW(), 'Mobile Home'),
(7, NOW(), NOW(), 'Vacation Home'),
(8, NOW(), NOW(), 'Other')
(1, NOW(), NOW(), 'Apartment'),
(2, NOW(), NOW(), 'Condo'),
(3, NOW(), NOW(), 'Duplex'),
(4, NOW(), NOW(), 'House'),
(5, NOW(), NOW(), 'Mobile Home'),
(6, NOW(), NOW(), 'Other'),
(7, NOW(), NOW(), 'Townhouse'),
(8, NOW(), NOW(), 'Vacation Home')
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
updated_at = NOW();
-- Task Categories (has: name, description, icon, color, display_order)
-- Ordered A-Z by name with display_order matching
INSERT INTO task_taskcategory (id, created_at, updated_at, name, description, icon, color, display_order)
VALUES
(1, NOW(), NOW(), 'Plumbing', 'Plumbing related tasks', 'wrench', '#3498db', 1),
(2, NOW(), NOW(), 'Electrical', 'Electrical work and repairs', 'bolt', '#f1c40f', 2),
(3, NOW(), NOW(), 'HVAC', 'Heating, ventilation, and air conditioning', 'thermometer', '#e74c3c', 3),
(4, NOW(), NOW(), 'Appliances', 'Appliance maintenance and repair', 'cog', '#9b59b6', 4),
(5, NOW(), NOW(), 'Exterior', 'Exterior maintenance and landscaping', 'tree', '#27ae60', 5),
(6, NOW(), NOW(), 'Interior', 'Interior maintenance and repairs', 'home', '#e67e22', 6),
(7, NOW(), NOW(), 'Safety', 'Safety and security tasks', 'shield', '#c0392b', 7),
(8, NOW(), NOW(), 'Cleaning', 'Cleaning and sanitation', 'broom', '#1abc9c', 8),
(9, NOW(), NOW(), 'Pest Control', 'Pest prevention and control', 'bug', '#8e44ad', 9),
(10, NOW(), NOW(), 'General', 'General maintenance tasks', 'tools', '#7f8c8d', 99)
(1, NOW(), NOW(), 'Appliances', 'Appliance maintenance and repair', 'cog', '#9b59b6', 1),
(2, NOW(), NOW(), 'Cleaning', 'Cleaning and sanitation', 'broom', '#1abc9c', 2),
(3, NOW(), NOW(), 'Electrical', 'Electrical work and repairs', 'bolt', '#f1c40f', 3),
(4, NOW(), NOW(), 'Exterior', 'Exterior maintenance and landscaping', 'tree', '#27ae60', 4),
(5, NOW(), NOW(), 'General', 'General maintenance tasks', 'tools', '#7f8c8d', 5),
(6, NOW(), NOW(), 'HVAC', 'Heating, ventilation, and air conditioning', 'thermometer', '#e74c3c', 6),
(7, NOW(), NOW(), 'Interior', 'Interior maintenance and repairs', 'home', '#e67e22', 7),
(8, NOW(), NOW(), 'Pest Control', 'Pest prevention and control', 'bug', '#8e44ad', 8),
(9, NOW(), NOW(), 'Plumbing', 'Plumbing related tasks', 'wrench', '#3498db', 9),
(10, NOW(), NOW(), 'Safety', 'Safety and security tasks', 'shield', '#c0392b', 10)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
description = EXCLUDED.description,
@@ -83,25 +85,27 @@ ON CONFLICT (id) DO UPDATE SET
display_order = EXCLUDED.display_order,
updated_at = NOW();
-- Contractor Specialties (check actual columns)
INSERT INTO task_contractorspecialty (id, created_at, updated_at, name)
-- Contractor Specialties (has: name, description, icon, display_order)
-- Ordered A-Z by name with display_order matching
INSERT INTO task_contractorspecialty (id, created_at, updated_at, name, display_order)
VALUES
(1, NOW(), NOW(), 'Plumber'),
(2, NOW(), NOW(), 'Electrician'),
(3, NOW(), NOW(), 'HVAC Technician'),
(4, NOW(), NOW(), 'Handyman'),
(5, NOW(), NOW(), 'Landscaper'),
(6, NOW(), NOW(), 'Painter'),
(7, NOW(), NOW(), 'Roofer'),
(8, NOW(), NOW(), 'Carpenter'),
(9, NOW(), NOW(), 'Appliance Repair'),
(10, NOW(), NOW(), 'Pest Control'),
(11, NOW(), NOW(), 'Cleaner'),
(12, NOW(), NOW(), 'Pool Service'),
(13, NOW(), NOW(), 'Locksmith'),
(14, NOW(), NOW(), 'General Contractor')
(1, NOW(), NOW(), 'Appliance Repair', 1),
(2, NOW(), NOW(), 'Carpenter', 2),
(3, NOW(), NOW(), 'Cleaner', 3),
(4, NOW(), NOW(), 'Electrician', 4),
(5, NOW(), NOW(), 'General Contractor', 5),
(6, NOW(), NOW(), 'Handyman', 6),
(7, NOW(), NOW(), 'HVAC Technician', 7),
(8, NOW(), NOW(), 'Landscaper', 8),
(9, NOW(), NOW(), 'Locksmith', 9),
(10, NOW(), NOW(), 'Painter', 10),
(11, NOW(), NOW(), 'Pest Control', 11),
(12, NOW(), NOW(), 'Plumber', 12),
(13, NOW(), NOW(), 'Pool Service', 13),
(14, NOW(), NOW(), 'Roofer', 14)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
display_order = EXCLUDED.display_order,
updated_at = NOW();
-- Subscription Settings (singleton)