admin and Claude Sonnet 4.6
08fd0dfb71
feat(04): Phase 4 — in-app notifications
...
Schema:
- Add NotificationType enum (FOLLOW, REACTION, COMMENT, MESSAGE)
- Add Notification model with recipientPet, actorPet, post, comment
relations; index on [recipientPetId, read, createdAt desc]
Backend:
- notifications router: list (cursor-paginated), unreadCount,
markRead, markAllRead
- follows.create: fire-and-forget FOLLOW notification to followee
- reactions.toggle: REACTION notification on create (skip self)
- comments.create: COMMENT notification with commentId (skip self)
All triggers use .catch(()=>{}) to never fail the main action
UI:
- NotificationBell component with orange badge, polls every 30s
- /notifications page: list with avatar, type icon, text, thumbnail,
read/unread dot; auto-marks all read on visit
- Sidebar: Notifications link activated with NotificationBell
- MobileNav: Bell replaces Search tab (Search still at /search)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:59:23 +02:00
admin and Claude Sonnet 4.6
7fafc6d17f
fix(StoryTray): align Add Story circle with PawRing items
...
PawRing containers are size+RING_PAD*2=72px tall while the Add Story
button was only 56px, causing vertical misalignment. Wrap the button
in a matching 72px container so all tray items share the same height.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:44:57 +02:00
admin and Claude Sonnet 4.6
4b2760a08d
fix(PawRing): center main pad ring at cy=50 so avatar sits inside it
...
mainCy=58 shifted the ring below the flex-centered avatar, causing the
image to appear above/half-inside the ring. Setting cy=50 aligns the
ring with the container center; toe beans (cy≈1-10) overflow upward via
SVG overflow:visible, which is the correct paw-print anatomy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:43:27 +02:00
admin and Claude Sonnet 4.6
a9886948b8
fix: empty feed + unclickable profile grid
...
- feed.getFeed: when Redis is unavailable, fall back to a direct
Postgres query (followed pets + own posts, cursor-based) instead of
returning an empty array — feed now works in dev without Upstash
- ProfileTabs: wrap grid thumbnails in <button> + open a bottom Sheet
with the full PostCard on tap; previously tapping a photo did nothing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:38:53 +02:00
admin and Claude Sonnet 4.6
5af2a40bb3
fix: resolve three runtime errors found in dev smoke test
...
- MultiImageUpload: move onKeysChange out of setImages updater into
useEffect to fix React "Cannot update a component while rendering"
warning; same fix applied to handleRemove
- feed.getFeed: wrap getFeedPage in try/catch so Redis failure
(Upstash not configured) returns empty feed instead of 500
- posts.create + reposts.create: wrap fanOutPost with .catch(() => {})
so Redis failure never rolls back an already-committed post
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:33:14 +02:00
admin and Claude Sonnet 4.6
01b4f18a97
fix: wrap useSearchParams in Suspense on reset-password page
...
Next.js static rendering requires useSearchParams() to be inside a
Suspense boundary. Splits page into ResetPasswordContent (inner) +
ResetPasswordPage (Suspense wrapper). Caught by npm run build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:21:07 +02:00
admin and Claude Sonnet 4.6
847ac97bde
feat(03-06): Hashtag search end-to-end — Phase 3 complete
...
- hashtag-helpers.ts: extractHashtags (regex+dedup) + saveHashtags (upsert)
- parse-caption.ts: parseCaption → CaptionSegment[] for client rendering
- search.byHashtag GREEN: hashtag.findUnique → postHashtag.findMany + pagination
- posts.create + reposts.create: extract+save hashtags after post creation
- /hashtag/[tag]: infinite scroll post grid + useInView sentinel
- /search Tags tab: byHashtag query wired, 3-col post grid
- PostCard: parseCaption replaces raw caption — hashtags are orange Link to /hashtag/[tag]
- STATE.md: Phase 3 complete, 3/7 phases done
Tests: 67 passing, 0 failing (5 todo), tsc clean
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:16:03 +02:00
admin and Claude Sonnet 4.6
59a3be27b0
feat(03-05): Explore + pet search — routers GREEN + pages + nav
...
- explore.listPets: publicProcedure, speciesId/breedId filter, cursor pagination
- search.pets: protectedProcedure, ILIKE name+breed OR, cursor pagination
- ExploreCard: avatar, breed badge, follower count, FollowButton
- /explore: species tabs + breed filter Select + infinite pet grid
- /search: debounced input, Pets tab with FollowButton rows, Tags stub
- Sidebar: Explore activated, Search added
- MobileNav: Explore activated, Notifications placeholder → Search
Tests: explore 3/3 GREEN, search.pets 2/2 GREEN; 65 total passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:09:24 +02:00
admin and Claude Sonnet 4.6
8507fe9489
feat(03-04): Paw-Back/Repost — reposts router GREEN + RepostCard + PawBackButton
...
- reposts.create: ownership + repost-of-repost guard + idempotency + fanOutPost
- reposts.delete: ownership + cascade via post.delete
- reposts.isReposted: compound-key lookup, returns boolean
- PawBackButton: optimistic toggle, orange when reposted, invalidates feed
- RepostCard: attribution header + original pet/images/caption, no action row
- PostCard: REPOST type dispatches to RepostCard; stub replaced with PawBackButton
- feed.ts + posts.ts: repost include added to all post hydration queries
- PostCardPost type: OriginalPostContent + repost field
Tests: 3/3 reposts GREEN, 60 total passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 12:01:58 +02:00
admin and Claude Sonnet 4.6
6fbb99e7c9
feat(03-02): Paw reactions GREEN — toggle/count router + PawButton on PostCard
...
- reactions.toggle: assertPetOwnership → findUnique(postId_petId) → create or delete, return {reacted}
- reactions.hasReacted, getCount implemented
- feed.ts + posts.byPetId: add _count{reactions,comments} to hydration include
- PawButton: optimistic toggle, filled/outline PawPrint icon, count badge
- PostCard: replace "0 likes/0 comments" placeholder with action row (PawButton + comment chip + Paw-Back stub)
- PostCardPost type: add optional _count field
- 4/4 reactions tests GREEN; 56 passing total (+3 from 53)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 11:43:31 +02:00
admin and Claude Sonnet 4.6
b71edfa758
docs: update README — Phase 3 in progress, plan 1/6 complete
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 11:37:04 +02:00
admin and Claude Sonnet 4.6
73666a3916
feat(03-01): Phase 3 schema foundation — Reaction/Comment/Repost/Hashtag models + router stubs RED
...
- Prisma: add Reaction, Comment, Repost, Hashtag, PostHashtag models; PostType.REPOST enum
- Back-relations on Post and Pet for all Phase 3 models (named to avoid ambiguous-relation errors)
- 5 tRPC router stubs: reactions, comments, reposts, explore, search — all registered in _app.ts
- Extend prisma-mock.ts with Phase 3 model mocks
- 5 test scaffold files: 14 failing RED + 3 FORBIDDEN passing; 53 Phase 2 tests untouched
- Phase 3 planning: CONTEXT, RESEARCH, UI-SPEC, VALIDATION, 6 PLANs, ROADMAP + STATE updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 11:31:48 +02:00
admin
273d412fb4
docs: add README with setup, architecture, progress and debugging notes
2026-06-13 10:25:30 +02:00
admin
3fa62d2ce0
feat(02-06): MilestoneForm + PostTypeSheet wiring + ProfileTabs + profile page — Phase 2 complete
2026-06-13 10:22:35 +02:00
admin
9b02d3dc8b
feat(02-06): milestone-meta map + MilestoneCard + PostCard MILESTONE routing — MILE-02
2026-06-13 10:21:49 +02:00
admin
554ca1deae
test(02-06): add milestones tests RED → implement milestonesRouter GREEN — MILE-01
2026-06-13 10:21:40 +02:00
admin
9a901e3485
feat(02-05): wire seams — PawRing in PostCard, StoryTray in feed, StoryForm in PostTypeSheet
2026-06-13 10:11:09 +02:00
admin
e30531f834
feat(02-05): storiesRouter GREEN + PawRing + StoryViewer + StoryTray + StoryForm
2026-06-13 10:08:23 +02:00
admin
99bff88545
test(02-05): add stories tests RED — STORY-01-03
2026-06-13 10:08:16 +02:00
admin
fa9b33ad7e
refactor(feed): use PrismaClient type directly in assertPetOwnership
2026-06-13 10:02:17 +02:00
admin and Claude Sonnet 4.6
f7b09902f3
docs(02-04): complete photo posts plan summary
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 12:50:55 +02:00
admin and Claude Sonnet 4.6
e4b619671f
feat(02-04): post creation flow — MultiImageUpload, PhotoPostForm, PostTypeSheet, + button nav
...
MultiImageUpload:
- Per-file: validate type(jpg/png/webp) + size(<10MB) with exact UI-SPEC error copy
- Rejects >10 total: "You can upload up to 10 photos per post."
- posts.getPresignedUrl → XHR PUT with exact Content-Type (Pitfall 4 prevention)
- Reorderable thumbnails with remove button and upload progress bar
PhotoPostForm:
- MultiImageUpload + caption Textarea (max 500, error "Caption must be 500 characters or fewer.")
- "Share Post" CTA (bg-orange-500) → posts.create({ petId: activePetId, imageKeys })
- onSuccess: invalidate feed query, close Dialog, router.push('/feed') (D-03)
- Toasts: "Post shared" / "Couldn't share your post. Please try again."
PostTypeSheet:
- Bottom Sheet titled "Create" with 3 options: Photo Post, Story, Milestone (D-01)
- Photo → full-screen Dialog with PhotoPostForm (D-02, no URL change)
- Story/Milestone: TODO(02-05)/TODO(02-06) seams with placeholder dialogs
Sidebar + MobileNav:
- + button opens PostTypeSheet (D-01)
- MobileNav center + button: was Link to /pets, now triggers PostTypeSheet
- Sidebar: New Post button added above owner identity
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 12:48:56 +02:00
admin and Claude Sonnet 4.6
15f51825d9
feat(02-04): full PostCard — carousel + caption clamp + options menu
...
- Header: Avatar (story ring seam TODO(02-05)), pet name, timestamp, MoreHorizontal
- Single image: object-cover max-h-[560px]; Carousel: Embla for 2–10 images
- Carousel index indicator top-right; dot indicators bg-muted/bg-foreground (NOT orange)
- Caption line-clamp-3 with more/less toggle (instant, no animation per UI-SPEC)
- Own post options: Edit caption (inline Textarea) + Delete post (AlertDialog)
- Other's post options: Report post (ReportSheet) + Block {name} (BlockDialog)
- updateCaption / delete wired to tRPC mutations with exact UI-SPEC copy
- activePetId === post.pet.id determines own-vs-other ownership
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 12:45:32 +02:00
admin and Claude Sonnet 4.6
75d1e80665
feat(02-04): implement postsRouter GREEN — PHOTO-01–04
...
- getPresignedUrl: scopes key to posts/{ownerId}/{petId}/, ownership check (T-02-30)
- create: ownership assertion + Post+PostImage nested write + fanOutPost (PHOTO-01)
- create: imageKeys.max(10) enforces carousel limit (PHOTO-02, T-02-32)
- imageKeys.startsWith('posts/') prevents path traversal (T-02-31)
- updateCaption: assertPostOwnership via post→pet→ownerId (PHOTO-03, T-02-34)
- delete: assertPostOwnership + prisma.post.delete, PostImages cascade (PHOTO-04)
- byPetId: cursor-paginated query with images+pet+milestone include
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 12:43:35 +02:00
admin and Claude Sonnet 4.6
5e71010e50
test(02-04): add failing tests for posts router RED
...
- PHOTO-01: create single photo inserts Post + PostImage + fans out
- PHOTO-02: carousel limit rejects >10 images (Zod already validates)
- PHOTO-03: updateCaption forbidden for non-owner → FORBIDDEN
- PHOTO-04: delete calls prisma.post.delete (PostImages cascade via schema)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 12:42:49 +02:00
admin
bdd676f19b
docs(02-02): complete follow/block/report plan summary
...
- SOCL-01/02/03 and SAFE-01/SAFE-02 all implemented and tested
- 21 new tests green (follows: 10, blocks: 7, reports: 7)
- tsc exits 0; vitest 36 passed
2026-06-07 12:39:47 +02:00
admin
7f969a7b33
docs(02-03): complete feed infrastructure plan summary
...
- FEED-01 implemented: Redis-backed infinite query + FeedList + EmptyFeed + PostCard placeholder
- /feed page created; home redirect (D-04); nav Home→/feed (D-05)
- TDD gate compliance: RED (9219d3a ) → GREEN (56f976e ) documented
2026-06-07 12:38:40 +02:00
admin
0428cf2a04
feat(02-02): social + safety UI — FollowButton, PetListItem, BlockDialog, ReportSheet, followers/following pages
...
- FollowButton: optimistic follow/unfollow, revert on error, AlertDialog unfollow confirm (SOCL-01/02)
- PetListItem: avatar + name + species badge + right-aligned FollowButton (SOCL-03)
- BlockDialog: AlertDialog with exact UI-SPEC copy, destructive Block CTA (SAFE-01)
- ReportSheet: 5 RadioGroup reasons, notes Textarea, destructive Submit CTA (SAFE-02)
- followers/page.tsx: RSC shell "{N} Followers" heading + FollowersList client (SOCL-03)
- following/page.tsx: RSC shell "Following {N}" heading + FollowingList client (SOCL-03)
- pets/[petId]/page.tsx: stats row (posts/followers/following) + ProfileActions (SOCL-03)
- ProfileActions: FollowButton + MoreHorizontal options menu + BlockDialog + ReportSheet
- Fix: test prisma cast to `as any` resolving TS2322 type errors (Rule 1 - Bug)
- tsc exits 0; vitest 36 passed
2026-06-07 12:37:45 +02:00
admin
e9b286b4df
feat(02-03): /feed page + home redirect + nav Home→/feed
...
- src/app/(app)/feed/page.tsx: RSC shell with StoryTray seam + FeedList, metadata "Home — PawFeed"
- src/app/page.tsx: redirect("/feed") per D-04 (home route → /feed after Phase 2)
- Sidebar.tsx: Home href "/" → "/feed"; active detection handles /feed and / (D-05)
- MobileNav.tsx: Home href "/" → "/feed"; active state updated for /feed (D-05)
- (app)/layout.tsx: unchanged — zero-pets redirect to /onboarding/pet preserved (D-06)
2026-06-07 12:37:04 +02:00
admin
fd7dd2d56b
feat(02-03): FeedList + SkeletonCard + EmptyFeed + PostCard placeholder
...
- FeedList: useInfiniteQuery + useInView sentinel, 3 skeleton loading, empty state, end-of-feed copy
- SkeletonCard: animate-pulse 80px header + image + 2 text lines per UI-SPEC
- EmptyFeed: "Your feed is empty" heading + Find Pets CTA to /explore (D-06)
- PostCard: minimal placeholder (header + single image + caption); marked TODO(02-04) for carousel
- feed.test.ts: any-cast for mock prisma (tsc clean on new code; 3 pre-existing errors unrelated)
2026-06-07 12:35:07 +02:00
admin
f85230a074
feat(02-02): implement blocksRouter + reportsRouter (GREEN)
...
- blocks.create: assertPetOwnership + self-block rejection + prisma.block.create (SAFE-01)
- blocks.list: assertPetOwnership + prisma.block.findMany scoped by blockerPetId (T-02-12)
- reports.create: assertPetOwnership + both-null target rejection + prisma.report.create (SAFE-02)
- ReportReason enum: SPAM, HARASSMENT, INAPPROPRIATE, MISINFORMATION, OTHER (T-02-13)
- Blocks authoritative in Postgres only; never Redis (RESEARCH anti-pattern avoided)
2026-06-07 12:33:42 +02:00
admin
65b30c7889
test(02-02): add failing tests for blocks + reports routers (RED)
...
- SAFE-01: blocks.create inserts row, self-block rejected, ownership assertion, list returns blockedPetIds
- SAFE-01: feed block filter helper test confirms excluded petIds pattern
- SAFE-02: reports.create with targetPostId/targetPetId, both-null rejection, ownership assertion, all 5 enum values
2026-06-07 12:32:52 +02:00
admin
7bdb2989ca
feat(02-02): implement followsRouter (GREEN)
...
- follows.create: assertPetOwnership + self-follow rejection + prisma.follow.create + backfillOnFollow
- follows.delete: assertPetOwnership + prisma.follow.delete by composite key
- follows.isFollowing: prisma.follow.findUnique → boolean
- follows.listFollowers: scoped by followeePetId, includes follower display fields
- follows.listFollowing: scoped by followerPetId, includes followee display fields
- All mutations use protectedProcedure; social graph is pet-to-pet never ownerId (SOCL-01/02/03)
2026-06-07 12:31:50 +02:00
admin
56f976e3c4
feat(02-03): implement feed.getFeed router with Redis + Prisma hydration
...
- assertPetOwnership enforces petId ownership (T-02-20)
- getFeedPage reads Redis sorted set with cursor pagination
- Block filter applied at Prisma hydration layer (T-02-21)
- Post order restored to Redis score order after Prisma findMany (Pitfall 7)
- FEED-01 tests green
2026-06-07 12:31:36 +02:00
admin
2e1cf45d7a
test(02-02): add failing tests for follows router (RED)
...
- SOCL-01: follow creates row, self-follow rejected, ownership assertion, backfillOnFollow called
- SOCL-02: unfollow removes row, ownership assertion
- isFollowing: returns true/false based on DB state
- SOCL-03: listFollowers scoped by petId, listFollowing scoped by petId
2026-06-07 12:31:13 +02:00
admin
9219d3a907
test(02-03): add failing tests for feed.getFeed FEED-01
...
- Empty feed: returns [] and null nextCursor for pet with no follows
- Cursor pagination: nextCursor passed through from getFeedPage
- Block filter: blocked pets excluded from hydration
- Ownership: throws FORBIDDEN when petId is not owned by requester
2026-06-07 12:31:03 +02:00
admin
fb76e7cd7b
docs(02-01): complete foundation scaffold plan summary
...
- SUMMARY.md for Phase 02 Plan 01 (Foundation Scaffold, Wave 0)
- 8 Prisma models pushed, 7 router stubs registered, 7 test scaffolds created
- 2 auto-fixed deviations documented (ZRANGE offset, vi import)
2026-06-07 12:28:42 +02:00
admin
4c8ca3ab2f
fix(02-01): add explicit vi import to 7 test scaffold files for TypeScript compatibility
...
vi.mock() is vitest-hoisted at runtime but TypeScript requires explicit import.
Adds: import { vi } from "vitest" to all 7 new test scaffolds.
npx tsc --noEmit now exits 0.
2026-06-07 12:27:22 +02:00
admin
c74fc0d750
feat(02-01): 7 test scaffolds + prisma-mock extension + react-intersection-observer + 7 shadcn components
...
- Extend src/__tests__/helpers/prisma-mock.ts with post, postImage, milestone, story, storyView, follow, block, report mocks
- Create 7 test scaffold files (21 it.todo stubs covering PHOTO-01..04, STORY-01..03, MILE-01, SOCL-01..03, FEED-01, SAFE-01..02)
- feed.test.ts mocks @/lib/redis — no real Upstash calls in tests
- Install react-intersection-observer ^10.0.3 (slopcheck [OK] per RESEARCH)
- Add shadcn components: carousel, sheet, alert-dialog, scroll-area, tabs, popover, radio-group
- All 7 test files load and run without import errors (21 todo, 0 failures)
2026-06-07 12:26:08 +02:00
admin
c435404b2d
feat(02-01): shared libs + 7 tRPC router stubs registered in _app.ts
...
- src/lib/redis.ts: @upstash/redis singleton (server-only)
- src/lib/feed-helpers.ts: feedKey, fanOutPost, backfillOnFollow, getFeedPage, trimFeed, FEED_RETENTION_MS
- src/lib/media-url.ts: getMediaUrl (mirrors getAvatarUrl signature, client-safe)
- src/lib/milestone-thresholds.ts: FOLLOWER_MILESTONE_THRESHOLDS constant (D-09, A3)
- Router stubs: posts, stories, milestones, follows, blocks, reports, feed (all NOT_IMPLEMENTED)
- All 9 routers registered in _app.ts (pets, media + 7 new)
- feed.getFeed input includes cursor: z.number().nullish() per Pitfall 6
- Rule 1 fix: @upstash/redis zrange requires {offset, count} not just count
- npx tsc --noEmit exits 0
2026-06-07 12:23:10 +02:00
admin
b2db6310fe
feat(02-01): add 8 Prisma models, 3 enums, Pet back-relations
...
- Append PostType, MilestoneType (16 values), ReportReason enums
- Add Post, PostImage, Milestone, Story, StoryView, Follow, Block, Report models
- Add Pet back-relations for all Phase 2 social graph relations
- Explicit named relations on all self-referential models (Follower/Followee, Blocker/Blocked, StoryViewer, Reporter)
- StoryView.storyId has NO onDelete cascade per D-08 (views survive story expiry)
- npx prisma validate + generate + db push all succeeded
2026-06-07 12:20:26 +02:00
admin
ff6b48e3aa
docs(02): create phase plan (6 plans)
2026-06-07 12:16:56 +02:00
admin
90240f46b3
docs(02): add validation strategy
2026-06-07 11:58:29 +02:00
admin and Claude Sonnet 4.6
cf669be3a7
docs(02): research phase 2 content core
...
Complete research for Phase 2 — Content Core covering Prisma 7 schema
design for all new models (Post, PostImage, Story, StoryView, Follow,
Block, Report, Milestone), Upstash Redis fan-out feed pattern with
sorted set cursor pagination, Supabase Storage extension for post
images, shadcn Carousel integration, tRPC v11 infinite query pattern,
and security threat model for content mutations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-07 11:49:05 +02:00
admin
476f1d3235
docs(state): record phase 2 context session
2026-06-06 12:17:45 +02:00
admin
6a5ecc3ebf
docs(02): capture phase context
2026-06-06 12:17:45 +02:00
admin and Claude Sonnet 4.6
ce25ca088c
docs(02): fix UI-SPEC blocking issues — copy, spacing, aria
...
- Report cancel: "Cancel" -> "Don't report"
- Block cancel: "Cancel" -> "Don't block"
- Story ring gap: 3px (non-multiple of 4) -> ring-1 ring-offset-1 (4px, standard Tailwind scale)
- Carousel dot gap: 6px (non-multiple of 4) -> gap-2 (8px)
- Removed both non-conformant values from spacing exceptions table
- Added aria-label="Close story" to story viewer close button spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-06 11:59:43 +02:00
admin and Claude Sonnet 4.6
0f7b00283f
docs(phase-2): UI design contract for Content Core
...
Adds 02-UI-SPEC.md covering photo posts, stories, milestone posts,
social graph, home feed, and safety (block/report) — extends Phase 1
contract without contradiction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-06 11:56:23 +02:00
admin
eeab28e8cb
chore: rename project from OnlyPets to PawFeed (domain: pawfeed.org)
2026-06-06 11:51:45 +02:00
admin
45c1410651
chore(01): phase 1 complete
2026-06-06 11:48:38 +02:00