Clone
NUXT-CLOUDFLARE-DEPLOYMENT-PLAN.md
Blame History Raw Edit 8.5 KB

Complete Plan: QRurl with Nuxt on Cloudflare Workers

Overview

Build a URL shortener with QR code generation using Nuxt (latest stable version) deployed to Cloudflare Workers with D1 database, R2 storage, and Postmark email integration.

Architecture Components

  • Frontend & Backend: Single Nuxt application (SSR)
  • Database: Cloudflare D1 (SQLite)
  • File Storage: Cloudflare R2 (for logos)
  • Cache: Cloudflare KV
  • Email: Postmark API
  • Deployment: Cloudflare Workers via Wrangler

Prerequisites

  • Node.js 20.x or later (stable LTS)
  • Cloudflare account with Workers, D1, R2, KV enabled
  • Domain in Cloudflare (qrurl.us)
  • Postmark account and API key
  • GitHub account (optional for CI/CD)

Step-by-Step Implementation Plan

Phase 1: Project Setup

1.1 Initialize Nuxt Project

npx nuxi@latest init qrurl --package-manager npm
cd qrurl

1.2 Install Core Dependencies

npm install --save-dev wrangler@latest
npm install @nuxt/ui @pinia/nuxt @vueuse/nuxt
npm install qrcode jsonwebtoken bcryptjs
npm install --save-dev @types/jsonwebtoken @types/bcryptjs

1.3 Configure Nuxt for Cloudflare

Create nuxt.config.ts:

  • Set nitro preset to cloudflare-pages or cloudflare-module
  • Configure build output for Workers
  • Set up environment variables
  • Configure TypeScript

Phase 2: Database Setup

2.1 Create D1 Database

wrangler d1 create qrurl-db

2.2 Database Schema

Create schema.sql:

CREATE TABLE links (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
url TEXT NOT NULL,
name TEXT,
logo_key TEXT,
user_email TEXT,
clicks INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE auth_tokens (
token TEXT PRIMARY KEY,
email TEXT NOT NULL,
used INTEGER DEFAULT 0,
expires_at DATETIME NOT NULL
);
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
user_email TEXT NOT NULL,
expires_at DATETIME NOT NULL
);
CREATE INDEX idx_links_slug ON links(slug);
CREATE INDEX idx_sessions_email ON sessions(user_email);

2.3 Initialize Database

wrangler d1 execute qrurl-db --file=./schema.sql --local
wrangler d1 execute qrurl-db --file=./schema.sql --remote

Phase 3: Cloudflare Resources Setup

3.1 Create R2 Bucket

wrangler r2 bucket create qrurl-logos

3.2 Create KV Namespace

wrangler kv namespace create cache

3.3 Update wrangler.toml

name = "qrurl"
compatibility_date = "2024-12-01"
pages_build_output_dir = ".output/public"
[[d1_databases]]
binding = "DB"
database_name = "qrurl-db"
database_id = "YOUR_DB_ID"
[[r2_buckets]]
binding = "STORAGE"
bucket_name = "qrurl-logos"
[[kv_namespaces]]
binding = "CACHE"
id = "YOUR_KV_ID"
[vars]
EMAIL_FROM = "noreply@qrurl.us"

Phase 4: Application Development

4.1 Directory Structure

qrurl/
├── server/
│ ├── api/
│ │ ├── auth/
│ │ │ ├── request.post.ts
│ │ │ └── verify.get.ts
│ │ ├── links/
│ │ │ ├── index.get.ts
│ │ │ ├── index.post.ts
│ │ │ └── [id].delete.ts
│ │ ├── qr/
│ │ │ └── [slug].get.ts
│ │ └── logo/
│ │ ├── upload.post.ts
│ │ └── [id].get.ts
│ ├── middleware/
│ │ └── auth.ts
│ └── utils/
│ ├── db.ts
│ ├── auth.ts
│ └── email.ts
├── pages/
│ ├── index.vue
│ ├── login.vue
│ ├── dashboard.vue
│ └── [slug].vue
├── components/
│ ├── NavBar.vue
│ ├── LinkForm.vue
│ ├── LinkList.vue
│ ├── QRCodeModal.vue
│ └── LogoUploader.vue
├── stores/
│ └── auth.ts
├── composables/
│ └── useApi.ts
└── public/

4.2 Server API Implementation

Database Utils (server/utils/db.ts):

  • Direct D1 binding access
  • Query builders
  • Migration helpers

Auth Utils (server/utils/auth.ts):

  • JWT token generation/verification
  • Session management
  • Cookie handling

Email Utils (server/utils/email.ts):

  • Postmark integration
  • Magic link generation
  • Email templates

4.3 Frontend Implementation

Pages:

  • index.vue: Public URL shortener
  • login.vue: Magic link request
  • dashboard.vue: Authenticated link management
  • [slug].vue: Redirect handler

Components:

  • Form validation
  • Real-time updates
  • QR code generation with logo overlay
  • File upload to R2

State Management (Pinia):

  • Auth store
  • Links store
  • UI store

Phase 5: Authentication Flow

  1. User enters email on login page
  2. Server validates email against whitelist
  3. Generate magic link token, store in D1
  4. Send email via Postmark
  5. User clicks link
  6. Verify token, create session
  7. Set HTTP-only cookie
  8. Redirect to dashboard

Phase 6: Core Features

6.1 URL Shortening

  • Generate random slug or accept custom
  • Validate URL format
  • Check slug uniqueness
  • Store in D1 with metadata

6.2 QR Code Generation

  • Use qrcode library
  • High error correction for logo overlay
  • Return as base64 or binary
  • Cache in KV for performance

6.3 Logo Upload

  • Accept image upload
  • Validate file type/size
  • Store in R2 with unique key
  • Reference in link record

6.4 Analytics

  • Track clicks in D1
  • Store user agent, referrer
  • Display in dashboard
  • Export functionality

Phase 7: Environment Configuration

7.1 Development (.env)

NUXT_JWT_SECRET=dev-secret
NUXT_EMAIL_API_KEY=your-postmark-key
NUXT_AUTHORIZED_EMAILS=email1@example.com,email2@example.com

7.2 Production Secrets

wrangler secret put JWT_SECRET
wrangler secret put EMAIL_API_KEY
wrangler secret put AUTHORIZED_EMAILS

Phase 8: Deployment

8.1 Build Process

npm run build

8.2 Deploy to Cloudflare

wrangler pages deploy .output/public

8.3 Configure Custom Domain

  1. Cloudflare Dashboard → Pages → Custom domains
  2. Add qrurl.us
  3. Configure DNS if needed

Phase 9: Testing & Optimization

9.1 Local Testing

npm run dev # Development server
npm run preview # Production preview

9.2 Performance Optimization

  • Implement caching strategies
  • Optimize database queries
  • Compress assets
  • Lazy load components

9.3 Security

  • Rate limiting
  • Input validation
  • CSRF protection
  • Content Security Policy

Phase 10: CI/CD Setup (Optional)

10.1 GitHub Actions

name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run build
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}

Common Issues & Solutions

Issue 1: EBADF Errors

  • Use Node.js LTS (20.x)
  • Avoid Node.js 23.x
  • Check file descriptor limits

Issue 2: D1 Binding Issues

  • Ensure database ID matches
  • Check wrangler.toml configuration
  • Verify local vs remote execution

Issue 3: CORS Problems

  • Not needed with unified deployment
  • Everything on same domain

Issue 4: Build Failures

  • Clear .nuxt and node_modules
  • Reinstall dependencies
  • Check TypeScript errors

Key Differences from Framework-Heavy Approach

  1. Simpler Structure: Single deployment unit
  2. No CORS: API and frontend on same domain
  3. Direct Bindings: Use Cloudflare resources directly
  4. Better Performance: Edge-optimized
  5. Easier Debugging: Unified logs

Testing Checklist

  • Homepage loads
  • URL shortening works
  • QR codes generate
  • Redirects work
  • Login flow completes
  • Dashboard accessible
  • Logo upload works
  • Analytics track
  • Session persistence
  • Logout works

Production Checklist

  • Database migrated
  • Secrets configured
  • Custom domain active
  • SSL working
  • Email sending
  • Error handling
  • Monitoring setup
  • Backup strategy

Estimated Timeline

  • Phase 1-3: 1 hour (setup)
  • Phase 4-6: 4-6 hours (development)
  • Phase 7-8: 1 hour (deployment)
  • Phase 9-10: 2 hours (testing/optimization)

Total: 8-10 hours for complete implementation

Success Criteria

  1. App deploys to qrurl.us
  2. All features from original app work
  3. No framework complexity
  4. Fast performance (<100ms response)
  5. Reliable email delivery
  6. Secure authentication
  7. Clean, maintainable code