Every docker compose invocation in the Makefile now pins
-p warmbly so all git worktrees target the same compose
project. This means infra (postgres, redis, kafka, mailpit,
localstack, stripe-mock, cloud-tasks-emulator, zookeeper,
schema-registry) is brought up once and stays running across
worktree switches. App services (backend, consumer, worker,
tracking, realtime, web) recreate in place per worktree against
the bind-mounted source.
Removed targets:
- dev, dev-down, dev-logs (and the DEV_SVCS / SVCS vars)
Added targets:
- infra, infra-down
- app, app-down, app-logs
Daily flow becomes:
make infra # once, from any worktree
cd /path/to/worktree-a
make app # bring up app code for branch A
cd /path/to/worktree-b
make app # recreates app against branch B;
# infra untouched, caches warm
The named cache volumes already shared their content across
worktrees (warmbly_gomodcache, warmbly_gocache, warmbly_cargo_home,
warmbly_cargo_target, warmbly_mix_deps, warmbly_mix_build); pinning
the project name additionally makes container ownership shared,
which is what eliminates the per-worktree cold start.
README.md, resources/local-development.md, resources/deployment-guide.md,
deploy/README.md, and docker-compose.dev.yml all updated to reflect
the new targets.
The bind-mounted .git is owned by the host user but the dev
container runs as root, so git aborts with "dubious ownership"
and Go's automatic VCS stamping fails the build with:
error obtaining VCS status: exit status 128
Use -buildvcs=false to disable VCS stamping.
Production Dockerfiles are unaffected because they do not
bind-mount .git; they COPY source into the image and let Go
stamp normally.
PR #10 added 000035_api_key_suffix and PR #11 separately added
000035_api_key_smart_limits, both targeting the api_keys table.
golang-migrate refuses to load when two source files share a
version number, so the backend container failed health checks
in fresh stacks.
Bumping api_key_smart_limits to 000037 keeps PR #10 in its
original slot (it landed first) and matches the next free
version after 000036_contact_categories. The two migrations
touch different columns so apply order does not matter.
- gofmt-align ContactEngagement fields and drop trailing blank line
in contact/export.go
- remove no-op self-assignment ac.CustomFields = ac.CustomFields
flagged by govet
- useContactTimeline now uses cursor-based useInfiniteQuery (50/page,
before=oldest cached at) instead of a one-shot fetch
- search input filters subject/content/campaign/sequence/mailbox/
reason/intent; matches are highlighted in the row
- date range picker (popover with from/to + 7/30/90d presets) filters
the visible list by event timestamp
- segmented type chips with motion indicator
- IntersectionObserver sentinel auto-fetches next page as user scrolls
- when filters narrow the visible set, lazy-prefetch more pages so
results aren't artificially short (bounded to 250 events / 5 pages)
- skeleton rows with staggered pulse on first load, inline spinner on
subsequent page loads, "end of history" marker when done
- drop colored timeline rail and per-type dot colors
- collapse per-event bordered cards into one bordered list container
with divided rows (matches Overview's "Latest activity" treatment)
- segmented filter strip with motion indicator, matches main tab strip
- quote-style left border for body content (notes, reply snippets)
instead of a free-floating block
- solid slate-100 round avatar with slate-700 initials (no gradient)
- single contextual status pill only when something is off
(suppressed/unsubscribed); no chip when everything's fine
- text-only segmented tab strip, drop icons + side tint band
- flat stat tiles, no gradient hero variant
- keep animated motion indicator on tabs and email copy affordance