Groups
Groups let users organize several pets and collaborate with people who care for them. They are optional: pets and direct PetRelationship records keep working without Groups, and the UI stays hidden until a user belongs to at least one Group.
Localized labels: Groups / Группы / Групи / Nhóm.
Domain Rules
- A user may belong to multiple Groups; a pet may belong to multiple Groups or none
- Group membership never creates owner/editor/viewer
PetRelationshiprows - Removing a user or pet from a Group never changes direct pet relationships
- Both Group roles (
admin,member) grant editor-equivalent view/update for Group pets - Both roles also grant full placement authority over Group pets: create, edit and close requests, and accept or reject responses. See Group Placement
- Ownership-only actions stay direct-owner-only: delete, transfer, manage people, add/remove pet from a Group
- A pet cannot be detached from a Group while it has an
openorpending_transferplacement request - Adopting a Group pet out permanently detaches it; it then appears in the Group's
group_pastsection - A Group always has at least one active admin (last-admin mutations lock the Group row)
API
Authenticated routes under /api/groups cover CRUD, members, pets, leave, and invitations. Pet creation accepts optional group_id (creator must be an active admin; assignment is atomic).
GET /api/my-pets/sections?group_id= filters the pets page to a Group context. Without it, All pets is the deduplicated union of direct and Group-accessible pets.
Sections always include group_past: pets this Group once held and no longer does, such as those it rehomed. It is empty outside Group context, and its entries carry no viewer_permissions — the Group keeps the record, not access to the pet.
Authenticated pet responses may include Group entries in viewer_permissions.access_sources. Public pet responses never expose Group names or access sources.
Frontend
/— context selector when the user has Groups; selection mode to create/add pets/groups,/groups/:groupId,/groups/:groupId/settings- Group mutations and context switching are online-only; offline falls back to cached All pets
Ledger Hooks
GroupLedgerSynchronization is called synchronously on pet attach/detach and Group delete. Until Finance/Ledgers exist, the binding is a no-op (NullGroupLedgerSynchronization).