Files
policy-ui/.claude/skills/nuxt/references/routing.md
HaimKortovich a2eb1f3789 Add nuxt-skills and update auto quotes to use new policy API structure
- Add nuxt-skills (vue, nuxt, nuxt-ui) to .claude/skills/
- Create useCustomerSelection() composable for managing insured/buyer selection
- Create usePolicyApi() composable for policy API operations
- Update auto quote components to use insured/buyer instead of client
- Update vehicle fields: remove valorVehiculo, add market_value, requested_value, rc_limits
- Make chassis_number and engine_number optional
- Update auto quote types and composables to match new API structure
- Update auto quote page to submit to policy API with new structure
2026-04-27 14:56:53 -05:00

6.1 KiB

Nuxt File-Based Routing

When to Use

Working with pages/ or layouts/ directories, file-based routing, navigation.

File-Based Routing Basics

pages/ folder structure directly maps to routes. File names determine URLs.

Naming Conventions

Key principles:

  • ALWAYS use descriptive params: [userId].vue NOT [id].vue
  • Optional params: [[paramName]].vue
  • Catch-all: [...path].vue
  • Route groups for organization: (folder)/ groups files without affecting URLs

Red Flags - Stop and Check Skill

If you're thinking any of these, STOP and re-read this skill:

  • "String paths are simpler than typed routes"
  • "Generic param names like [id] are fine"
  • "I remember how Nuxt 3 worked"

All of these mean: You're about to use outdated patterns. Use Nuxt 4 patterns instead.

File Structure Example

pages/
├── index.vue               # /
├── about.vue               # /about
├── [...slug].vue           # catch-all for 404
├── users.vue               # parent route (layout for /users/*)
└── users/
    ├── index.vue           # /users
    └── [userId].vue        # /users/:userId

Route Groups for Organization

Route groups organize files WITHOUT affecting URLs. Wrap folder names in parentheses:

pages/
├── (marketing)/            # group folder (ignored in URL)
│   ├── about.vue           # /about (not /marketing/about)
│   └── pricing.vue         # /pricing
└── (admin)/                # group folder (ignored in URL)
    ├── dashboard.vue       # /dashboard
    └── settings.vue        # /settings

Use route groups to:

  • Organize pages by feature/team
  • Group related routes without affecting URLs
  • Keep large projects maintainable
  • Apply middleware to specific groups (via route.meta.groups)

Access route groups in middleware:

// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to) => {
  // Check if route is in admin group
  if (to.meta.groups?.includes('admin')) {
    const auth = useAuthStore()
    if (!auth.isAdmin) return navigateTo('/')
  }
})

Parent Routes (Layouts)

Parent route = layout for nested routes:

<!-- pages/users.vue -->
<template>
  <div class="users-layout">
    <nav>
      <NuxtLink to="/users">All Users</NuxtLink>
      <NuxtLink to="/users/create">Create User</NuxtLink>
    </nav>
    <NuxtPage />
  </div>
</template>

Child routes:

pages/
├── users.vue           # Parent route with <NuxtPage />
└── users/
    ├── index.vue       # /users
    ├── [userId].vue    # /users/:userId
    └── create.vue      # /users/create

definePage() for Route Customization

<script setup lang="ts">
definePage({
  name: 'user-profile',
  path: '/profile/:userId',  // Override default path
  alias: ['/me', '/profile'],
  meta: {
    requiresAuth: true,
    title: 'User Profile',
    roles: ['user', 'admin']
  }
})
</script>

<template>
  <div>Profile content</div>
</template>

Typed Router

ALWAYS use typed routes for navigation:

// ✅ Type-safe with route name
await navigateTo({ name: '/users/[userId]', params: { userId: '123' } })

// ❌ String-based (not type-safe, avoid)
await navigateTo('/users/123')

REQUIRED: Check typed-router.d.ts for available route names and params before navigating.

useRoute with Types

Pass route name for stricter typing:

// Generic route
const route = useRoute()

// Typed route (preferred)
const route = useRoute('/users/[userId]')
// route.params.userId is now typed correctly

Navigation

// Navigate to route
await navigateTo('/about')
await navigateTo({ name: '/users/[userId]', params: { userId: '123' } })

// Navigate with query
await navigateTo({ path: '/search', query: { q: 'nuxt' } })

// External redirect
await navigateTo('https://nuxt.com', { external: true })

// Replace history
await navigateTo('/login', { replace: true })

// Open in new tab
await navigateTo('/docs', { open: { target: '_blank' } })

Route Meta & Middleware

<script setup lang="ts">
definePageMeta({
  middleware: ['auth', 'admin'],
  layout: 'dashboard',
  meta: {
    requiresAuth: true
  }
})
</script>

Dynamic Layout Switching

Use setPageLayout() to switch layouts programmatically:

<script setup lang="ts">
const user = useUser()

// Switch layout based on auth state
if (!user.value) {
  setPageLayout('guest')
} else {
  setPageLayout('dashboard')
}

// With layout props (Nuxt 4.3+)
setPageLayout('dashboard', {
  sidebar: 'collapsed',
  theme: 'dark'
})
</script>

Dynamic Routes Patterns

[userId].vue              # /users/123
[[slug]].vue              # /blog or /blog/post (optional)
[...path].vue             # /a/b/c (catch-all)
[[...path]].vue           # / or /a/b/c (optional catch-all)

Best Practices

  • index.vue for index routes - valid and correct for creating default routes
  • Route groups (folder)/ for organization - group files without affecting URLs
  • Descriptive param names - [userId] not [id], [postSlug] not [slug]
  • Type-safe navigation - use route names, not strings
  • Check typed-router.d.ts for available routes
  • Parent routes for layouts - users.vue with <NuxtPage />
  • Use definePage for custom paths/aliases
  • Catch-all for 404 - [...path].vue or [...slug].vue

Common Mistakes

Wrong Right
[id].vue [userId].vue or [postId].vue
navigateTo('/users/' + id) navigateTo({ name: '/users/[userId]', params: { userId: id } })
<Nuxt /> <NuxtPage />
Separate layouts/ folder Parent routes with <NuxtPage />

Resources