Commit Graph
52 Commits
Author SHA1 Message Date
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
adminandClaude 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
adminandClaude 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
adminandClaude 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
admin 95e42f5474 fix(01-04): replace all R2/api-avatar URLs with Supabase Storage CDN via getAvatarUrl() 2026-06-06 11:38:37 +02:00
admin e3c279d6a4 feat(01-04): switch media storage from Cloudflare R2 to Supabase Storage 2026-06-06 11:32:17 +02:00
admin 1a735b9393 docs(01-04): complete media pipeline plan summary 2026-06-06 11:13:12 +02:00
admin 62b7cdaf1e test(01-04): implement 7 media upload unit tests covering security and validation
- Test 1: getPresignedUrl generates URL with correct contentType and avatars/-scoped key
- Test 2: getPresignedUrl rejects non-owner with FORBIDDEN (T-4-01)
- Test 3: getPresignedUrl rejects image/gif (Zod enum validation, T-4-02)
- Test 4: getPresignedUrl rejects 11MB file (T-4-06 fileSize limit)
- Test 5: confirmUpload writes avatarKey to DB with correct update call
- Test 6: confirmUpload rejects path traversal key (T-4-05)
- Bonus: confirmUpload rejects non-owner with FORBIDDEN (T-4-01)
- Mock getPresignedUploadUrl via vi.mock — no real R2 calls
2026-06-06 11:11:40 +02:00
admin fb8bb5c8fe feat(01-04): wire CDN avatar into profile, edit page, sidebar, and mobile nav
- pets/[petId]/page.tsx: replace /api/avatar stub with NEXT_PUBLIC_R2_PUBLIC_URL CDN URL
- pets/[petId]/edit/page.tsx: pass initialAvatarKey to PetForm so AvatarUpload shows current photo
- Sidebar.tsx: add avatarKey to Pet type; show AvatarImage from CDN for active pet and dropdown list
- MobileNav.tsx: same CDN avatar pattern for mobile pet switcher
- next.config.ts: add images.remotePatterns for R2 CDN hostname (T-4-04 safeguard)
2026-06-06 11:10:28 +02:00
admin 1bd1a89c68 feat(01-04): AvatarUpload five-state component + wire into PetForm
- Create AvatarUpload.tsx: idle/dragging/uploading/error/idle-with-avatar states
- XHR PUT to R2 presigned URL with progress tracking (Content-Type must match presignedUrl)
- Two-step upload: getPresignedUrl -> XHR PUT -> confirmUpload -> CDN URL display
- Client-side validation: size <= 10MB, type jpeg/png/webp
- Disabled state in create mode (no petId) with tooltip
- Drag and drop: dragOver/dragLeave/onDrop handlers; orange border in dragging state
- Wire AvatarUpload into PetForm replacing AvatarUploadZone stub
- Add initialAvatarKey prop and currentAvatarKey state to PetForm
- onUploadComplete invalidates React Query cache (pets.byId + pets.list)
2026-06-06 11:08:56 +02:00
admin 485877a541 feat(01-04): tRPC media router with getPresignedUrl and confirmUpload
- Create src/trpc/routers/media.ts with server-only import (T-4-03)
- getPresignedUrl: ownership assertion, contentType enum (jpeg/png/webp), fileSize <= 10MB, UUID-scoped R2 key
- confirmUpload: ownership assertion, key.startsWith('avatars/') validation (T-4-05)
- Register media: mediaRouter in _app.ts appRouter
- Fix pre-existing TS error in PetForm.tsx: setSelectedSpeciesId(val ?? '') (Rule 1 bug)
2026-06-06 11:07:09 +02:00
admin 3d0e2e6961 fix(01-03): pet card click navigates to profile page 2026-06-06 10:49:13 +02:00
admin d7eb00a5a3 feat(01-03): auto-capitalize first letter of pet name on input 2026-06-06 10:45:56 +02:00
admin a0fdc0b9c4 fix(01-03): resolve species/breed name directly from list in trigger — bypass Radix SelectValue bug 2026-06-06 10:42:22 +02:00
admin 9d51003ece fix(01-03): use empty string instead of undefined for Select value — prevents controlled/uncontrolled switch 2026-06-06 10:38:47 +02:00
admin c4588098ca fix(01-03): defer species/breed Select render until data loads — fixes CUID showing in trigger 2026-06-06 10:35:31 +02:00
admin 63ec6637b1 fix(01-01): add seed command to prisma.config.ts 2026-06-06 10:24:54 +02:00
admin b0cca2deb6 docs(01-03): complete pet profile CRUD plan summary
- SUMMARY.md with all task commits, deviations, known stubs
- Self-check: all 11 files found, all 5 commits verified
2026-06-06 10:23:03 +02:00
admin 8824391613 fix(01-03): fix tRPC caller context type in pet-profile tests
- Type CallerCtx explicitly to avoid union type inference error
- petsRouter.createCaller accepts Context | (() => Context); explicit type avoids TS error
2026-06-06 10:20:00 +02:00
admin f996459133 test(01-03): implement pet-profile unit tests (PET-01 through PET-05)
- PET-01: create stores pet with ownerId, validates name<=30, upserts owner FK
- PET-02: update FORBIDDEN for non-owner, succeeds for owner
- PET-03: delete by owner succeeds ({ success: true }); FORBIDDEN for non-owner
- PET-05: adoptionStory persists to DB; validates max 500 chars
- Ownership assertion: FORBIDDEN tested for both update and delete (T-3-01)
- All 11 tests passing; no real DB calls (mocked via createMockPrisma)
2026-06-06 10:18:52 +02:00
admin 95dfec7bdf feat(01-03): add pet profile pages (My Pets grid, profile view, edit, onboarding)
- My Pets: server-fetched list + PetGrid client island for active pet selection
- Pet profile view: avatar/name/species badge, "Managed by @owner" subordination
- Edit pet: PetForm in edit mode + delete confirmation dialog (UI-SPEC copy)
- Delete dialog: "Delete pet profile?", "Yes, delete", "Keep pet" per UI-SPEC
- Onboarding page: replaced stub with PetForm mode=create, redirects to /pets/[petId]
- Used buttonVariants for Link-as-button (base-nova lacks asChild)
2026-06-06 10:17:34 +02:00
admin 63d8c06b48 feat(01-03): add PetForm and PetCard components
- PetForm: create/edit mode, species/breed from DB (never hardcoded)
- Species selector wired to listSpecies tRPC query
- Breed selector wired to listBreeds, resets on species change
- Bio (maxLength=150) + adoption story (maxLength=500) with char counters
- Pet name maxLength=30 with Zod validation via react-hook-form
- AvatarUploadZone stub (Plan 04 wires upload; disabled in create mode)
- PetCard: avatar with active orange ring, species badge, hover shadow
2026-06-06 10:11:54 +02:00
admin 69553b103b feat(01-03): extend pets router (update/delete/listSpecies/listBreeds) + breed seed
- Add assertPetOwnership helper (T-3-01: ownership check before every mutation)
- Add pets.update with Zod limits (name<=30, bio<=150, adoptionStory<=500)
- Add pets.delete with ownership assertion
- Add pets.listSpecies (protectedProcedure — T-3-04 scraping prevention)
- Add pets.listBreeds filtered by speciesId
- Extend seed with 45 breeds: 20 dog, 15 cat, 10 bird (idempotent upserts)
- Install react-hook-form + @hookform/resolvers for PetForm (Task 2)
2026-06-06 10:07:04 +02:00
admin 5f781fc20e fix(01-02): rename src/middleware.ts to src/proxy.ts — Next.js 16 convention 2026-06-06 10:01:29 +02:00
admin 32226739b7 fix(01-02): move onboarding/pet outside (app) group — breaks redirect loop 2026-06-06 09:59:01 +02:00
admin d6fc3e5ccf fix(01-02): move middleware.ts to src/ — required when project uses src/ directory 2026-06-06 09:46:58 +02:00
admin 177403276b fix(01-02): update layout comment to reference middleware.ts 2026-06-06 09:43:00 +02:00
admin b71ac2f5d2 fix(01-02): rename proxy.ts to middleware.ts — Next.js only recognizes middleware.ts 2026-06-06 09:42:39 +02:00
admin 43faa35795 fix(01-01): use DIRECT_URL for Prisma CLI — PgBouncer pooler hangs on schema push 2026-06-06 09:34:29 +02:00
admin 091c2dc0e4 fix(01-01): load .env manually in prisma.config.ts — Prisma 7 env() unreliable on Windows 2026-06-06 09:29:39 +02:00
admin 1b5f1affe9 fix(01-01): move DB URL to schema.prisma datasource, simplify prisma.config.ts 2026-06-06 09:28:14 +02:00
admin 31f9279ffc fix(01-02): correct next.config.ts syntax error (module.exports inside object literal) 2026-06-06 09:13:48 +02:00
admin 105574d907 docs(01-02): complete auth screens and app shell plan 2026-06-06 09:04:34 +02:00
admin e7d300f9c2 feat(01-02): protected app shell with sidebar, mobile nav, onboarding redirect
- (app)/layout.tsx: server component with auth() check + pets.list + redirect to /onboarding/pet if no pets
- Sidebar.tsx: 240px desktop nav (lg:), pet switcher with active state, nav links with orange-500 active indicator
- MobileNav.tsx: fixed bottom bar (h-16, lg:hidden), pet switcher above tabs, orange-500 center post button
- onboarding/pet/page.tsx: stub with Plan 03 placeholder (replaces walking skeleton client form)
- Deviation: base-nova shadcn uses @base-ui/react/menu (no asChild support) — used onClick+useRouter
- Deviation: Clerk 7 UserButton no longer accepts afterSignOutUrl
2026-06-06 08:57:38 +02:00
admin 325eaa9a25 feat(01-02): auth layout and Clerk-rendered auth pages
- (auth)/layout.tsx: centered 448px container, items-center, bg-background
- sign-up/[[...sign-up]]/page.tsx: Clerk <SignUp> with orange-500 appearance, redirects to /onboarding/pet
- log-in/[[...sign-in]]/page.tsx: Clerk <SignIn> with orange-500 appearance, redirects to /pets
- forgot-password/page.tsx: two-step Clerk 7 reset flow (create identifier + resetPasswordEmailCode.sendCode)
- reset-password/page.tsx: Clerk 7 resetPasswordEmailCode.verifyCode + submitPassword + finalize
- verify-email/page.tsx: static server component + ResendEmailButton client island
- Deviation: Clerk 7 SignInFutureResource API used (no isLoaded/setActive/attemptFirstFactor)
2026-06-06 08:52:23 +02:00
admin e0214ea0f8 feat(01-01): wire Clerk proxy.ts, Prisma 7 schema + singleton, tRPC stack, R2 client, ActivePetContext
- Create proxy.ts at repo root with clerkMiddleware + createRouteMatcher (public allowlist: sign-up, log-in, forgot-password, reset-password, verify-email)
- Create prisma/schema.prisma: Owner, Species, Breed, Pet models with ownership index and FK constraints
- Create prisma.config.ts with Prisma 7 defineConfig (datasource url via env)
- Create src/lib/prisma.ts: Prisma 7 singleton using @prisma/adapter-pg for local dev, withAccelerate() for Prisma Accelerate on Vercel
- Create src/lib/r2.ts (server-only): S3Client + getPresignedUploadUrl with contentType enforcement and 300s expiry
- Create src/lib/auth.ts: getOwnerId() Clerk auth wrapper
- Create src/trpc/init.ts: createTRPCContext, router, publicProcedure, protectedProcedure (throws UNAUTHORIZED)
- Create src/trpc/routers/pets.ts: pets.create (upserts Owner, creates Pet with ownerId=ctx.userId), pets.list (scoped), pets.byId (ownership-asserted)
- Create src/trpc/routers/_app.ts: appRouter + AppRouter type export
- Create src/trpc/query-client.ts, server.ts (RSC caller), client.tsx (TRPCReactProvider + useTRPC)
- Create src/app/api/trpc/[trpc]/route.ts: tRPC fetch handler (GET + POST)
- Create src/context/ActivePetContext.tsx + src/hooks/useActivePet.ts: localStorage-backed active pet context
- Create prisma/seed.ts: seeds Dog/Cat/Bird species idempotently via upsert
- Update src/app/layout.tsx: wrap children in ClerkProvider (orange primary), TRPCReactProvider, ActivePetProvider, Toaster
- Install @prisma/adapter-pg + pg for Prisma 7 local dev (Rule 2: required for Prisma 7 engine compatibility)
- [Rule 1 - Bug] Prisma 7 no longer supports url/directUrl in schema.prisma; moved to prisma.config.ts with defineConfig
2026-06-05 19:18:16 +02:00
admin dbc074e9ee chore(01-01): scaffold Next.js 16 + install full stack + Vitest test scaffold
- Create-next-app Next.js 16.2.7 with TypeScript 6.0.3, React 19, Tailwind v4, Turbopack
- Install all pinned runtime deps: Clerk 7.4.3, tRPC 11.17.0, Prisma 7.8.0, Zod 4.4.3, AWS SDK 3.1062.0, Sonner 2.0.7, Upstash Redis 1.38.0
- Configure Tailwind v4 (postcss.config.mjs uses @tailwindcss/postcss; globals.css uses @import "tailwindcss")
- Initialize shadcn/ui with default preset; add all Phase 1 components (button, input, form, label, textarea, select, avatar, card, dialog, dropdown-menu, sonner, progress, separator, badge, skeleton)
- Set orange-500 design system: --primary: oklch(0.7024 0.1967 41.45); --background: oklch(0.9882 0 0)
- Load Inter via next/font/google in root layout
- Create vitest.config.ts with jsdom environment and @ path alias
- Create Wave 0 test scaffolds (22 it.todo tests): auth, pet-profile, media-upload + prisma-mock helper
- Create .env.example listing all required service env vars
2026-06-05 19:10:46 +02:00
admin d3fe4982ff docs(01): create phase plan 2026-06-05 17:29:13 +02:00
admin be93b6c56d docs(01): add validation strategy 2026-06-05 17:11:23 +02:00
adminandClaude Sonnet 4.6 dbc002c492 docs(01): fix 3 blocking UI-SPEC issues from checker
- Copywriting: rename delete pet cancel button from "Cancel" to "Keep pet"
- Typography: reduce to exactly 4 sizes (12/14/16/20px) and 2 weights (400/600)
- Visuals: add focal point declaration per screen in Screen Inventory

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:49:44 +02:00
adminandClaude Sonnet 4.6 4608ff19f0 docs(01): UI design contract for Phase 1 Foundation
Locks spacing, typography, color, copywriting, and design system decisions
for the owner auth and pet profile screens before execution begins.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:46:47 +02:00
admin 1e7d511204 docs: create roadmap (7 phases) 2026-06-05 16:38:59 +02:00
admin 72214f2a10 docs: define v1 requirements 2026-06-05 16:28:43 +02:00
adminandClaude Sonnet 4.6 6e2f6f59d7 docs: complete project research for OnlyPets
Research files: STACK.md, FEATURES.md, ARCHITECTURE.md, PITFALLS.md, SUMMARY.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:24:38 +02:00