Skip to content

fix(passport): write PassportStamp when authed users visit a town#61

Merged
harshithmullapudi merged 1 commit into
mainfrom
fix/passport-stamp-write
Jul 13, 2026
Merged

fix(passport): write PassportStamp when authed users visit a town#61
harshithmullapudi merged 1 commit into
mainfrom
fix/passport-stamp-write

Conversation

@harshithmullapudi

Copy link
Copy Markdown
Member

Bug

Signed-in visitors were seeing 0 stamps on their passport no matter how many towns they walked into. Reproduced from an incident screenshot — a real user (Manik) with a valid passport id and one owned town landed on `/passport` and the right page was blank.

Root cause: the passport read side, the display, the PDF export, the OG image, and the entry toast all shipped in #57. The write-site hook — the actual `PassportStamp` upsert on visit — was called out explicitly in the follow-up section of that PR and never landed.

Fix

  • New helper `upsertPassportStamp(userId, townId, townOwnerId)` at `apps/web/src/lib/passport/stamp.ts`. Idempotent on `(userId, townId)`:
    • First visit → creates the row (`firstVisitedAt = now`, `visitCount = 1`).
    • Subsequent visits → bump `lastVisitedAt`, increment `visitCount`.
  • No-op if `userId === townOwnerId` — mirrors the schema rule from feat(passport): shareable identity + per-town stamps + PDF export #57. Own-town visits already surface as `TOWNS OWNED: N` on the identity page.
  • Called fire-and-forget from the visitor path in `apps/web/src/app/[town]/page.tsx`, right alongside `creditFirstVisitAura` and `recordTownActivity`, and gated on:
    1. `session` exists (CORE-authed viewer)
    2. `session.user.id !== town.ownerId`
  • Guests are still handled at read time in `loadGuestPassportData` by aggregating every `town-visit-` cookie in the browser — unchanged.

Related

Test plan

  • Sign in with CORE. Visit a public town you don't own via a valid share code / invite link.
  • Immediately visit `/passport` — the town appears as a stamp on the right page, and `0 STAMPS` becomes `1 STAMP` in the subtitle.
  • Refresh the same town → `visitCount` increments in the DB, but the stamp gallery doesn't duplicate (first-visit-date locked, `@@unique([userId, townId])` guarantees idempotency).
  • Visit your own town → no new stamp row created (owner-filter kicks in).
  • Guest mode (incognito) → guest flow still populates from the per-town cookies as before, unchanged.
  • Public passport URL `/passport/[passportId]` on the same user now shows the stamp too.

🤖 Generated with Claude Code

The read side + display + PDF + toast all shipped in #57, but the
write-site hook was flagged as a follow-up and never landed. Result:
signed-in visitors saw 0 stamps forever no matter how many towns they
walked into.

- New `upsertPassportStamp(userId, townId, townOwnerId)` helper.
  Idempotent on `(userId, townId)`: first visit creates the row,
  subsequent visits bump `lastVisitedAt` and increment `visitCount`.
  No-op if the visitor is the town's owner (mirrors the schema rule —
  own-town visits show as `TOWNS OWNED: N` on the identity page and
  don't need to stamp too).
- Called fire-and-forget from the visit path in `[town]/page.tsx`,
  right next to `creditFirstVisitAura` and `recordTownActivity`.
  Only fires for signed-in viewers; guests are still aggregated at
  read time from their `town-visit-<slug>` cookies in `loadGuestPassportData`.

Closes the write-site gap on #55.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@harshithmullapudi
harshithmullapudi merged commit 2fb7f90 into main Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant