Skip to content

Folder Structure ​

Understanding the frontend project organization.

Project Structure ​

apps/frontend/
  app/
    β”œβ”€β”€ components/        # Reusable components (auto-imported)
    β”œβ”€β”€ composables/       # Composables (auto-imported)
    β”œβ”€β”€ layouts/           # Layout wrappers
    β”œβ”€β”€ middleware/        # Route middleware
    β”œβ”€β”€ pages/             # File-based routes
    β”œβ”€β”€ plugins/           # App plugins
    β”œβ”€β”€ types/             # TypeScript types
    β”œβ”€β”€ utils/             # Utility functions (auto-imported)
    └── app.vue            # Root component
  i18n/locales/            # Translation files
  public/                  # Static assets

Auto-Imports ​

These folders are automatically imported - no import statements needed:

  • βœ… components/ - All components
  • βœ… composables/ - All composables
  • βœ… utils/ - All utilities
vue
<script setup>
// βœ… No imports needed - auto-imported
const { data } = useApi('/api/endpoint')
const result = someUtilFunction()
</script>

<template>
  <!-- βœ… No import needed -->
  <UiButton>Click me</UiButton>
</template>

Components Organization ​

Global Components (components/) ​

Reusable components available throughout the app:

components/
  β”œβ”€β”€ ui/                  # shadcn-vue UI components
  β”‚   β”œβ”€β”€ button/
  β”‚   β”œβ”€β”€ input/
  β”‚   └── dialog/
  β”œβ”€β”€ app-shell/           # App layout components
  β”œβ”€β”€ chevron/             # RTL-aware chevrons
  └── route-dialog/        # Route dialog utilities

Page-Specific Components (_components/) ​

Components specific to a page or feature:

pages/
  employees/
    index.vue              # Parent page
    _components/           # Components for employees pages
      EmployeeTable.vue
      EmployeeRow.vue
      EmployeeFilters.vue

Component Names Must Be UNIQUE

Important: _components folders are auto-imported but NOT scoped!

pages/
  employees/
    _components/
      EmployeeTable.vue    # ❌ Conflict!
  
  departments/
    _components/
      EmployeeTable.vue    # ❌ Same name - will conflict!

Solution: Use unique names:

employees/_components/EmployeeTable.vue     # βœ… Unique
departments/_components/DepartmentTable.vue  # βœ… Unique

Optional Explicit Imports ​

For local components, you can optionally use explicit imports for clarity:

vue
<script setup>
// βœ… Optional - makes it clear where component comes from
import EmployeeTable from './_components/EmployeeTable.vue'

// βœ… Also valid - auto-import (works because of unique names)
// No import needed
</script>

<template>
  <EmployeeTable />
</template>

When to Use Explicit Imports

Use explicit imports when:

  • You want to make the component source obvious
  • Working with unfamiliar code
  • Prefer explicit over implicit

Types Organization ​

Global Types (types/) ​

Shared types available throughout the app:

types/
  β”œβ”€β”€ api-types.ts         # Auto-generated from OpenAPI
  β”œβ”€β”€ api-type-utils.ts    # API type helpers
  β”œβ”€β”€ employee.ts          # Employee types
  └── index.d.ts           # Global declarations

Local Types Files ​

For page or feature-specific types, create a local types.ts:

pages/
  employees/
    [id]/
      profile/
        index.vue
        _components/
          ProfileCard.vue
        types.ts           # Local types for profile page

When to use local types:

  • Types only used in this page/feature
  • Not needed elsewhere in the app
  • Keep types close to usage
typescript
// pages/employees/[id]/profile/types.ts
export interface ProfileFormData {
  firstName: string
  lastName: string
  email: string
}

export type ProfileSection = 'personal' | 'contact' | 'employment'

Composables (composables/) ​

Auto-imported composables:

composables/
  β”œβ”€β”€ useApi.ts            # API calls
  β”œβ”€β”€ useConfirm.ts        # Confirmation dialogs
  β”œβ”€β”€ useRtl.ts            # RTL support
  β”œβ”€β”€ useEdit.ts           # Edit mode management
  └── state/               # State management
      β”œβ”€β”€ auth.ts
      └── organizationData.ts

Usage:

vue
<script setup>
// βœ… No import needed
const { data } = useApi('/api/endpoint')
const { confirm } = useConfirm()
</script>

Utils (utils/) ​

Auto-imported utility functions:

utils/
  β”œβ”€β”€ apiTypes.ts          # API type shortcuts
  β”œβ”€β”€ errorHandling.ts     # Error utilities
  β”œβ”€β”€ fireAndForget.ts     # Async helpers
  β”œβ”€β”€ i18n-keys.ts         # r() function
  └── validation.ts        # Validation helpers

Usage:

vue
<script setup>
// βœ… No import needed
fireAndForget(saveData, 'Failed to save')

if (isApiError(error)) {
  // Handle error
}
</script>

Layouts (layouts/) ​

Layout wrappers for different page types:

layouts/
  β”œβ”€β”€ default.vue          # Default layout
  β”œβ”€β”€ auth.vue             # Auth pages layout
  └── hr.vue               # HR app layout

Usage in pages:

vue
<script setup>
definePageMeta({
  layout: 'hr'
})
</script>

Middleware (middleware/) ​

Route middleware for navigation guards:

middleware/
  β”œβ”€β”€ 01-initUser.global.ts    # Global middleware (runs on every route)
  └── auth-step.ts              # Named middleware

Plugins (plugins/) ​

App-wide plugins:

plugins/
  β”œβ”€β”€ api.ts               # API setup ($api, $apiFetch)
  β”œβ”€β”€ focus.ts             # Focus management
  └── maska.ts             # Input masking

Internationalization (i18n/locales/) ​

Translation files organized by language:

i18n/locales/
  β”œβ”€β”€ en/
  β”‚   β”œβ”€β”€ common.json
  β”‚   β”œβ”€β”€ employees.json
  β”‚   └── index.ts
  β”œβ”€β”€ es/
  β”‚   └── [same structure]
  └── he/
      └── [same structure]

See Internationalization β†’ for details.

Best Practices ​

Do's βœ…

  • Use _components for page-specific components
  • Give components unique names across the app
  • Use local types.ts for page-specific types
  • Optionally use explicit imports for clarity
  • Keep related files close together

Don'ts ❌

  • Don't duplicate component names in different _components folders
  • Don't create global types for page-specific data
  • Don't import composables/utils (they're auto-imported)
  • Don't put shared components in _components

Quick Reference ​

NeedLocationImport?
Reusable componentcomponents/❌ Auto
Page-specific componentpages/.../\_components/❌ Auto (optional explicit)
Composablecomposables/❌ Auto
Utility functionutils/❌ Auto
Shared typetypes/βœ… Manual
Page-specific typeLocal types.tsβœ… Manual
Layoutlayouts/❌ Via definePageMeta
Routepages/❌ File-based

Related: Routing & Navigation β†’ | UI Components β†’ | Composables β†’