Consent is bound to the channel it was given for: approving a post on X says nothing about Instagram. Publishing state moves from the SocialMilestone row into SocialMilestonePost, one row per channel, where a missing row means no consent. The dialog asks per channel, shows the text each one will publish and keeps a separate handle for each; Instagram captions end in hashtags because a link there is not clickable. Also fixes three problems in the existing X path: - A QR code already past several thresholds produced one prompt per threshold, and since the post quotes the current scan count, every one of them would have published the same number. Only the highest threshold is announced now. - Detection ran after every unique scan and re-read the QR code's full scan history just to hit skipDuplicates. Known milestones are filtered first. - A failed post stayed failed forever because the consent dialog only opens once. The queue now retries three times on its own, spaces first attempts by SOCIAL_MILESTONE_MIN_GAP_HOURS, and Settings lists every milestone per channel with restart and revoke. The worker no longer renders the card itself; it downloads the image the app renders at /s/m/<token>/og, which also serves the new square and portrait formats. Instagram publishing stays off until SOCIAL_MILESTONE_CHANNELS and SOCIAL_WORKER_CHANNELS both name it. Schema changes are manual SQL, see sql/2026-08-16_*.sql. Run both before deploying this version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
QR Master - Create Custom QR Codes in Seconds
A production-ready SaaS application for creating and managing QR codes with advanced tracking, analytics, and Stripe payment integration.
Features
- 🎨 Custom QR Codes - Create static and dynamic QR codes with full customization
- 📊 Advanced Analytics - Track scans, locations, devices, and user behavior
- 🔄 Dynamic Content - Edit QR code destinations anytime without reprinting
- 📦 Bulk Operations - Import CSV/Excel files to create up to 1,000 QR codes at once
- 💳 Stripe Integration - FREE, PRO, and BUSINESS subscription plans with secure billing
- 🎨 Custom Branding - Logo upload, custom colors (PRO+ plans)
- 🌍 SEO Optimized - Schema.org structured data, meta tags, breadcrumbs
- 🔒 Privacy-First - GDPR-compliant, hashed IPs, DNT headers respected
- 📱 Responsive Design - Works perfectly on all devices
Tech Stack
- Frontend: Next.js 14 (App Router), TypeScript, Tailwind CSS
- Backend: Next.js API Routes, Prisma ORM
- Database: PostgreSQL (with Prisma migrations)
- Cache: Redis (optional)
- Auth: NextAuth.js (Credentials + Google OAuth)
- Payments: Stripe (Subscriptions & Webhooks)
- QR Generation: qrcode library
- Bulk Processing: Papa Parse (CSV), XLSX, JSZip
- Analytics: PostHog (optional)
- SEO: next-sitemap, Schema.org structured data
Quick Start
Prerequisites
- Node.js 18+
- Docker and Docker Compose V2
- Git
Installation
Option 1: Development Mode (Recommended)
Run database in Docker, app on host machine:
- Clone the repository:
git clone https://github.com/yourusername/qr-master.git
cd qr-master
- Install dependencies:
npm install
- Copy and configure environment:
cp env.example .env
Edit .env and set:
NEXTAUTH_SECRET(generate:openssl rand -base64 32)IP_SALT(generate:openssl rand -base64 32)- (Optional) Google OAuth credentials
- Start database services:
npm run docker:dev
- Run database migrations and seed:
npx prisma migrate dev
npm run db:seed
Note
: If you get migration errors, you can reset the database:
npx prisma migrate resetThis will drop the database, recreate it, run all migrations, and seed data.
- Start development server:
npm run dev
- Access the application:
- App: http://localhost:3050
- Database UI: http://localhost:8080 (Adminer - username:
root, password:root) - Database: localhost:5435 (username:
postgres, password:postgres) - Redis: localhost:6379
Option 2: Full Docker (Production)
Run everything in Docker:
- Clone and setup:
git clone https://github.com/yourusername/qr-master.git
cd qr-master
cp env.example .env
# Edit .env with your configuration
- Build and start:
npm run docker:prod
- Run migrations:
docker-compose exec web npx prisma migrate deploy
- Access at http://localhost:3050
📚 For detailed Docker setup, see DOCKER_SETUP.md
Demo Account
After running npm run db:seed, use these credentials to test the application:
- Email: demo@qrmaster.com
- Password: demo123
- Plan: FREE (3 QR codes limit)
The seed script also creates sample QR codes for testing.
Development
Available Scripts
# Development
npm run dev # Start Next.js dev server (port 3050)
npm run build # Build for production
npm run start # Start production server
# Database
npm run db:generate # Generate Prisma Client
npm run db:migrate # Run migrations (dev mode)
npm run db:deploy # Deploy migrations (production)
npm run db:seed # Seed database with demo data
npm run db:studio # Open Prisma Studio UI
npx prisma migrate reset # Reset database (drop, recreate, migrate, seed)
# Docker
npm run docker:dev # Start DB & Redis only
npm run docker:dev:stop # Stop dev services
npm run docker:dev:clean # Stop and clean containers
npm run docker:prod # Start full stack (production)
npm run docker:stop # Stop all services
npm run docker:logs # View container logs
npm run docker:db # PostgreSQL CLI
npm run docker:redis # Redis CLI
npm run docker:backup # Backup database to SQL file
Local Development (without Docker)
- Install dependencies:
npm install
-
Set up PostgreSQL and Redis locally
-
Configure
.envwith local database URL:
DATABASE_URL=postgresql://postgres:postgres@localhost:5435/qrmaster?schema=public
- Run migrations and seed:
npx prisma migrate dev
npm run db:seed
- Start dev server:
npm run dev
Resetting the Database
If you need to reset your database (drop all tables, recreate, and reseed):
# Full reset (drops database, reruns migrations, seeds data)
npx prisma migrate reset
# Or manually:
npx prisma migrate reset --skip-seed # Reset without seeding
npm run db:seed # Then seed manually
This is useful when:
- Schema has changed significantly
- You have migration conflicts
- You want to start fresh with clean data
Project Structure
qr-master/
├── src/
│ ├── app/ # Next.js app router pages
│ ├── components/ # React components
│ ├── lib/ # Utility functions and configurations
│ ├── hooks/ # Custom React hooks
│ ├── styles/ # Global styles
│ └── i18n/ # Translation files
├── prisma/ # Database schema and migrations
├── docker/ # Docker initialization scripts
│ ├── init-db.sh # PostgreSQL initialization
│ └── README.md # Docker documentation
├── public/ # Static assets
├── docker-compose.yml # Production Docker setup
├── docker-compose.dev.yml # Development Docker setup
├── Dockerfile # Container definition
├── DOCKER_SETUP.md # Complete Docker guide
└── env.example # Environment template
API Endpoints
Authentication
POST /api/auth/signin- Sign in with credentialsPOST /api/auth/signout- Sign outGET /api/auth/session- Get current session
QR Codes
GET /api/qrs- List all QR codesPOST /api/qrs- Create a new QR code (dynamic or static)POST /api/qrs/static- Create a static QR codeGET /api/qrs/[id]- Get QR code detailsPATCH /api/qrs/[id]- Update QR codeDELETE /api/qrs/[id]- Delete QR codeDELETE /api/qrs/delete-all- Delete all user's QR codes
Analytics
GET /api/analytics/summary- Get analytics summary for a QR code
User & Settings
GET /api/user/plan- Get current user planGET /api/user/stats- Get user statisticsPOST /api/user/password- Update passwordPOST /api/user/profile- Update profileDELETE /api/user/delete- Delete account
Stripe Payments
POST /api/stripe/checkout- Create checkout sessionPOST /api/stripe/portal- Create customer portal sessionPOST /api/stripe/webhook- Handle Stripe webhooksPOST /api/stripe/cancel-subscription- Cancel subscription
Public Redirect
GET /r/[slug]- Redirect and track QR code scan
Environment Variables
| Variable | Description | Required | Default |
|---|---|---|---|
DATABASE_URL |
PostgreSQL connection string | Yes | - |
NEXTAUTH_URL |
Application URL | Yes | http://localhost:3050 |
NEXTAUTH_SECRET |
Secret for JWT encryption | Yes | - (Generate with openssl rand -base64 32) |
IP_SALT |
Salt for IP hashing (privacy) | Yes | Generate with openssl rand -base64 32 |
GOOGLE_CLIENT_ID |
Google OAuth client ID | No | - |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret | No | - |
STRIPE_SECRET_KEY |
Stripe secret key | No | - |
STRIPE_WEBHOOK_SECRET |
Stripe webhook signing secret | No | - |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY |
Stripe public key | No | - |
NEXT_PUBLIC_INDEXABLE |
Allow search engine indexing | No | false (set to true in production) |
REDIS_URL |
Redis connection string | No | redis://redis:6379 |
NEXT_PUBLIC_POSTHOG_KEY |
PostHog analytics key | No | - |
NEXT_PUBLIC_POSTHOG_HOST |
PostHog host URL | No | - |
Note: Copy env.example to .env and update the values before starting.
Generating Secrets
# Generate NEXTAUTH_SECRET
openssl rand -base64 32
# Generate IP_SALT
openssl rand -base64 32
Security & Privacy
- IP Hashing: IP addresses are hashed with salt before storage (GDPR-compliant)
- DNT Respect: Honors Do Not Track browser headers
- Rate Limiting: API endpoints protected against abuse
- CSRF Protection: Token-based CSRF validation on mutations
- Secure Sessions: NextAuth.js with encrypted JWT tokens
- Stripe Security: PCI-compliant payment processing
- SQL Injection Prevention: Prisma ORM parameterized queries
Database Schema
The application uses PostgreSQL with Prisma ORM. Key models:
- User: User accounts with Stripe subscription data
- QRCode: QR code records (static/dynamic, multiple content types)
- QRScan: Scan analytics data (hashed IP, device, location, UTM params)
- Integration: Third-party integrations (Zapier, etc.)
- Account/Session: NextAuth authentication data
Supported QR Code Types
- URL: Website links
- VCARD: Contact cards (name, email, phone, company)
- GEO: GPS locations
- PHONE: Phone numbers (tel: links)
- TEXT: Plain text
- SMS: SMS messages
- WHATSAPP: WhatsApp messages
Plans
- FREE: 3 dynamic QR codes, unlimited static
- PRO: 50 codes, custom branding, advanced analytics
- BUSINESS: 500 codes, bulk upload, API access, priority support
Deployment
Docker (Recommended for Self-Hosting)
The application includes production-ready Docker configuration with PostgreSQL and Redis:
# Build and start all services
docker-compose up -d --build
# Run migrations
docker-compose exec web npx prisma migrate deploy
# View logs
docker-compose logs -f
For detailed deployment instructions, see DOCKER_SETUP.md.
Vercel
- Push your code to GitHub
- Import the project in Vercel
- Add a PostgreSQL database (Vercel Postgres, Supabase, or other)
- Add environment variables in Vercel dashboard
- Deploy
Note: For Vercel deployment, you'll need to set up a PostgreSQL database separately.
Troubleshooting
Database Issues
Problem: Migration errors or schema conflicts
# Solution: Reset the database
npx prisma migrate reset
Problem: "Error: P1001: Can't reach database server"
# Check if Docker containers are running
docker ps
# Restart database
npm run docker:dev:stop
npm run docker:dev
Problem: Prisma Client out of sync
# Regenerate Prisma Client
npx prisma generate
Problem: Need to start completely fresh
# Stop all Docker containers
npm run docker:dev:stop
# Remove volumes (⚠️ deletes all data)
docker volume prune
# Restart everything
npm run docker:dev
npx prisma migrate dev
npm run db:seed
Port Already in Use
If port 3050 is already in use:
# Find and kill the process (Windows)
netstat -ano | findstr :3050
taskkill /PID <PID> /F
# Or change the port in package.json
"dev": "next dev -p 3051"
Docker Issues
Problem: Permission denied errors
# Windows: Run PowerShell as Administrator
# Linux/Mac: Use sudo for docker commands
Problem: Out of disk space
# Clean up Docker
docker system prune -a
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For support, email support@qrmaster.net or open an issue on GitHub.
Acknowledgments
- Next.js team for the amazing framework
- Vercel for hosting and deployment
- All open-source contributors
Built with ❤️ by QR Master Team
Führe diese im Terminal aus:
IndexNow (Bing/Yandex + Partner): npm run submit:indexnow Google Indexing API: npm run trigger:indexing