Personal data · v1.0.0
Reuse a person without duplicating identity.
Contacts belong to one organization and can be ordered on many locations. Unlinking is not deletion, and one relationship can be primary.
One directory, explicit links
/contacts owns name, email, phone, active state, and revision. /locations/{locationId}/contacts owns order and primary status. Shared edits affect every linked location; unlinking preserves the directory record.
Search is literal, case/accent-insensitive, server-paged, and AND-term based. Similar names or numbers are suggestions only—crewQI never auto-merges people.
Least-privilege scopes
contacts:readreads/searches the directory and relationships.contacts:writemutates contacts and links.locations:readalone neither returns nor searches personal contact values.
With both read scopes, location responses add primaryContact and contactCount. Audit metadata records IDs, changed field names, and counts, never email or phone values. Deployments must redact the sensitive q query string from gateway and access logs.
Concurrency-safe relationships
Use Idempotency-Key on every write. Read the resource first and send its ETag through If-Match for edits, reorder, primary changes, unlink, and deactivation. A stale write returns 412; a still-linked deactivation returns 409 CONTACT_STILL_LINKED.
Compatibility and rollout
The additive migration creates one contact per legacy location without merging. Supported old clients continue through a temporary singular projection; editing a shared contact there clones it for one location and preserves email. Deploy database first and retain relational data on rollback.
This pre-adoption alignment keeps /v1 and 1.0.0. Issued-key inventory and available gateway/access logs must still prove zero external consumers immediately before release.
For exact examples and recovery details, read the source guide.