From 59cb72b57e903c0020b784eb7f0a7c0b01d1df51 Mon Sep 17 00:00:00 2001 From: neodk2004 Date: Sun, 23 Aug 2026 17:16:05 +0200 Subject: [PATCH] docs: add session handoff for admin mobile fix, breed taxonomy, Gitea #33 --- ...-mobile-breed-taxonomy-follower-privacy.md | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 .claude/handoffs/2026-08-23-admin-mobile-breed-taxonomy-follower-privacy.md diff --git a/.claude/handoffs/2026-08-23-admin-mobile-breed-taxonomy-follower-privacy.md b/.claude/handoffs/2026-08-23-admin-mobile-breed-taxonomy-follower-privacy.md new file mode 100644 index 0000000..ed98c1c --- /dev/null +++ b/.claude/handoffs/2026-08-23-admin-mobile-breed-taxonomy-follower-privacy.md @@ -0,0 +1,77 @@ +# Session Handoff: Admin Mobile Responsive, Breed Taxonomy Expansion, Follower Privacy (Gitea #33) + +**Date:** 2026-08-23 +**Project:** T:\CC-Projekte\OnlyPets (PawFeed) +**Session Duration:** ~4-5 hours (continuation of the same day's session — see also `2026-08-23-security-review-block-enforcement-full-sync.md` for the earlier security-review half of today) + +## Current State + +**Task:** Fix admin panel mobile responsiveness, expand dog/cat breed taxonomy to full FCI/FIFe lists, fix + extend the followers/following visibility bug (Gitea #33). +**Phase:** Complete +**Progress:** 100% — all three pieces deployed and verified live; Gitea #33 commented and closed. + +## What We Did + +User reported (via Gitea #10 comment) that the admin dashboard was unusable on mobile. Fixed the layout-level sidebar issue, then a follow-up report narrowed it to the Users admin page specifically still being broken — fixed that too. Both deployed and confirmed working by the user on their phone. + +User then asked to expand the dog/cat breed taxonomy to the full official FCI (dogs) and FIFe (cats) breed lists, in both English and German. Fetched both authoritative lists live (fci.be's nomenclature CSV via a GitHub mirror, fifeweb.org/cats/breeds/ directly), added everything missing on top of the existing curated lists, ran the seed against the shared dev/prod DB. + +User then asked to look at Gitea #33 ("Besucher sieht keine Follower") — a 404 bug when viewing another pet's followers/following list. Root-caused it to a wrong tRPC procedure choice, fixed it, and — per the issue's own request — added a full follower-visibility privacy setting (Everyone/Followers-only/Nobody) as a new feature alongside the fix. Commented and closed the Gitea issue when done. + +## Decisions Made + +- **Admin sidebar: hide behind a mobile drawer, not just shrink** — a `w-56` fixed sidebar had zero responsive handling; below `md:` it's now replaced by `AdminMobileNav` (hamburger + Sheet drawer), matching the existing `MobileNav.tsx`/`PostTypeSheet` pattern already in the app. +- **Breed taxonomy: only add, never rename/remove existing entries** — `Breed` upsert is keyed on `speciesId+name`, and existing breeds may already be referenced by `Pet.breedId`. Renaming to match FCI/FIFe's exact official wording would have created duplicate rows instead of updating in place, so the original 20 dog / 15 cat breeds were left untouched and the FCI/FIFe additions layered on top. +- **German breed translations: only where genuinely different, not for every breed** — `pickLocalizedName` already falls back to the canonical English/international name when no translation row exists, which is *correct* behavior for many FCI breeds (regional/foreign-named breeds aren't translated in German cynology literature either). Translated ~173/340 new dog breeds and 21/39 new cat breeds — the well-known ones — rather than guessing German names for very obscure regional breeds. +- **Gitea #33: fix the bug AND build the requested privacy feature in one pass** — user explicitly chose "Beides jetzt umsetzen" over doing just the bug fix first. Visibility levels (Everyone/Followers-only/Nobody) and default (Everyone) were both user-specified via AskUserQuestion, not guessed. +- **FOLLOWERS_ONLY semantics: "people who follow me", not "people I follow"** — deliberately distinct from `DmPolicy.FOLLOWERS_ONLY` (which checks the *recipient's* following list). Implemented as "does any pet owned by the caller follow the target pet" since the app's follow graph is pet-to-pet and the viewer isn't scoped to one specific pet when browsing. + +## Code Changes + +**Admin mobile responsive fix:** +- `src/components/admin/AdminMobileNav.tsx` (new) — mobile topbar + Sheet drawer nav. +- `src/app/p/[secret]/layout.tsx` — sidebar `hidden md:flex`, mobile nav wired in, responsive padding. +- `src/app/p/[secret]/users/page.tsx` — filter bar and per-user action-button row now stack on mobile (`flex-col sm:flex-row`), removed unconditional `shrink-0`/fixed widths. + +**Breed taxonomy expansion (commit `b0b8370`):** +- `prisma/seed.ts` — `DOG_BREEDS` 20→360 (all FCI-recognized breeds, fetched from fci.be), `CAT_BREEDS` 15→54 (all FIFe-recognized breeds, fetched from fifeweb.org). `DOG_BREEDS_DE`/`CAT_BREEDS_DE` extended with translations for the well-known subset (193/36 total entries respectively). Seed already run against the live shared DB — verified counts match. + +**Gitea #33 fix + feature (commit `75377c4`):** +- `prisma/schema.prisma` — new `FollowerVisibility` enum (`EVERYONE`/`FOLLOWERS_ONLY`/`NOBODY`) + `Pet.followerVisibility` field, default `EVERYONE`. Pushed via `prisma db push` (never `migrate` — shared dev/prod DB). +- `src/lib/assert-can-view-followers.ts` (new) — `assertCanViewFollowerLists(prisma, targetPetId, userId)`, owner always allowed, otherwise gated by the target's `followerVisibility`. +- `src/trpc/routers/follows.ts` — `listFollowers`/`listFollowing` call the new assertion before querying. +- `src/trpc/routers/pets.ts` — `update` procedure accepts `followerVisibility` (mirrors existing `dmPolicy` field). +- `src/app/(app)/pets/[petId]/followers/page.tsx`, `.../following/page.tsx` — **the actual bug fix**: `trpc.pets.byId` (owner-only, throws `FORBIDDEN` for pets you don't own) → `trpc.pets.getProfile` (public-safe, same procedure the real profile page already uses). Also now catch a `FORBIDDEN` from the list query and render a "private" message instead of erroring. +- `src/app/(app)/pets/[petId]/edit/page.tsx` — new "Who can see {name}'s followers?" Select in the Privacy section, next to the existing DM-policy control, same save-button pattern. +- `src/lib/gdpr-export.ts` — `followerVisibility` added to the per-pet GDPR export alongside `dmPolicy`. +- `messages/en.json`, `messages/de.json` — new `EditPet.*` and `FollowersPage.private`/`FollowingPage.private` keys. +- `src/__tests__/follows.test.ts` — updated `SOCL-03` tests to stub `mockPrisma.pet.findUnique` for the new assertion. + +**Key code context:** `pets.byId` (owner-only) vs `pets.getProfile` (public-safe, `NOT_FOUND`-only) is the load-bearing distinction in this codebase for "is this page for the owner or for any visitor" — grep for other pages using `pets.byId` outside of the edit page if a similar 404 bug is reported elsewhere. + +## Open Questions + +None outstanding — all three pieces of work were explicitly scoped and confirmed by the user (mobile fix tested on their phone, breed counts verified against the live DB, Gitea #33 comment+close done at the user's request). + +## Blockers / Issues + +- **Pre-existing lint debt, not touched:** `src/app/(app)/pets/[petId]/edit/page.tsx`'s `dmPolicy` sync-from-query `useEffect` already violated `react-hooks/set-state-in-effect` before this session (confirmed via `git stash` + lint). The new `followerVisibility` effect added here matches that same existing pattern for consistency — both are now flagged, but this is pre-existing project debt, not something introduced or that needs fixing as part of this task. +- **Claude-in-Chrome extension has no permission for `localhost`** — navigating it to `localhost:3000` silently lands on the real production `pawfeed.org` session instead (the tab was already logged into prod). Abandoned live browser verification for the admin mobile fix rather than risk touching production; verified via lint/tsc/code-review only. If live-in-browser verification is wanted again, the extension's site permissions need `localhost` added first. + +## Context to Remember + +- Everything this session (all 3 pieces) followed the same deploy loop: local edit → `tsc`/lint/vitest clean → `git commit` + `git push origin main` (Gitea, also the backup) → `scp`/`cat|ssh` the changed files to `/Dockers/PawFeed` on the NAS (bracket paths like `[petId]`/`[secret]`/`[token]` need `cat local | ssh user@host "cat > 'remote/path'"`, not plain `scp`, which fails on the brackets) → `cd /Dockers/PawFeed/docker && ./rolling-deploy.sh` (zero-downtime, rebuilds once + restarts `pawfeed-1/2/3` sequentially). +- Schema changes need **both** `npx prisma db push` (applies to the live shared DB immediately, from local) **and** uploading the updated `schema.prisma` to the server + a rebuild (so the server's own bundled Prisma Client also knows the new field/enum) — the DB and the running code's client can drift out of sync otherwise. +- Gitea issues/comments go through the `tea` CLI (`tea issue --repo admin/petfeed`, `tea comments add/list`, `tea issues close`) — already logged in, no token wrangling needed. + +## Next Steps + +1. [ ] None required — all three tasks are shipped, verified, and (for #33) the Gitea issue is closed. +2. [ ] If another mobile-responsiveness report comes in for a different admin page, check for the same two anti-patterns first: fixed-width elements in a `flex` row with no `sm:`/`md:` breakpoints, and `shrink-0` action-button clusters squeezing an info block. +3. [ ] If a similar "visitor gets 404 on another pet's X" report comes in, check whether that page uses `pets.byId` instead of `pets.getProfile` first — same root cause as #33. + +## Files to Review on Resume + +- `src/components/admin/AdminMobileNav.tsx` + `src/app/p/[secret]/layout.tsx` — admin mobile nav pattern, reusable if more admin pages need it. +- `src/lib/assert-can-view-followers.ts` — the new visibility-gate helper. +- `prisma/seed.ts` — now very large (897 lines); if breeds need touching again, the FCI/FIFe source additions are clearly commented and appended after the original curated lists.