Markdown Converter
Agent skill for markdown-converter
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Sign in to like and favorite skills
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
HappyGotchaDays.com - A Progressive Web App for pet owners to celebrate and share their dogs' and cats' adoption anniversaries ("gotcha days"). Built on Cloudflare Workers edge platform.
Current State: Fully deployed and operational at https://happygotchadays.bill-burkey.workers.dev
Critical Context: This platform is exclusively for pet (dog/cat) adoption celebrations. The term "gotcha day" is controversial in child adoption contexts. Never conflate pet and human adoption.
/api/* or static files)Frontend assets are embedded as JavaScript strings and served via the Worker itself (no separate static hosting). See
src/middleware/static.js and src/frontend/*.
All tables use
TEXT for IDs (UUIDs) and INTEGER for timestamps (Unix epoch). Key relationships:
# Local development npm run dev # Start local Worker (localhost:8787) curl http://localhost:8787/health # Quick health check # Database operations npm run db:migrate:local # Apply migrations locally npm run db:migrate # Apply migrations to remote D1 wrangler d1 execute gotchadays-db --local --command="SELECT * FROM users LIMIT 5" # Query local DB wrangler d1 execute gotchadays-db --remote --command="SELECT * FROM users LIMIT 5" # Query remote DB # Testing npm test # Run all tests with Vitest npm test -- tests/unit/auth.test.js # Run specific test file npm run test:coverage # Run tests with coverage # Deployment npm run deploy # Deploy to production npm run deploy:preview # Deploy to preview environment # Secrets and configuration wrangler secret list # List configured secrets wrangler secret put JWT_SECRET # Set JWT_SECRET (prompted for value) wrangler kv:namespace list # List KV namespaces wrangler r2 bucket list # List R2 buckets
src/index.js - Main Worker, sets up Hono app with all routessrc/routes/auth.js - Register, login, logout, verifysrc/routes/pets.js - Pet profile CRUDsrc/routes/photos.js - Photo upload/download via R2src/routes/social.js - Posts, likes, comments, followssrc/routes/search.js - Search pets/users, discover, upcoming gotcha dayssrc/routes/reminders.js - Gotcha day reminder management (email notifications)src/utils/jwt.js - JWT signing/verification using Web Crypto APIsrc/utils/password.js - Password hashing with SHA-256src/utils/id.js - UUID generation and timestampssrc/middleware/auth.js - JWT authentication middleware
authMiddleware - Requires valid JWT, attaches user to context as c.get('user')optionalAuth - Checks for JWT but doesn't require it (for public/private content)src/middleware/static.js - Serves frontend from embedded stringssrc/ai/image-analysis.js - Breed detection, descriptions, moderation, taggingsrc/ai/content-generation.js - Story prompts, celebration messages, hashtagssrc/frontend/index.html.js - Main HTML structuresrc/frontend/styles/main.css.js - Complete CSS including modalssrc/frontend/scripts/app.js.js - Client-side JavaScriptsrc/frontend/manifest.json.js - PWA manifestsrc/frontend/sw.js.js - Service WorkerAccessed via
c.env in Hono context:
DB - D1 database (gotchadays-db)PHOTOS - R2 bucket (gotchadays-photos)SESSIONS - KV namespace for user sessionsCACHE - KV namespace for general cachingAI - Workers AI bindingJWT_SECRET - Secret for signing tokensANALYTICS - Analytics Engine (optional)All route files export a Hono router instance:
import { Hono } from 'hono'; export const myRoutes = new Hono(); myRoutes.get('/endpoint', async (c) => { /* handler */ });
Register in
src/index.js with: app.route('/api/prefix', myRoutes)
Routes using
authMiddleware require JWT and attach user to context:
import { authMiddleware } from '../middleware/auth.js'; myRoutes.get('/protected', authMiddleware, async (c) => { const user = c.get('user'); // { id: string, email: string } // ... });
Use
optionalAuth for endpoints that work for both authenticated and guest users.
All tables use
TEXT for IDs and INTEGER for timestamps. D1 uses prepared statements:
// Single result const user = await c.env.DB.prepare( 'SELECT * FROM users WHERE id = ?' ).bind(userId).first(); // Multiple results const pets = await c.env.DB.prepare( 'SELECT * FROM pets WHERE user_id = ?' ).bind(userId).all(); // Insert/Update/Delete const result = await c.env.DB.prepare( 'INSERT INTO pets (id, user_id, name, species, gotcha_date, created_at) VALUES (?, ?, ?, ?, ?, ?)' ).bind(id, userId, name, species, gotchaDate, timestamp).run();
// Upload with metadata await c.env.PHOTOS.put(key, fileStream, { httpMetadata: { contentType: 'image/jpeg' } }); // Retrieve const object = await c.env.PHOTOS.get(key); const arrayBuffer = await object.arrayBuffer(); // Delete await c.env.PHOTOS.delete(key);
// Image classification const result = await c.env.AI.run('@cf/microsoft/resnet-50', { image: arrayBuffer }); // Vision model const result = await c.env.AI.run('@cf/llava-hf/llava-1.5-7b-hf', { image: arrayBuffer, prompt: "Describe this pet" }); // Text generation const result = await c.env.AI.run('@cf/meta/llama-3.1-8b-instruct', { messages: [{ role: "user", content: "Generate a story..." }] });
The frontend is not separate files - it's embedded as exported strings in
.js files. When editing frontend:
src/frontend/*.js filesModals are dynamically created by injecting HTML into
#modalContainer. Close by clicking backdrop or calling closeModal(). Requires proper CSS (already added).
When adding new endpoints:
src/routes/ (or create new route file)src/index.js: app.route('/api/prefix', newRoutes)migrations/npm run db:migrate:local to apply locallynpm run devnpm run deploy to push changes (frontend is bundled with Worker)If frontend calls an API endpoint that doesn't exist (like
/api/auth/verify was initially), add it to the appropriate route file and redeploy.
src/index.jsnpm run deploy to see changesnpm run db:migratewrangler.toml match codeJWT_SECRET is set: wrangler secret listAuthorization: Bearer <token> header@cf/microsoft/resnet-50 - Image classification, breed detection@cf/llava-hf/llava-1.5-7b-hf - Vision model for descriptions and moderation@cf/meta/llama-3.1-8b-instruct - Text generation for stories, prompts, hashtagsLive URL: https://happygotchadays.bill-burkey.workers.dev GitHub: https://github.com/abandini/happygotchadays Cloudflare Account: [email protected] Worker Name:
happygotchadays
Workflow at
.github/workflows/deploy.yml auto-deploys on push to main (requires CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets).
tests/unit/npm test -- tests/unit/auth.test.jsauth.test.js, reminders.test.jstests/integration/ and tests/e2e/BROWSER_TEST.md for full API workflow"type": "module" in package.json)camelCase for variables/functions, PascalCase for classesimport { Hono } from 'hono'; import { authMiddleware } from '../middleware/auth.js'; export const myRoutes = new Hono(); // GET endpoint with auth myRoutes.get('/resource', authMiddleware, async (c) => { const user = c.get('user'); // Handler logic return c.json({ data: result }); }); // POST endpoint myRoutes.post('/resource', authMiddleware, async (c) => { const body = await c.req.json(); // Handler logic return c.json({ success: true }, 201); });
Frontend files in
src/frontend/ are JavaScript modules that export template literal strings:
// src/frontend/example.html.js export const exampleHTML = ` <!DOCTYPE html> <html> <!-- HTML content --> </html> `;