# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **QR Master** is a production-ready SaaS application for creating and managing QR codes with advanced analytics, Stripe payment integration, and multi-tier subscription plans (FREE, PRO, BUSINESS). ## Tech Stack - **Frontend**: Next.js 14 (App Router), React 18, TypeScript, Tailwind CSS, Framer Motion - **Backend**: Next.js API Routes, Prisma ORM, PostgreSQL - **Authentication**: NextAuth.js v4 (Credentials + Google OAuth) - **Payments**: Stripe (subscriptions, webhooks) - **Cache**: Redis (optional) - **Analytics**: PostHog (optional), QR scan tracking with IP hashing - **QR Generation**: qrcode, qr-code-styling libraries - **Bulk Operations**: Papa Parse (CSV), ExcelJS, JSZip - **Storage**: AWS S3 (via @aws-sdk) ## Quick Development Commands ```bash # Setup npm install npm run docker:dev # Start PostgreSQL & Redis in Docker npx prisma migrate dev # Run migrations npm run db:seed # Seed demo data # Development npm run dev # Start dev server (port 3050) npm run lint # Run ESLint # Database npm run db:migrate # Run pending migrations (dev mode) npm run db:deploy # Apply migrations (production) npm run db:studio # Open Prisma Studio UI npx prisma migrate reset # Reset database (drops, recreates, seeds) # Docker npm run docker:prod # Start full production stack npm run docker:dev:stop # Stop dev services npm run docker:logs # View logs npm run docker:db # PostgreSQL CLI npm run docker:redis # Redis CLI npm run docker:backup # Backup database to SQL file # Build & Deploy npm run build # Production build npm run start # Start production server ``` ## Project Structure ``` src/ ├── app/ │ └── (main)/ │ ├── (app)/ # Authenticated app pages (dashboard, bulk-creation, settings) │ ├── (auth)/ # Auth pages (login, signup, forgot-password) │ ├── (marketing)/ # Public pages & marketing tools │ │ └── tools/ # QR code type-specific generators (20+ tools) │ └── api/ # API routes organized by domain │ ├── auth/ # Authentication (signin, signup, OAuth, password reset) │ ├── qrs/ # QR code CRUD (GET, POST, PATCH, DELETE) │ ├── analytics/ # Analytics summary endpoint │ ├── stripe/ # Payment webhooks & session management │ ├── user/ # User profile, plan, stats, password │ ├── newsletter/ # Subscription management │ └── [other]/ # admin, feedback, leads, bulk, etc. ├── components/ │ ├── ui/ # Reusable UI primitives (Card, Dialog, Input, etc.) │ ├── generator/ # QR code generator components │ ├── analytics/ # Charts, maps, data visualization │ ├── dashboard/ # Dashboard-specific components │ ├── settings/ # Settings & account components │ └── SessionProvider.tsx # NextAuth session provider ├── lib/ │ ├── auth.ts # NextAuth configuration │ ├── db.ts # Prisma client │ ├── stripe.ts # Stripe utilities │ ├── email.ts # Email sending (Resend) │ ├── qr.ts # QR code generation utilities │ ├── geo.ts # Geolocation utilities │ ├── hash.ts # IP hashing (privacy) │ ├── csrf.ts # CSRF token generation/validation │ ├── rateLimit.ts # Rate limiting utilities │ ├── schema.ts # Zod validation schemas │ ├── validationSchemas.ts # Additional validation │ └── cookieConfig.ts # Cookie configuration ├── hooks/ │ ├── useCsrf.ts # CSRF token hook │ └── useTranslation.ts # i18n hook └── types/ └── analytics.ts # Analytics type definitions ``` ## Database Architecture **Key Models** (see `prisma/schema.prisma`): - **User**: User accounts with Stripe subscription fields - **QRCode**: QR code records (static/dynamic, multiple content types) - **QRScan**: Analytics data (ts, ipHash, device, os, country, UTM params) - **Account/Session**: NextAuth authentication tables - **Integration**: Third-party integrations - **NewsletterSubscription**: Email subscribers - **Lead**: Lead generation data **QR Code Types**: URL, VCARD, GEO, PHONE, SMS, TEXT, WHATSAPP, PDF, APP, COUPON, FEEDBACK ## API Architecture ### Authentication Flow - Credentials-based login/signup via `/api/auth/signup` and `/api/auth/simple-login` - Google OAuth via `/api/auth/google` - NextAuth.js session management at `/api/auth/[...nextauth]` - Password reset: `/api/auth/forgot-password` + `/api/auth/reset-password` ### QR Code Operations - **CRUD**: `GET/POST /api/qrs`, `GET/PATCH/DELETE /api/qrs/[id]` - **Static Generation**: `POST /api/qrs/static` - **Bulk Operations**: `POST /api/bulk/*` for CSV/Excel import - **Public Redirect**: `GET /r/[slug]` (redirect + analytics tracking) ### Payments - Stripe webhooks: `POST /api/stripe/webhook` - Checkout session: `POST /api/stripe/checkout` or `/api/stripe/create-checkout-session` - Customer portal: `POST /api/stripe/portal` - Subscription sync: `POST /api/stripe/sync-subscription` - Cancellation: `POST /api/stripe/cancel-subscription` ### Analytics - Summary endpoint: `GET /api/analytics/summary?qrId=` - Scan tracking with hashed IP (GDPR-compliant) ## Key Implementation Patterns ### Authentication & Authorization - NextAuth.js v4 with Prisma adapter - Sessions stored in database - CSRF protection on all mutations (check `useCsrf` hook) - Password hashing with bcryptjs ### API Security - Rate limiting on sensitive endpoints (auth, payments) - CSRF tokens validated on POST/PATCH/DELETE - IP hashing for privacy (IP_SALT environment variable) - DNT header respected for analytics ### Database Operations - Prisma ORM for all database access - Migrations stored in `prisma/migrations/` - Seed script for demo data in `prisma/seed.ts` - Database indexes on frequently queried fields (userId, createdAt, etc.) ### QR Code Generation - `qrcode` library for basic generation - `qr-code-styling` for advanced customization - `qrcode.react` for inline React components - Canvas/SVG export via `html-to-image`, `jspdf`, `jszip` ### State & Validation - Zod schemas in `/lib/schema.ts` for runtime validation - TypeScript strict mode enabled - Prisma provides type safety at database layer ## Environment Variables **Required**: - `DATABASE_URL` - PostgreSQL connection string - `NEXTAUTH_SECRET` - JWT encryption secret - `NEXTAUTH_URL` - Application URL (default: `http://localhost:3050`) - `IP_SALT` - Salt for IP hashing **Optional but Important**: - `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` - `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` - OAuth - `REDIS_URL` - Redis connection - `NEXT_PUBLIC_POSTHOG_KEY`, `NEXT_PUBLIC_POSTHOG_HOST` - Analytics - `NEXT_PUBLIC_INDEXABLE` - Set to `true` for production (enables search engine indexing) **Generate Secrets**: ```bash openssl rand -base64 32 # NEXTAUTH_SECRET and IP_SALT ``` ## Common Tasks ### Adding a New QR Code Type 1. Add type to `ContentType` enum in `prisma/schema.prisma` 2. Create generator component in `src/components/generator/` or `src/app/(main)/(marketing)/tools/` 3. Add validation schema in `src/lib/schema.ts` 4. Create API endpoint if needed in `src/app/(main)/api/qrs/` ### Creating a New Marketing Tool Page 1. Create page at `src/app/(main)/(marketing)/tools/[tool-name]/page.tsx` 2. Create generator component in same directory 3. Add SEO metadata in page component 4. Tool should be static (no database) or use public API endpoints ### Adding a New API Endpoint 1. Create route file in appropriate directory under `src/app/(main)/api/` 2. Add Zod validation schema in `src/lib/schema.ts` 3. Check authentication with `getServerSession()` if needed 4. Implement rate limiting for sensitive operations 5. Return typed responses with proper status codes ### Database Schema Changes 1. Update `prisma/schema.prisma` 2. Run `npx prisma migrate dev --name ` 3. This creates migration file and updates Prisma client 4. Test with `npm run db:seed` if demo data affected ## Testing & Debugging - Demo account (after seed): email: `demo@qrmaster.com`, password: `demo123` - Prisma Studio: `npm run db:studio` - visual database browser - API testing: Check `/src/app/(main)/api/` for examples - Frontend: Pages hot-reload on changes during `npm run dev` ## Performance Considerations - PostgreSQL indexes on `QRCode(userId, createdAt)` and `QRScan(qrId, ts)` - Redis optional but recommended for caching analytics - Static export for marketing pages when possible - Image optimization enabled in `next.config.mjs` - Prisma connection pooling recommended for production ## Database Change Policy **IMPORTANT: No Prisma migrations.** All database schema changes (new columns, new enum values, new tables) must be applied via raw SQL commands directly against the running PostgreSQL instance. Workflow for schema changes: 1. Write the raw SQL (e.g. `ALTER TABLE`, `ALTER TYPE ... ADD VALUE`) 2. Run via Docker: `npm run docker:db` then execute SQL, or use `docker-compose exec db psql -U postgres -d qrmaster -c "..."` 3. Update `prisma/schema.prisma` to match (so Prisma client types stay in sync) 4. Run `npx prisma generate` to regenerate the client (no `migrate`) Example — adding an enum value: ```sql ALTER TYPE "ContentType" ADD VALUE 'BARCODE'; ``` ## Common Pitfalls 1. **Database Connection**: If "Can't reach database server", ensure Docker is running (`npm run docker:dev`) 2. **Prisma Out of Sync**: Run `npx prisma generate` if TypeScript errors appear 3. **Migration Conflicts**: Use `npx prisma migrate reset` to start fresh 4. **Port 3050 in Use**: Change port in `package.json` dev script or kill process 5. **Build Failures**: Check `NODE_OPTIONS='--max-old-space-size=4096'` in build script - set higher if needed ## SEO & Content - Schema.org structured data implemented for products, organizations, FAQs - Breadcrumb navigation for UX/SEO - Meta tags configured per page - Open Graph images at `/api/og` - Sitemap generation via next-sitemap - Google Indexing API + IndexNow submission scripts available ## AI SEO / AEO Tracking (AI Answer Engine Visibility) Ongoing effort to increase QR Master's presence in AI-generated answers (ChatGPT, Perplexity, AI Overviews, etc.) for QR-code-generator-related queries. Update this section after each audit/build cycle so future sessions build on prior findings instead of re-deriving them. ### Baseline audit (2026-07-22) Query-fanout data (what an AI model searches for while answering a prompt) showed QR Master already being cited in AI-generated answers for 3 of 9 tested query themes: "best QR code generator for marketing campaigns", "QR code generator with analytics and tracking", and "affordable dynamic QR code generator for small business" — positioned as the budget/SMB pick alongside Uniqode, QR TIGER, Bitly, Flowcode, and Hovercode. No QR Master citation appeared for: "best dynamic QR code generator 2026", "best QR code generator for businesses", "best QR code generator for agencies", "alternatives to QR TIGER", "QR code generator with unlimited scans", "free dynamic QR code generator unlimited scans". Existing on-site AEO infrastructure found during the audit: - `public/llms.txt` present — lists core pages and cornerstone guides for AI retrieval - `/alternatives/` pages exist only for: qr-code-generator.com, Flowcode, Beaconstac, Bitly - `/vs/` pages exist only for: Beaconstac - `/compare/[slug]` dynamic comparison route exists (e.g. `free-vs-paid-qr-code-generator`) - Blog cornerstones: best-qr-code-generator-2026, free-vs-paid-qr-generator, qr-code-tracking-guide-2025, dynamic-vs-static-qr-codes, qr-code-small-business, qr-code-scan-statistics-2026, etc. Pattern observed: QR Master gets cited by AI models only where first-party comparison/guide content already exists on the domain. The fanout queries repeatedly run `site:` searches against Uniqode, QR TIGER (qrcode-tiger.com), Hovercode, Scanova, and QRCodeChimp — none of which currently have a matching QR Master alternatives/vs page. ### Priority backlog (from this audit) 1. Build `/alternatives/uniqode`, `/alternatives/qr-code-tiger`, `/alternatives/hovercode` (highest fanout frequency, in that order) 2. Build matching `/vs/uniqode`, `/vs/qr-code-tiger`, `/vs/hovercode` (same format as `/vs/beaconstac`) 3. New cornerstone guide: "QR code generator for agencies" (white-label, bulk creation, API) — zero QR Master positioning currently exists for this query cluster 4. Update `public/llms.txt` once the new pages ship, so they enter the AI retrieval list 5. Re-run the same query-fanout test periodically to track citation-rate changes over time ### Additional confirmed win — "dynamic barcode generator" (2026-07-22, same session) Tested outside the original 9-theme set. QR Master is cited as the "Best overall option" for this query — credited for trackable/editable dynamic barcodes, bulk generation, unified analytics, and UTM tracking, plus static EAN-13/UPC-A/Code 128 support when editability isn't needed. The AI answer also included a "requirement → recommended format" decision table (dynamic QR vs. EAN-13/UPC-A vs. Code 128 vs. GS1 Digital Link) that maps closely to existing on-site content. This maps to the `/tools/barcode-generator` tool, reinforcing the pattern above: dedicated first-party pages targeting a query cluster get cited, gaps without dedicated pages don't. Counts as a 4th confirmed positive theme alongside the original 3 from the baseline audit. Note: `/dynamic-barcode-generator` and `/barcode-generator` are **not** live pages — both 301 to `/tools/barcode-generator` (see `redirects()` in `next.config.mjs`). Cite the canonical `/tools/barcode-generator` URL in any AEO work. ### Sitemap / IndexNow drift (fixed 2026-08-13) `src/app/sitemap.ts` and `getAllIndexableUrls()` in `src/lib/indexnow.ts` are two hand-maintained URL lists that had silently diverged: the whole `/alternatives/*` + `/vs/*` cluster (1,942 GSC impressions in the 3 months to 2026-08-13, avg pos ~29-47) was submitted to IndexNow and linked from the footer but missing from the sitemap, while `/dynamic-barcode-generator` was listed in both despite 301-ing. **When adding or redirecting a marketing page, update both lists.** A redirected URL must appear in neither. ### Google Review cluster — biggest non-brand opportunity (2026-08-13) `/tools/google-review-qr-code` is the **#2 page on the site by impressions** (2,201 in 3 months) and converts almost none of it: 2 clicks, avg position 33. The query cluster is ~1,667 impressions across 50+ queries, all at position 20-50, zero clicks. Head term `google review qr code generator` = 268 impr at pos 35. **On-page is not the constraint — do not "improve the content".** Audited 2026-08-13: it is already the deepest tool page on the site (1,352 rendered words, 8 h2 / 18 h3 vs 549 for crypto, 741 for wifi), with SoftwareApplication + HowTo + FAQPage schema, a correctly matched title, and canonical set. It also does not meaningfully cannibalize `/use-cases/qr-codes-for-review-collection` (36 impr, pos 11), which targets the tracking angle. What was done: added `google-review-qr-code` to `toolsMap` in `qr-code-for/[industry]/page.tsx` and to the `tools[]` array of the 32 local-business industries in `src/lib/industry-pages.ts`, creating contextual internal links from crawled, well-ranking pages (barbershops pos 9.7, hotels, cafes, bars). The 20 institutional industries (airports, schools, stadiums, libraries, churches, universities, museums, theaters, cinemas, art-galleries, events, trade-shows, retail, and the non-local stores) were deliberately excluded — review collection is not their job, and blanket-linking all 52 would be boilerplate. Remaining gap is off-site authority, not anything in this repo. Note the fallback in that template silently rewrites an unknown tool slug to `/tools/url-qr-code`, so any new slug must be added to `toolsMap` or the link disappears without erroring. ## Deployment Notes ### Docker (Self-Hosted) ```bash npm run docker:prod # Builds and starts full stack docker-compose exec web npx prisma migrate deploy # Run migrations in container ``` ### Vercel - Push to GitHub and import in Vercel dashboard - Set environment variables in Vercel settings - Requires external PostgreSQL database (Vercel Postgres, Supabase, etc.) - Redis is optional ## Additional Resources - README.md - Detailed setup and feature overview - DOCKER_SETUP.md - Complete Docker deployment guide - prisma/schema.prisma - Database schema and relationships - env.example - Environment variable template ## gstack (REQUIRED — global install) Before doing any AI-assisted work in this repo, verify gstack is installed globally: ```bash test -d ~/.claude/skills/gstack/bin && echo "GSTACK_OK" || echo "GSTACK_MISSING" ``` If `GSTACK_MISSING`: stop and install it: ```bash git clone --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack cd ~/.claude/skills/gstack && ./setup --team ``` After install, use gstack skills where appropriate, especially `/browse`, `/review`, `/investigate`, `/qa`, `/ship`, and `/cso`. Use `~/.claude/skills/gstack/...` for gstack file paths because this repo does not vendor the pack locally. ## Skill routing When the user's request matches an available skill, ALWAYS invoke it using the Skill tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. The skill has specialized workflows that produce better results than ad-hoc answers. Key routing rules: - Product ideas, "is this worth building", brainstorming → invoke office-hours - Bugs, errors, "why is this broken", 500 errors → invoke investigate - Ship, deploy, push, create PR → invoke ship - QA, test the site, find bugs → invoke qa - Code review, check my diff → invoke review - Update docs after shipping → invoke document-release - Weekly retro → invoke retro - Design system, brand → invoke design-consultation - Visual audit, design polish → invoke design-review - Architecture review → invoke plan-eng-review - Save progress, checkpoint, resume → invoke checkpoint - Code quality, health check → invoke health