From 070293498b25741d6717ce15053160e5c9801293 Mon Sep 17 00:00:00 2001 From: Mannu Date: Sun, 10 May 2026 15:16:45 +0530 Subject: [PATCH] Update CLAUDE.md with R2 storage learnings --- CLAUDE.md | 82 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 791d60c..440220f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,8 +7,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ```bash # Development pnpm dev # Start dev server at http://localhost:3000 -pnpm build # Production build -pnpm start # Start production server +pnpm build # Production build +pnpm start # Start production server # Database (drizzle) pnpm db:push # Push schema to database @@ -43,11 +43,12 @@ src/ │ ├── medical/ # Vaccination tracking │ ├── growth/ # Growth charts │ ├── memories/ # Photo gallery -│ ├── menu/ # Navigation menu +│ ├── menu/ # Navigation menu │ ├── onboarding/ # First-time setup -│ └── login/ # Magic link login -├── libs/ # Shared utilities (if any) -└── styles/ # Global styles +│ ├── settings/ # Settings with theme picker +│ └── login/ # Magic link login +├── ThemeProvider.tsx # Theme context (light/dark/system/time) +├── ThemeProvider drizzle/ # Database migrations docs/ # Design docs ``` @@ -66,15 +67,24 @@ docs/ # Design docs - **Logs:** Feed, sleep, diaper entries with timestamps - **Vaccinations:** IAP schedule tracking - **Growth:** Weight/height over time -- **Memories:** Photos with vision AI tags +- **Memories:** Photos with R2 storage ### Key Patterns +**ThemeProvider:** Wrap app in ThemeProvider from layout.tsx. Use `useTheme()` hook in components. + +```typescript +import { useTheme } from "./ThemeProvider"; +const { theme, toggle, setMode } = useTheme(); +// theme: "light" | "dark" +// mode: "light" | "dark" | "system" | "time" +``` + **Offline Queue:** Uses localStorage (`tia_offline_queue`) for failed API calls, retries when online. -**Chat Sessions:** Stored in localStorage (`tia_chat_sessions`) as array of sessions with messages. Shared between home page AI card and /ai page. +**Chat Sessions:** Stored in localStorage (`tia_chat_sessions`) - shared between home page AI card and /ai page. -**API Routes:** Return standard JSON `{ entries: [...] }` format for lists. +**API Routes:** Return standard JSON `{ success: true, items: [...] }` format for lists. **AI Integration:** @@ -82,17 +92,63 @@ docs/ # Design docs - Model: `minimax-2.7` - See `/docs/debugging.md` for troubleshooting +## R2 Storage (Cloudflare) + +### Setup + +1. **Create bucket** in Cloudflare Dashboard → R2 +2. **Create API token** with "Object Read & Write" permissions +3. **Enable Public Development URL** in bucket settings (gives pub-*.r2.dev URL) + +### API Endpoint Format + +The S3 API endpoint is: `https://.r2.cloudflarestorage.com` + +For your bucket named "tia": +- Account ID: `e71f22a2f8614fb3ba6d9b28a264d8ce` +- S3 Endpoint: `https://e71f22a2f8614fb3ba6d9b28a264d8ce.r2.cloudflarestorage.com` +- Public URL: `https://pub-37a76fd657c94d1dbc521a109c087a11.r2.dev` (no bucket name in path!) + +### Code Example + +```typescript +const client = new S3Client({ + region: "auto", + endpoint: `https://${accountId}.r2.cloudflarestorage.com`, + credentials: { accessKeyId, secretAccessKey }, +}); + +// List objects +const command = new ListObjectsV2Command({ Bucket: "tia" }); +const res = await client.send(command); + +// Get presigned upload URL +const command = new PutObjectCommand({ Bucket: "tia", Key: key, ContentType }); +const url = await getSignedUrl(client, command, { expiresIn: 3600 }); +``` + +### Key Learnings + +1. **S3 API endpoint** does NOT include bucket name: `https://...r2.cloudflarestorage.com` +2. **Public URL** does NOT include bucket path: `https://pub-...r2.dev` (NOT `/tia/...`) +3. **CORS** needs GET and PUT methods for uploads +4. ListObjects needs bucket name in command, not endpoint + ## Environment Variables Set in `.env.local` for development, or in Dokploy dashboard for production. -See `.env.example` for all required vars. Key ones: +Required: - `DATABASE_URL` - PostgreSQL connection - `AUTH_SECRET` - NextAuth secret -- `LITELLM_BASE_URL` - AI gateway URL -- `LITELLM_API_KEY` - AI API key - `R2_ACCOUNT_ID` - Cloudflare R2 account ID - `R2_ACCESS_KEY_ID` - R2 access key - `R2_SECRET_ACCESS_KEY` - R2 secret key -- `R2_BUCKET_NAME` - R2 bucket name +- `R2_BUCKET_NAME` - R2 bucket name (e.g., "tia") +- `R2_PUBLIC_URL` - Public R2 URL (e.g., `https://pub-...r2.dev`) + +Optional for AI: + +- `LITELLM_BASE_URL` - AI gateway URL +- `LITELLM_API_KEY` - AI API key \ No newline at end of file