Appearance
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 assetsAuto-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 utilitiesPage-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.vueComponent 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 # β
UniqueOptional 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 declarationsLocal 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 pageWhen 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.tsUsage:
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 helpersUsage:
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 layoutUsage 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 middlewarePlugins (plugins/) β
App-wide plugins:
plugins/
βββ api.ts # API setup ($api, $apiFetch)
βββ focus.ts # Focus management
βββ maska.ts # Input maskingInternationalization (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
_componentsfor page-specific components - Give components unique names across the app
- Use local
types.tsfor page-specific types - Optionally use explicit imports for clarity
- Keep related files close together
Don'ts β
- Don't duplicate component names in different
_componentsfolders - 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 β
| Need | Location | Import? |
|---|---|---|
| Reusable component | components/ | β Auto |
| Page-specific component | pages/.../\_components/ | β Auto (optional explicit) |
| Composable | composables/ | β Auto |
| Utility function | utils/ | β Auto |
| Shared type | types/ | β Manual |
| Page-specific type | Local types.ts | β Manual |
| Layout | layouts/ | β Via definePageMeta |
| Route | pages/ | β File-based |
Related: Routing & Navigation β | UI Components β | Composables β