2.0 KiB
2.0 KiB
Organizational ticketing rollout
The organizational layer is additive: legacy tickets with no unit keep their existing visibility rules, while every ticket assigned to a unit is isolated by unit membership and database-managed Django permissions.
Admin setup order
- Create organizational units under Staff → Organizational units.
- Select the Django permissions inherited by every member of each unit.
- Assign staff through unit memberships and choose one primary unit.
- Classify external contacts as customer, supplier, carrier, or other.
- Create unit-owned contact groups and assign each contact to any number of groups.
- Create optional unit-specific SMS templates. A template with no unit is the global
fallback. Supported variables include
recipient_name,unit_name,company_name,magic_link,ticket_number, andsubject. - Grant
tickets.dispatch_group_ticketsto units allowed to create bulk dispatches. Grantaccounts.view_all_magic_linksonly to senior auditors who may inspect every unit; other Admin users see only links from their active unit memberships.
Useful unit permissions include tickets.view_ticket, tickets.claim_ticket,
tickets.transfer_ticket, tickets.share_ticket, tickets.change_ticket,
tickets.change_ticket_priority, tickets.delete_ticket, and
messaging.add_message.
Security invariants
- Each group recipient gets a separate
Ticket, notification job, and magic link. - External users can access only tickets whose
customer_idis their own user ID. - Unit filtering happens in both list querysets and object-level policy checks.
- Every valid magic-link opening appends an immutable access-log row and atomically increments its view counter.
- Raw magic-link tokens are never stored; only SHA-256 digests are persisted.
- Group dispatch runs inside a database transaction, preventing partially-created batches when validation or ticket creation fails.
Apply schema changes with:
.\.venv\Scripts\python.exe manage.py migrate