# Migrating QRurl to Nuxt 3 with NuxtFlare

## Why Nuxt 3 + NuxtFlare?

### Current Architecture Problems:
- Separate frontend (Vue) and backend (Workers) codebases
- Complex CORS configuration
- Manual static file serving
- Two different routing systems
- Complicated deployment process

### Nuxt 3 + NuxtFlare Benefits:
- **Single codebase** - Frontend and backend unified
- **SSR on Workers** - Better SEO and performance
- **Built-in API routes** - `/server/api/*` routes
- **Direct Cloudflare bindings** - D1, R2, KV without wrangler
- **Zero CORS issues** - Everything on same origin
- **Simple deployment** - `npm run deploy`
- **Hot module replacement** - Full-stack HMR in development
- **TypeScript support** - End-to-end type safety

## Migration Strategy

### Phase 1: Setup Nuxt 3 Project

```bash
# Create new Nuxt 3 app
npx nuxi@latest init qrurl-nuxt

# Install dependencies
cd qrurl-nuxt
npm install

# Add NuxtFlare module
npm install @nuxflare/core
```

### Phase 2: Configure NuxtFlare

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxflare/core'],
  
  nitro: {
    preset: 'cloudflare-pages',
    
    // Cloudflare bindings
    cloudflare: {
      bindings: {
        DB: {
          type: 'd1',
          databaseName: 'qrurl-db',
          databaseId: '17eb6fdb-19da-4ed7-931c-a4cdef281f8c'
        },
        STORAGE: {
          type: 'r2',
          bucketName: 'qrurl-storage'
        },
        CACHE: {
          type: 'kv',
          namespaceId: '1cacb0f1b44b4324b62c1bc010ff15f5'
        }
      }
    }
  }
})
```

### Phase 3: Migrate Components

Move Vue components to Nuxt structure:
```
frontend/src/components/* → components/
frontend/src/views/* → pages/
frontend/src/stores/* → stores/ (with Pinia)
```

### Phase 4: Convert API Routes

Transform Workers routes to Nuxt server routes:

**Before (Workers):**
```javascript
// src/routes/api.js
export async function apiRoutes(request, env, ctx) {
  if (path === '/api/links') {
    return getLinks(request, env);
  }
}
```

**After (Nuxt):**
```typescript
// server/api/links.get.ts
export default defineEventHandler(async (event) => {
  const db = useD1Database('DB', event);
  return await db.prepare('SELECT * FROM links').all();
})
```

### Phase 5: Authentication with Nuxt

```typescript
// server/api/auth/request.post.ts
import { usePostmark } from '#nuxflare/postmark';

export default defineEventHandler(async (event) => {
  const { email } = await readBody(event);
  const postmark = usePostmark(event);
  
  // Generate magic link
  const token = generateToken();
  
  // Store in D1
  const db = useD1Database('DB', event);
  await db.prepare('INSERT INTO auth_tokens...').run();
  
  // Send email
  await postmark.sendEmail({
    From: 'noreply@qrurl.us',
    To: email,
    Subject: 'Your QRurl Login Link',
    HtmlBody: `...`
  });
  
  return { success: true };
})
```

### Phase 6: File Uploads with R2

```typescript
// server/api/logo/upload.post.ts
export default defineEventHandler(async (event) => {
  const form = await readFormData(event);
  const file = form.get('logo') as File;
  
  const r2 = useR2Bucket('STORAGE', event);
  await r2.put(`logos/${file.name}`, file);
  
  return { url: `/api/logo/${file.name}` };
})
```

## File Structure (Nuxt)

```
qrurl-nuxt/
├── server/
│   ├── api/
│   │   ├── auth/
│   │   │   ├── request.post.ts
│   │   │   └── verify.post.ts
│   │   ├── links/
│   │   │   ├── index.get.ts
│   │   │   ├── index.post.ts
│   │   │   └── [id].delete.ts
│   │   └── logo/
│   │       ├── upload.post.ts
│   │       └── [id].get.ts
│   └── routes/
│       └── [slug].ts          # Short link redirects
├── pages/
│   ├── index.vue              # Homepage
│   ├── dashboard.vue          # Dashboard
│   └── auth/
│       └── verify.vue         # Magic link verification
├── components/
│   ├── NavBar.vue
│   ├── CreateLinkForm.vue
│   ├── QRCodeGenerator.vue
│   └── LogoUploader.vue
├── stores/
│   └── auth.ts                # Pinia store
├── nuxt.config.ts
└── wrangler.toml              # Minimal, just for secrets

```

## Deployment (Simplified!)

### Development:
```bash
npm run dev
# That's it! Full-stack hot reload
```

### Production:
```bash
npm run build
npm run deploy
# Deploys everything to Cloudflare Workers/Pages
```

## Benefits Over Current Architecture

| Feature | Current (Vue + Workers) | Nuxt 3 + NuxtFlare |
|---------|------------------------|-------------------|
| **Codebase** | 2 separate | 1 unified |
| **Routing** | Vue Router + Workers Router | Nuxt file-based routing |
| **API** | Manual Workers setup | Built-in server routes |
| **SSR** | No (SPA only) | Yes (better SEO) |
| **Development** | 2 servers + CORS | 1 server, no CORS |
| **Type Safety** | Partial | Full-stack TypeScript |
| **Deployment** | Complex scripts | Single command |
| **HMR** | Frontend only | Full-stack |
| **Data Fetching** | Manual fetch + CORS | `$fetch` with auto-typing |

## Migration Timeline

1. **Week 1**: Set up Nuxt project, migrate components
2. **Week 2**: Convert API routes to server routes
3. **Week 3**: Integrate D1, R2, KV with NuxtFlare
4. **Week 4**: Testing and deployment optimization

## Example: Complete Link Creation Flow

```vue
<!-- pages/dashboard.vue -->
<template>
  <form @submit.prevent="createLink">
    <input v-model="url" />
    <button type="submit">Shorten</button>
  </form>
</template>

<script setup>
const url = ref('');

async function createLink() {
  // No CORS, no API URL config needed!
  const { slug } = await $fetch('/api/links', {
    method: 'POST',
    body: { url: url.value }
  });
  
  // Redirect to success page
  await navigateTo(`/link/${slug}`);
}
</script>
```

```typescript
// server/api/links.post.ts
export default defineEventHandler(async (event) => {
  const { url } = await readBody(event);
  const db = useD1Database('DB', event);
  
  const slug = generateSlug();
  await db.prepare(
    'INSERT INTO links (slug, url) VALUES (?, ?)'
  ).bind(slug, url).run();
  
  return { slug };
})
```

## Conclusion

Migrating to Nuxt 3 with NuxtFlare would:
- **Eliminate complexity** - No more CORS, separate deployments, or complex configs
- **Improve developer experience** - Single codebase, full-stack HMR
- **Enhance performance** - SSR, edge rendering, better caching
- **Simplify deployment** - One command to deploy everything

The migration effort would be worth it for the massive simplification and improved developer experience.