Replace hand-rolled JWT auth with Better-Auth session-based authentication.
- Scaffold auth/ Node.js service with Better-Auth, bcrypt password compat,
Postgres adapter mapped to existing users table
- Add Alembic migration (002) creating sessions, accounts, verifications
tables and migrating password hashes to accounts table
- Update FastAPI auth dependency to validate sessions via shared DB
(supports both cookie and Bearer token)
- Remove registration/login/refresh endpoints from API gateway (now
handled by Better-Auth service)
- Update frontend to use better-auth/react client with httpOnly cookies
(no tokens in localStorage or memory)
- Rewrite auth store, Login, Register, Dashboard, Settings, ProtectedRoute
to use session-based auth
- Update all tests to create sessions directly in DB instead of JWT tokens
Resolves CAR-27
See plan: CAR-26#document-plan
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Kubernetes runAsNonRoot validation requires the USER directive to be
explicitly set in the image metadata. nginx-unprivileged runs as UID 101
internally, but without the explicit USER directive Kubernetes cannot
verify this from the image config and fails with CreateContainerConfigError.
Fixes CAR-231.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Non-root users cannot bind to ports < 1024. Port 8080 is used by
nginxinc/nginx-unprivileged by default.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Switch from nginx:stable-alpine to nginxinc/nginx-unprivileged:stable-alpine.
The unprivileged image runs as nginx user (UID 101) on port 8080, satisfying
the runAsNonRoot: true security context in Kubernetes.
Fixes: https://github.com/cartsnitch/infra/issues/65
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Full Twitter/X and Reddit promotional copy for all 5 shrinkflation
series posts (anchor top-10, dairy, frozen, household, snacks).
Includes 7-tweet thread + Reddit crosspost for Apr 1 anchor, and
single-tweet + thread teaser for Apr 3-11 series posts.
Refs: CAR-202, CAR-170, CAR-199
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds data-driven ranking of grocery products with the highest effective
unit price increases from shrinkflation between 2021 and 2025.
Refs: CAR-170, CAR-114, CAR-131
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Update frontmatter and footer navigation for dairy, frozen food,
household essentials, and snacks posts to match the cereal post series
format. Sets consistent series name "The Shrinkflation Files", correct
part numbers (2–5), and properly linked prev/next nav footers.
Refs: CAR-157, CAR-114
Co-authored-by: Frontend Frankie <frankie@cartsnitch.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* content: add founder story blog post — Why We Built CartSnitch
Replaces the Phase 1 draft with the final founder story from CMO
content-spec (CAR-134). Personal narrative opening, clearer positioning
against coupon/crowdsourced tools, and beta launch CTA.
Refs: CAR-134, CAR-114
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* content: merge founder story with data stats per Penny's review (v1.1)
Restores BLS/USDA statistics, specific shrinkflation examples, and
privacy footer from the original draft. Keeps the founder pasta story,
three-things framework, and cleaner positioning from the CMO content-spec.
Combined version addresses all points raised in Penny's changes-requested review.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
---------
Co-authored-by: Frontend Frankie <frankie@cartsnitch.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
* content: add shrinkflation series post 1 — The Shrinkflation Files: Cereal
Updates cereal blog post with final content-spec v1.0 from CAR-141.
Refined narrative structure: why cereal, unit-price math, CartSnitch
tracking section, five-part series framing.
Part of shrinkflation series (CAR-141, parent CAR-114).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* content: update cereal shrinkflation post to v1.1 with brand-specific data
Restores brand data table (Cheerios, Frosted Flakes, Lucky Charms, etc. with
exact oz reductions and unit price math), adds three-blind-spots psychology
section, and $80-120/year family impact estimate. Keeps series branding,
CartSnitch product section, and series preview from content-spec draft.
Addresses CEO changes-requested review on PR #29.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
---------
Co-authored-by: Frontend Frankie <frankie@cartsnitch.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Adds marketing blog post comparing CartSnitch, Flipp, Basket, and Ibotta.
Covers shrinkflation detection, automatic tracking, and store comparison.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Onboarding guides cover the five core user flows: getting started,
connecting store accounts, setting up price alerts, reading the
dashboard, and comparing stores. FAQ addresses common questions
about how CartSnitch works, data privacy, supported stores, and
troubleshooting.
All guides include screenshot placeholders for integration once
staging is available (blocked on CAR-60).
Ref: CAR-114
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The build-and-push job pulls nginx:stable-alpine from Docker Hub during
docker build. Anonymous pulls hit rate limits on self-hosted runners.
Add docker/login-action for Docker Hub using org secrets before the
build step (unconditional — needed for both PR and push builds).
Closes#22
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Tag container images with YYYY.MM.DD CalVer format on merge to main,
with build number suffix for same-day collisions. Creates matching
git tags (vYYYY.MM.DD). Retains latest tag as convenience alias.
GitHub issue: cartsnitch/infra#24
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Copy 10 marketing content files from the cmo/content-phase1 branch
of cartsnitch/agents into content/marketing/, preserving the
blog/, email/, and social/ subdirectory structure.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The correct self-hosted ARC runner label is runners-cartsnitch, not
cartsnitch-runners. All CI jobs were failing because no runners
matched the old label.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
We push to GHCR only per infrastructure policy. The Docker Hub login
step was added in error and would fail since DOCKERHUB_USERNAME/TOKEN
secrets are not configured.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Confirmed secrets are length 0 from CI runners. Docker Hub auth
cannot work until secrets are properly scoped to these repos.
Refs: CAR-77
Co-Authored-By: Paperclip <noreply@paperclip.ing>
DOCKERHUB_USERNAME/DOCKERHUB_TOKEN secrets are not accessible from
the self-hosted runners. Remove credentials blocks and login steps
to avoid template validation failures. Docker Hub pulls will use
anonymous access.
Refs: CAR-77
Co-Authored-By: Paperclip <noreply@paperclip.ing>