Commit Graph
356 Commits
Author SHA1 Message Date
admin 82c9bb87b9 feat(mobile): add multi-image indicator to feed posts
Multi-photo posts gave no visual hint they were swipeable — a viewer
would only ever see the first image unless they already knew to swipe.
Adds a "1 / N" counter badge (top-right overlay) and a dot-page
indicator below the carousel, porting web's PostCard indicators.
2026-09-06 20:12:21 +02:00
admin 086b0e8900 docs(mobile): update found.md for notification/comments dark-mode fixes 2026-09-06 19:57:31 +02:00
admin 3d196b1528 fix(mobile): notification post link and actor-name link, comments dark mode
Notification taps for post-related types (REACTION/COMMENT/MENTION/
PAW_BACK) landed on a bare "no comments yet" screen with no sign of the
actual post. The comments screen now fetches the post via the existing
posts.getById and shows it (image/caption/header) via the shared
PostCard above the comment list.

The actor's name in each notification row is now its own tappable text
run that links to their profile, separate from tapping the rest of the
row (which still opens the notification's target) — ported from web's
notifications page, which does the same split between a Link and plain
text.

Also fixed: the comments screen used the static (light-only) color
tokens throughout, so embedding the theme-aware PostCard produced
near-invisible light text on its own light background in dark mode.
Converted the screen to useTheme() like the rest of the dark-mode-
converted screens.
2026-09-06 19:56:48 +02:00
admin 73ea97ac16 fix(mobile): notification separators/navigation, own-post delete option
Notifications: add a visible hairline separator between rows and make
each row tappable — it marks read and navigates to the relevant post
(comments screen) or pet profile, porting web's getHref()/getPostId()
routing logic.

Feed: the "..." menu on a post now opens a delete confirmation instead
of the report sheet when the post belongs to the currently active pet;
report sheet stays unchanged for posts from other pets. Reuses the
pre-existing posts.delete mutation, no backend changes needed.
2026-09-06 19:39:52 +02:00
admin 6b01046ded feat(mobile): mix trending posts into the Feed, update app icon assets
- explore.getTrending posts are now interleaved into the chronological
  Feed at semi-random intervals (src/lib/interleave-trending.ts),
  marked with a small "Trending" badge on PostCard — a lightweight
  stand-in for web's separate Explore "Trending" tab, which mobile
  wasn't going to get as its own screen. No backend change: reuses the
  existing explore.getTrending procedure as-is.
- update app icon / splash / favicon / Android adaptive-icon assets
  (user-provided)
- README: correct the now-stale Dark Mode "not yet converted" list
  (Explore/Notifications/pet profile/health were converted in the
  found.md batch) and document the report/date-format/pinch-zoom/
  legal-links fixes
2026-09-06 19:12:39 +02:00
admin 4a35fce20b fix(mobile): found.md batch — reports, dark mode, health form fixes
- new report feature: a "..." button on every post opens a reason-picker
  sheet (reports.create), matching web's ReportSheet reasons/copy
- pet profile, edit, followers/following, and the whole health screen
  (incl. consent gate) converted to the makeStyles(colors) dark-mode
  pattern
- fixed the invisible back button on every pushed (app)/_layout.tsx
  screen: headerTintColor was never set, so the native-stack default
  back chevron kept its platform tint instead of the theme color —
  black-on-black in dark mode looked like a missing button entirely
- health forms (weight/vet visit/vaccine) now take dates as DD-MM-YYYY
  instead of the backend's raw YYYY-MM-DD, converting internally
  (src/lib/date-format.ts); invalid dates now show an error instead of
  the mutation silently failing with no onError handler at all — this,
  not persistence, was the actual "Gesundheitsdaten werden nicht
  gespeichert" bug
- pinch-to-zoom on the full-screen image viewer via a plain
  PanResponder (no new native dependency)
- Pets tab: language switcher now uses flag emoji (🇩🇪/🇬🇧/🌐), and a
  new footer section links Impressum/Datenschutz/Nutzungsbedingungen
  plus the installed app version

All live-verified against the deployed backend except pinch-zoom
(two-finger gestures aren't simulatable over adb).
2026-09-06 18:55:12 +02:00
admin 462f295caa feat(mobile): add German/English i18n across the whole app
- i18next + react-i18next + expo-localization: device-locale detection,
  an MMKV-persisted DE/EN/Automatisch override (mirrors web's cookie-only
  locale, no backend field needed), and a language switcher on the Pets
  tab next to the theme toggle
- every screen and shared component converted from hardcoded German
  strings to translation keys; de.json/en.json kept in exact key-parity
  (218 keys each, verified programmatically)
- backend: src/trpc/init.ts now accepts an x-locale header as a fallback
  locale source (cookie still wins, web unaffected) since mobile has no
  cookie jar to set NEXT_LOCALE in; mobile's tRPC client sends the
  current language on every request
- fixes a latent bug: species/breed pickers were hardcoded to locale
  "de" while every other pet query resolved names via ctx.locale's
  default (English, since mobile never sent a locale cookie) — both now
  use the same current-language value
- expo-localization is a new native module (config plugin) and needs a
  native rebuild to actually link; deviceLocale() falls back to English
  instead of crashing when it isn't linked yet, so the app stays usable
  before that rebuild happens

Needs a NAS deploy (src/trpc/init.ts is shared backend code) before the
x-locale fallback and the species/breed locale fix take effect for mobile.
2026-09-06 17:31:41 +02:00
admin 0c6421c8de fix(mobile): dark mode on Explore/Notifications, breed dropdown overlay
- Explore and Notifications tabs now read colors from ThemeContext
  instead of the static light-only tokens
- OptionPicker's option list is position:absolute so it overlays
  following content instead of pushing it down, with zIndex on the
  component root (and FlatList's ListHeaderComponentStyle on Explore)
  so it actually paints above sibling content instead of underneath it
- check off found.md's resolved items, record the three newly reported ones
2026-09-06 16:30:02 +02:00
admin 0408be2063 feat(mobile): add onboarding flow, dark mode, and bugfixes
- 5-step onboarding (guidelines, upload consent, spider opt-in, pet
  creation, avatar) that gates first launch until a pet exists
- Add/delete pet flows on the Pets tab, with a shared OptionPicker
  (ScrollView-based, not FlatList, to avoid nested-VirtualizedList
  warnings inside onboarding's outer ScrollView)
- App-wide light/dark/auto theme via ThemeContext, synced with the
  existing owner.getThemePreference/setThemePreference backend
  procedures; core navigation chrome, Feed, Pets tab, and shared
  primitives (Button, TextField, Card, PetAvatar, PostCard, StoryTray)
  converted to the makeStyles(colors) pattern
- found.md fixes: safe-area insets on image/story viewers so controls
  clear the status bar, auto-mark-all-read on the notifications tab,
  and an Explore species/breed filter
2026-09-06 16:14:44 +02:00
adminandClaude Sonnet 5 330cfdeac2 feat(mobile): add sign-up screen
sign-in.tsx only ever covered login (per its own comment "sign-up screens
are follow-up work"). Adds the other half: email/password sign-up using
Clerk's Futures API (signUp.password() -> verifications.sendEmailCode()/
verifyEmailCode() -> finalize()), mirroring sign-in.tsx's two-step
credentials/verify shape. No invite-code step, since INVITE_REQUIRED is
globally off on the backend since launch.

Verified live on the Android emulator: real Clerk validation surfaces
correctly (breached-password rejection), and a valid submission correctly
sends a verification email and transitions to the code-entry step.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:49:13 +02:00
adminandClaude Sonnet 5 a890904b6c docs(mobile): document the full push-notification setup and its gotchas
Push notifications went from "wired but not deliverable" to fully working
end-to-end this session. Records the three separate one-time setup pieces
(EAS project id, FCM credentials baked at prebuild time, and the FCM V1
vs. Legacy service-account-key slot mixup that produced a confusing
"Unable to retrieve the FCM server key" error) so a future session doesn't
have to rediscover them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:28:03 +02:00
adminandClaude Sonnet 5 fcb5ae3eef chore(mobile): add eas.json build profile config
Minimal EAS Build config (development/preview/production profiles) —
needed by `eas credentials` to manage the FCM push key, no EAS Build
runs yet. Push notifications are now fully verified end-to-end: real
device token minted, registered with the backend, and a live push
delivered to the Android emulator's notification tray.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:27:13 +02:00
adminandClaude Sonnet 5 d3bf94799e fix: exclude mobile/ from the web app's TypeScript checking and Docker build
Next.js's production build type-checks the whole repo by tsconfig.json's
default include glob, which picked up mobile/'s .tsx files once the
Docker image's git checkout finally included mobile/ (first pull to
include it) — none of mobile's own dependencies (react-native, expo-router,
...) are installed in that container, so the build failed outright.
mobile/ is now excluded from tsconfig.json and .dockerignore; it's a
separate app with its own tsconfig/package.json and was never meant to be
type-checked or shipped as part of the web image.

Also completes the mobile EAS/FCM push setup (app.json's extra.eas.projectId
and googleServicesFile, google-services.json gitignored) and adds a 15s
timeout around getExpoPushTokenAsync so a device that can't reach FCM fails
visibly instead of hanging silently forever.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 14:07:27 +02:00
adminandClaude Sonnet 5 a3f19ff70f feat(mobile): add health tracking, milestones, messaging, and push registration
Health: consent gate (Art. 9 DSGVO) plus weight/vet-visit/vaccine log
sections, gated behind health.getConsentStatus like the web app.
Milestones: view a pet's milestone posts and create the 5 user-initiated
types with an optional photo. Messaging: chat detail/compose screen
(messages/[conversationId].tsx) polling while focused, reachable from the
conversations list and from a pet profile's new "Nachricht" entry point.
Push: usePushNotifications requests permission and registers the Expo
push token with owner.registerPushToken; real delivery still needs an EAS
project id (`eas init`), tracked in the README.

All four verified live on a real Android emulator: health CRUD (add/list/
delete a weight log), Health/Milestones/Nachricht entry points gated
correctly by own-pet vs. other-pet, and full chat history loading via an
existing conversation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:50:07 +02:00
adminandClaude Sonnet 5 0323e8d449 feat: add Expo push notification infrastructure
Owner.expoPushToken + owner.registerPushToken/clearPushToken, plus a
best-effort Expo push send wired into notify() alongside the existing
in-app Notification row. Missing/expired token or unreachable Expo push
service silently no-ops — push delivery must never break the underlying
action it's attached to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 09:49:02 +02:00
adminandClaude Sonnet 5 eda6d3b801 feat(mobile): add stories, video playback, and search
Story tray/creation/viewer with PawRing seen/unseen indicator, expo-video
playback for VIDEO posts (replacing the static placeholder), and a
pets/people/hashtags search screen reachable from the Explore tab header.
Extracts FollowButton from the pet-profile screen since search results
need the same follow/unfollow toggle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 08:53:07 +02:00
admin 8aa89e1011 docs(mobile): update README for repost creation 2026-09-05 15:44:05 +02:00
admin 925d121bb8 feat(mobile): add repost (Paw-Back) creation
PawBackButton toggles reposts.create/delete with an isReposted-backed
optimistic state, mirroring web's PawBackButton — replaces the static
repost count in PostCard's action row. RepostCard renders a REPOST
post as a read-only "Paw-Back von {name}" attribution wrapper around
the original post's pet header, image, and caption, ported from web's
RepostCard with no action row (matches web: only the original post is
reactable/commentable).
2026-09-05 15:43:48 +02:00
admin 257319e81e docs(mobile): update README for post creation and comments 2026-09-05 15:36:05 +02:00
admin 085d2abb53 feat(mobile): add post creation and comments
Post creation: gallery/camera picker (expo-image-picker) uploads each
image straight to Supabase Storage via a presigned PUT
(posts.getPresignedUrl + expo-file-system), then posts.create with the
resulting storage keys — reachable via a new "+" header button on the
Feed tab. No client-side blurhash (browser Canvas API, no RN
equivalent) or AI-disclosure/mention support yet, matching the rest of
mobile's plain-text captions.

Comments: a dedicated screen (posts/[postId]/comments) for reading,
posting, and deleting one's own comments, reachable by tapping the
comment icon on a PostCard. Ported from web's PostDetailDialog comment
panel, scoped down to just that panel since mobile's image full-view
already has its own route.
2026-09-05 15:35:32 +02:00
admin c1067b3245 feat(mobile): add header wordmark and full-screen image viewer
Header now shows the PawFeed paw+text logo on the Feed tab (matching
web's Sidebar wordmark). Tapping a post image opens a full-screen
viewer as a route-based fullScreenModal, with a blurred edge-to-edge
copy of the same photo behind the sharp foreground image instead of a
flat black backdrop, for a more dynamic Photos-app-style lightbox.
2026-09-05 14:53:13 +02:00
admin 72f09e9f12 docs(mobile): update README — pet profile is done, adjust remaining list 2026-09-05 13:48:09 +02:00
admin a737a17976 fix(mobile): feed separation, adaptive launcher icon; feat: full pet profile
Fixes from user testing on a real device:
- Feed: replaced an invisible spacing-only separator with an actual
  hairline divider between posts.
- Android launcher icon showed Expo's default placeholder (a blue arrow)
  because the app icon and the Android adaptive-icon layers
  (foreground/background/monochrome) are two separate asset sets — only
  icon.png/favicon.png had been replaced. Added scripts/derive-adaptive-
  icon.js to crop the paw glyph out of icon.png (detected by its marigold
  color) and generate all three adaptive-icon layers plus the splash icon;
  this is an explicit placeholder per user's own call, not final art.

New: full pet profile (app/(app)/pets/[petId]/), matching web's
src/app/(app)/pets/[petId]/page.tsx:
- View: identity, species, bio/adoption story, follower/following counts
  (tappable → list screens), the pet's own posts below.
- Follow/unfollow with real initial state (follows.isFollowing) and
  optimistic toggle — unlike feed reactions, this endpoint actually
  exists, so no need to fake an initial state.
- Edit screen (name/nickname/bio/adoption story via pets.update) for the
  owner's own pets.
- Tapping a pet (feed header, Explore card, Pets-tab row) now opens this
  profile instead of nowhere; the Pets tab's active-pet switch is now a
  separate checkmark control instead of overloading the whole row tap.

PostCard's post-shape prop is now structural rather than tied to
feed.getFeed's output type, since posts.byPetId selects `pet` via the
narrower petIdentitySelect (no isVerified/owner) — both need to satisfy
the same component.

Verified end-to-end on-device: feed separator visible, own-pet profile
shows a working Bearbeiten button whose form is correctly prefilled (a
stray edit was made to Bianca's nickname field by mistake during testing
and was discarded via back-navigation without saving — never sent to the
server), someone else's pet profile shows a working Follow/Unfollow
toggle, followers list navigates correctly, and the home-screen launcher
icon now shows the paw instead of the default Expo icon.
2026-09-05 13:47:20 +02:00
admin c35d4cda46 feat(mobile): Phase 1 — real Feed/Explore/Notifications/Pets tabs
Moves the mobile app from a connectivity scaffold to a real Phase 1 app:

- Migrate off Expo Go onto a local custom dev client (expo-dev-client,
  built via expo prebuild + expo run:android against the local Android
  SDK — no EAS account needed). Needed because react-native-mmkv requires
  native code Expo Go doesn't ship.
- Persisted, MMKV-backed TanStack Query cache (PersistQueryClientProvider)
  plus expo-image, so a relaunch renders the last-known feed/pets/
  notifications instantly instead of a blank screen while refetching.
- ActivePetContext: every pet-scoped procedure requires an explicit petId
  server-side (no server-side "current pet"), ported from web's
  ActivePetContext, MMKV-backed instead of localStorage.
- Bottom Tabs (Feed/Explore/Notifications/Pets) mirroring the web app's
  actual mobile nav, with Messages as a header button rather than a tab
  (matches web). Feed, PostCard, PawButton reactions, pet discovery grid,
  notifications list, and a conversations list are all wired to the real
  backend and verified against the live database.
- Design tokens/components extended with PostCard/PawButton/PetAvatar/
  PetIdentityBadges, all styled from the existing src/theme/tokens.ts.
- Fixed a react/react-dom version mismatch surfaced along the way, and
  handle Clerk's needs_client_trust (Device Trust) sign-in status with an
  email-code step.

Verified end-to-end in the Android emulator against pawfeed.org: feed
scrolls and paginates with real posts/images, paw reactions toggle
optimistically and persist, pet switching updates every screen, and
notifications/explore show live data.
2026-09-05 13:19:01 +02:00
admin c4aaa8b3d6 feat(mobile): update app icon and favicon to PawFeed branding 2026-09-05 11:58:17 +02:00
admin dc344f1188 feat(mobile): match PawFeed web design system, fix Clerk device trust
- Add design tokens (colors, radii, typography) mirroring DESIGN.md's
  "Spotlight Porch" system, plus Button/TextField/Card components built
  on them. Restyle the sign-in and placeholder home screens to match.
- Load Inter via @expo-google-fonts/inter, gate rendering on fonts +
  Clerk being ready instead of a blank screen.
- Pin react-dom to match react's version — Metro/Hermes hard-require
  exact equality, and react-dom wasn't pinned anywhere before.
- Handle Clerk's `needs_client_trust` status (Device Trust, tied to the
  dashboard's Native Applications API): send/verify an email code
  before finalizing sign-in.

Verified end-to-end in the Android emulator against the live backend:
sign-in, device-trust code verification, and the home screen showing
real stats.getPublicStats data.
2026-09-05 11:51:17 +02:00
admin 9eb31c3323 feat(mobile): add Expo/React Native scaffold for PawFeed Android app
Connectivity + auth scaffold only: Expo Router, Clerk session auth via
expo-secure-store, and a type-only tRPC AppRouter import from the web
app's router — no backend changes needed. See mobile/README.md.
2026-09-05 11:01:49 +02:00
admin c225c9aef7 fix(admin): mount Clerk client SDK on admin panel to stop UNAUTHORIZED
The admin panel (src/app/p/[secret]/layout.tsx) never wrapped its tree
in ClerkThemeProvider, unlike (app)/layout.tsx — a SpeedUp-Plan P0
optimization that deliberately kept Clerk's client bundle off routes
without a <UserButton/>. Consequence: no client-side session-token
refresh ran on admin pages. The initial page load stayed authenticated
(Clerk's server-side handshake reissues the token on full document
navigations), but subsequent tRPC XHRs — e.g. legal.publish — started
failing with UNAUTHORIZED/401 a few minutes in, since that handshake
only fires for navigations, not fetch calls. Confirmed live: a fresh
page reload always restored a working session, matching this exactly.

Mounting ClerkThemeProvider in the admin layout re-adds background
token refresh. Also gives the legal-publish error handler an
actionable message for UNAUTHORIZED specifically (distinct from other
failures), since a residual case can still occur after a real 7-day
session expiry.
2026-09-04 17:56:43 +02:00
admin e9378d9d7a feat(health): require explicit, revocable consent for Health-Tracking
Add a per-pet consent gate (Art. 9 Abs. 2 lit. a DSGVO) in front of the
whole Health-Tracking area (weight, vet visits, vaccines, emergency
vet, feeding, Health Card): an un-pre-checked checkbox must be
confirmed before any of it is used, enforced server-side in
health.ts (not just the UI) via a new assertHealthConsent check on
every data-bearing endpoint.

Revoking consent (health.revokeConsent) deletes every health record
for that pet in one transaction and is available at any time from the
Health page. Pet gains healthConsentGivenAt/healthConsentRevokedAt
(nullable, additive — db push already applied against the shared
Supabase instance).

Extends the Datenschutzerklärung (Abschnitt 3) with the Art. 9 legal
basis and the revoke/auto-delete mechanism, per counsel's follow-up.
2026-09-04 16:10:14 +02:00
admin 122a5ba73b docs(legal): refine pet-data personal-data disclaimer per counsel wording
Narrow the Art. 4 No. 1 GDPR non-personal-data claim to data that
permits no inference about the owner as a natural person, and call
out the case where it can (e.g. pet photos alongside a profile
picture) as personal data after all.
2026-09-04 15:50:42 +02:00
admin ef2f67a353 docs(legal): address counsel review of Datenschutzerklärung
- clarify pet-only data (breed, weight, health records) is not
  personal data under Art. 4 No. 1 GDPR since GDPR protects only
  natural persons; still handled confidentially per policy
- switch Clerk/Cloudflare/Mux/Stripe from SCC framing to EU-U.S. DPF
  certification (Art. 45 adequacy decision), strengthen the residual
  SCC/Schrems-II fallback clause beyond TLS + access restrictions
- document 30-day retention and rationale for technical error reports
2026-09-04 15:40:20 +02:00
admin 922c2c1aec docs: correct script-src comment — strict-dynamic ignores the added host
Verified live that adding Clerk's frontend API host to script-src does
NOT resolve the CSP violation in modern browsers: with 'strict-dynamic'
present, CSP3 ignores host-based entries in that directive entirely
(Chrome's own violation message confirms this). The console noise is a
Clerk SDK-side loading quirk, not something fixable here without
dropping 'strict-dynamic'. Keeping the host entry only as the same
spec-mandated pre-CSP3 fallback the existing 'unsafe-inline' entry
already relies on, with the comment corrected to say so.
2026-09-01 20:58:07 +02:00
admin 99d9e5813e fix: allow Clerk's frontend API host in CSP script-src
Clerk's clerkMiddleware auto-adds its frontend API host to connect-src
but not script-src, so the initial (unversioned) clerk.browser.js/
ui.browser.js load was blocked by strict-dynamic before the 307 redirect
to the versioned URL — two CSP violations reported to /api/csp-report on
every page that renders Clerk UI, dragging the Best Practices Lighthouse
score down. Derives the host from the publishable key (same approach as
the existing Supabase/GlitchTip hostname helpers) instead of hardcoding it.
2026-09-01 20:23:24 +02:00
admin f56d1c7cb1 docs: document Clerk German localization, mark Capacitor mobile plan superseded
- README: note @clerk/localizations' deDE usage in the tech stack table
  and shipped-features list.
- ClerkThemeProvider: comment explaining why deDE is needed (Clerk's own
  UI defaults to English regardless of the app's next-intl locale).
- mobil.md: mark the Capacitor plan superseded by the React Native/Expo
  scaffold decided this session (see mobile/README.md).
2026-09-01 20:18:49 +02:00
admin 21e7f29acb feat: localize Clerk auth UI to German via @clerk/localizations
The sign-in/sign-up UI rendered in English despite the rest of the app
being German — @clerk/localizations ships an official deDE locale that
plugs directly into ClerkProvider's existing appearance config.
2026-09-01 19:53:55 +02:00
admin 1b83bb9665 docs: update README, add session handoff, fix deploy-script executable bit
README: document today's shipped work (story reactions/comments, per-pet
insights dashboard, DESIGN.md/PRODUCT.md design system, admin panel visual
pass) in "What's Shipped" and the admin panel section.

docker/rolling-deploy.sh and start.sh were tracked as 100644 (no executable
bit) since this repo is worked from Windows, which never records it — every
fresh git pull onto the Linux NAS made them non-executable again. Fixed via
git update-index --chmod=+x so this doesn't recur.
2026-08-25 19:24:52 +02:00
admin 641a58a1b5 feat(admin): add button legend to Posts page
The post-card action row (comments, hide/unhide, pin/unpin, AI-disclosure
correction, delete) had no explanation of what each icon does — add a help
popover next to the "Posts" heading listing icon + action name.
2026-08-25 19:17:39 +02:00
admin 06a25b4e28 feat(admin): link attention stat tiles to their queue pages
Open reports and Verifications pending summarized a number but gave no way to
act on it — link each tile straight to /reports and /verification, with
hover/focus states and a chevron affordance so it reads as navigation, not
just a number.
2026-08-25 19:14:43 +02:00
admin 2f7cacfc82 feat(admin): color-code dashboard Overview by category, unify depth system
The Overview card was a flat, uncategorized list of 10 stats with no visual
grouping. Split it into three labeled, color-identified groups so a moderator
can scan by kind of number instead of reading every label:

- Activity (emerald): owners, pets, posts, DAU, MAU
- Violations (rose): banned users, shadowbanned, blacklist entries — values
  only pick up the color when actually > 0, same "act on this" convention as
  the existing AttentionStat tiles
- Info (sky): active ads, verifications closed

Also switched the maintenance banner and AttentionStat tiles from border to
ring-1, matching the shared Card component's depth convention so the whole
dashboard uses one visual vocabulary instead of two.
2026-08-25 19:09:34 +02:00
admin f12f4edc69 feat(admin): fix admin shell theme tokens, declutter dashboard, add active-page nav highlight
Admin shell used hardcoded zinc-* classes instead of semantic design tokens and
a redundant "PawFeed Admin" kicker label. Dashboard was a wall of 12 identically
weighted stat cards with no hierarchy. Sidebar/mobile nav gave no indication of
the current page.

- layout.tsx/AdminMobileNav.tsx/GranularityToggle.tsx/TimeSeriesChart.tsx: replace
  zinc-* with bg-background/text-foreground/border-border etc., force dark via
  the `dark` class so the admin surface stays permanently dark regardless of
  site-wide theme toggle
- New AdminSidebarNav.tsx: highlights the current page (desktop sidebar)
- AdminMobileNav.tsx: same active-state logic for the mobile drawer, topbar
  shows the current page label instead of a static title
- page.tsx: replace the 12-card stat grid with 2 AttentionStat tiles (reports,
  pending verifications — color means "act on this") plus a flat Overview list,
  and convert the 5 chart containers to the shared Card component
2026-08-25 18:52:08 +02:00
admin 2cb54d4ed4 feat(design): rebuild landing page, header, and legal pages against new DESIGN.md
Introduces PRODUCT.md/DESIGN.md (Impeccable skill) capturing PawFeed's
existing brand identity ("The Spotlight Porch") as durable reference, then
applies it:

- Landing hero: restrained "spotlight" glow instead of a full orange
  gradient panel, tagline as the actual headline with a marigold accent on
  "Stars"/"stars", real PawPrint mark fixed (was a mismatched hand-drawn
  shape, also fixed a viewBox overflow clipping bug).
- Features section: one dominant mechanism (pet-as-identity) plus a quiet
  supporting list, replacing the four-identical-cards grid craft-floor
  refuses.
- Header: dropped the generic glass-blur sticky nav for a flat header with
  a soft marigold gradient hairline; CTA button now matches DESIGN.md
  (rounded-lg, no shadow, same orange as the hero CTA); logo gets a
  paw-spring hover as a small on-brand moment; new active-page indicator
  (LandingNavLinks) under the current nav link.
- Legal pages (Impressum/Datenschutz/Nutzungsbedingungen): replaced the
  stacked numbered-card-per-section layout with a flowing typographic
  document (hairline dividers, no boxes, no arbitrary section-number
  badges) via the shared LegalLayout/LegalSection components.
- Nutzungsbedingungen: moved Sponsoring earlier (now 3a, right after
  Nutzerinhalte & Urheberrecht) while keeping Salvatorische Klausel/Kontakt
  last; existing section numbers left untouched to avoid breaking the
  "gemäß Abschnitt 5" cross-reference in Haftungsausschluss.
2026-08-25 18:22:58 +02:00
admin 6e9e08be70 feat(insights): make spotlight post/story cards clickable
Top-post and top-story cards in the pet insights dashboard now open the
real post (PostDetailDialog, same fetch-by-id pattern as the notifications
page) or story (StoryViewer, new initialStoryId prop to jump straight to
the right story instead of always starting at index 0).
2026-08-24 18:57:33 +02:00
admin 45448573ea feat(insights): add owner-facing post/story analytics (Gitea #30)
New insights router aggregates the reactionCount/commentCount counters
(Post pre-existing, Story added in #29) into a small per-pet dashboard —
total paws/comments received and which post/story is resonating most.
Reachable from the owner's own pet profile ("Meine Tiere"), owner-only.
2026-08-24 18:39:03 +02:00
admin 05c9abfb7a feat(stories): add paw reactions and comments (Gitea #29)
Story reactions/comments mirror the existing Post/Ad engagement models
(StoryReaction/StoryComment tables, denormalized counters on Story) with
a comment overlay rendered on top of the still-playing story rather than
pausing it. No notification wiring yet, matching the Advertisement
engagement model's precedent.
2026-08-24 18:28:19 +02:00
admin 59cb72b57e docs: add session handoff for admin mobile fix, breed taxonomy, Gitea #33 2026-08-23 17:16:05 +02:00
admin 75377c4711 fix(follows): fix 404 on followers/following pages, add visibility setting
pets.byId is owner-only (throws FORBIDDEN for pets you don't own), but
followers/page.tsx and following/page.tsx used it just to grab the
pet's name for the heading/empty-state — any visitor viewing another
pet's followers or following list got a 404 (Gitea #33). Swapped to
pets.getProfile, the same public-safe procedure the actual profile
page already uses.

Also adds the requested privacy control: Pet.followerVisibility
(EVERYONE/FOLLOWERS_ONLY/NOBODY, default EVERYONE) gates
follows.listFollowers/listFollowing via a new assertCanViewFollowerLists
helper — FOLLOWERS_ONLY checks whether any pet the caller owns follows
the target pet; the owner can always see their own. Both pages now
render a "private" message instead of erroring when blocked. Editable
from the pet edit page's Privacy section, next to the existing DM
policy control.
2026-08-23 17:10:06 +02:00
admin b0b83703cd feat(taxonomy): expand dog/cat breeds to full FCI/FIFe nomenclature
Dog breeds: added all 340 remaining FCI-recognized breeds (fetched from
fci.be's nomenclature, 2026-08-23) not already in the existing 20-entry
list, bringing the total to 360. 173 of the 340 additions get a German
BreedTranslation using standard German cynology naming; the rest keep
the same name in both locales (correct for many FCI breeds, which
German-language sources don't translate either), falling back via
pickLocalizedName as designed.

Cat breeds: added all 39 remaining FIFe-recognized breeds (fetched from
fifeweb.org/cats/breeds/, 2026-08-23), bringing the total to 54. 21 get
a German translation.

Existing entries were left untouched (upsert is keyed on
speciesId+name) so no Pet.breedId reference breaks. Seed already run
against the shared dev/prod DB (idempotent, additive only) — verified
360/54 breed counts and 193/36 DE-translated counts post-run.
2026-08-23 16:35:46 +02:00
admin 8b74ca5763 fix(admin): make users page responsive on mobile
Search input (w-64) + two status/role selects (w-36) sat in one
unwrappable row, and each user row's shrink-0 action-button cluster
(up to 6 buttons) never yielded width to the info block — both
squeezed everything together below md:. Filter bar now stacks
(search full-width, filters side by side below it), and user rows
stack info above actions on mobile, row layout from sm: up.
2026-08-23 16:05:50 +02:00
admin f7049569e1 fix(admin): make admin panel layout responsive on mobile
The permanent 224px sidebar in the admin layout had no responsive
handling at all, leaving almost no width for content on a phone
(Gitea #10). Sidebar is now hidden below md: and replaced by a
topbar + slide-in Sheet drawer (AdminMobileNav) with the same nav
links; content padding and the outer flex direction adapt per
breakpoint.
2026-08-23 16:00:31 +02:00
admin 707b0b6797 docs: add session handoff for security review + full server sync 2026-08-23 15:31:56 +02:00