Frontend Architecture
Overview
The frontend uses Inertia.js v3 with Svelte 5 for the public-facing site, and Filament v5 (server-rendered) for the admin panel. All Svelte code follows atomic design principles with a strict stores→services→api layering.
Technology Stack
| Technology | Version | Purpose |
|---|---|---|
| Svelte | 5 | Component framework (runes: $state, $derived, $effect) |
| Inertia.js | 3 | Server-driven SPA (no client-side routing) |
| Tailwind CSS | 4 | Utility-first styling |
| Lucide | Latest | Icon library |
| Vitest | Latest | Unit/integration testing |
| Playwright | Latest | E2E browser testing |
| TypeScript | 5 | Type safety |
Folder Structure
resources/js/
├── components/
│ └── landing/ # Atomic design components
│ ├── atoms/ # Smallest building blocks (Button, Input, Badge, etc.)
│ ├── molecules/ # Composed atoms (Card, Navigation, Pagination, etc.)
│ └── organisms/ # Composed molecules (Form, HeroHeader, MockupPreview, etc.)
├── layouts/ # Svelte layouts (landing, unauthorized, etc.)
├── lib/ # Shared utilities
│ ├── i18n.svelte.ts # Internationalization (i18next)
│ ├── styles/ # Tailwind class constants
│ ├── utils.ts # Utility functions (cn, sanitize, etc.)
│ ├── state.ts # StateContainer pattern definition
│ └── localization.ts # Localized value resolution
├── modules/ # Feature modules
│ └── landing/
│ ├── setup/ # Setup wizard module
│ └── .../ # Other feature modules
└── pages/ # Inertia page components
└── landing/ # Public pagesAtomic Design
atoms/ → Button, Input, Badge, Icon, Modal, Steps, Dropdown, etc.
molecules/ → Card, Navigation, Pagination, MainCard, Mockup, Timeline, etc.
organisms/ → Form, HeroHeader, MockupPreview, SelectorCard, etc.Rules:
- Atoms are presentational only — no business logic, no store imports
- Molecules combine atoms — minimal logic, accept props/callbacks
- Organisms combine molecules — still presentational, may have internal UI state only
- Modules contain all business logic — stores, services, API calls
Store Pattern (stores→services→api)
Every data flow follows this chain:
Component (subscribe + call action)
↓
Store (StateContainer<TData> — manages state)
↓
Service (pure functions — business logic)
↓
API (HTTP fetch — typed endpoints)Module Structure
module/
├── Index.svelte # Entry point — minimal, no logic
├── api/ # API fetch functions
├── parts/ # Sub-components
├── services/ # Business logic
├── stores/ # State management
│ └── entry/ # Store groups with barrel index.ts
├── types/ # TypeScript interfaces
└── __tests__/ # Vitest testsKey Conventions
| Convention | Rule |
|---|---|
| Store files | <action>-<module>.stores.ts |
| Service files | <module>.service.ts |
| API files | <module>.api.ts |
| Naming (FE) | camelCase (firstName) |
| Naming (API) | snake_case (first_name) |
| State shape | StateContainer<TData> from @/types/state |
| Components | NO fetch(), NO SSE, NO business logic |
Key Files
| File | Purpose |
|---|---|
resources/js/app.ts | Svelte app entry point + Inertia setup |
resources/js/lib/i18n.svelte.ts | i18n initialization and t() function |
resources/js/lib/state.ts | StateContainer<TData> type definitions |
resources/js/types/state.ts | StateMeta, StateErrors, createState() |
vite.config.ts | Vite + Inertia + Wayfinder configuration |
tailwind.config.ts | Tailwind CSS v4 configuration |