- createInvite: use saveAndFlush when invalidating existing invite so the
UPDATE is guaranteed to hit the DB before the new INSERT, preventing
duplicate key violation on uq_household_invite_active
- acceptInvite: also set invalidated_at when marking invite as used, so
accepted invites are fully removed from the partial unique index and
cannot block future invite creation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Multi-stage Dockerfile for the backend (build + runtime).
Compose defines db (postgres:16-alpine with healthcheck) and app services.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>