# Architecture

## Goals

1. **Domain isolation** – every business capability is a self-contained module.
2. **Predictability** – a single, consistent place to find a feature's UI,
   state, types, services, hooks, and data.
3. **Server-first** – favor React Server Components; opt into client only when
   needed.
4. **Replaceability** – the dummy data layer can be flipped off the moment
   real APIs are live, without touching components.

---

## Layering

```
┌──────────────────────────────────────────────────────────────┐
│  src/app/                                                    │
│  Routes, layouts, metadata. NO business logic.               │
│  Each page.tsx is a thin import of a feature component.      │
└──────────────────────────────────────────────────────────────┘
                       │  composes
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  src/features/{feature}/                                     │
│  Business code. Self-contained: components, services, store, │
│  types, data, hooks, utils.                                  │
│  ❌ Features must NOT import from each other directly.       │
│     Cross-feature reuse goes via src/shared/.                │
└──────────────────────────────────────────────────────────────┘
                       │  uses
                       ▼
┌──────────────────────────────────────────────────────────────┐
│  src/shared/                                                 │
│  Generic UI primitives, lib helpers, types. Zero domain code.│
└──────────────────────────────────────────────────────────────┘
```

### Allowed dependencies

```
app    →  features  →  shared
                ↘   shared
                   features  ✗  (forbidden)
```

If feature A needs something feature B owns, **lift it to `shared/`**.

---

## Feature folder layout

```
src/features/{feature}/
├── components/        # Feature UI (incl. admin/ subfolder if applicable)
├── hooks/             # use{Feature}() and friends
├── services/          # {feature}Api.ts – HTTP calls
├── store/             # Zustand slice(s)
├── types/             # {feature}.types.ts
├── data/              # dummy.ts – fallback data
└── utils/             # Feature-only helpers
```

Not every feature needs every folder. Only create what's used.

---

## Components & rendering

* Default to **Server Components** in `src/app/`.
* Mark interactivity with `'use client'` at the top of files that need:
  hooks, state, refs, browser APIs, or 3rd-party client libs.
* Keep page files thin – they should usually just import a feature component
  and add metadata.
* If a component grows beyond ~150 lines, extract sub-components and a
  `useXxx()` hook into the same feature.

### Admin panel composition

```
src/app/admin/layout.tsx
   └── <AdminLayout> (features/admin/components/AdminLayout.tsx)
            └── {children}   ← page content from
                              features/{feature}/components/admin/*
```

The admin layout owns the sidebar, top bar, breadcrumbs, and chrome.
Each domain module supplies its own admin pages under
`features/{feature}/components/admin/`.

---

## State management

* **Zustand**, one store slice per feature, lives at
  `src/features/{feature}/store/{feature}Store.ts`.
* Provide **selector hooks** (e.g. `useVehicleList`, `useCurrentUser`) so
  components only re-render when their slice changes.
* Avoid a global "master" store. Cross-feature coordination happens through
  shared types or events.
* For server-derived data, prefer fetching via the feature's hook
  (`useVehicles()`) which itself wraps the store + service.

---

## Styling

* **Tailwind CSS v4** is the primary styling layer. Design tokens live in
  CSS variables in `src/styles/theme.css`.
* `src/styles/admin.css` contains the admin layout utility classes
  (`.admin-main`, `.admin-stat-grid`, etc.).
* `src/app/globals.css` aggregates everything and is the single CSS entry
  point imported by `src/app/layout.tsx`.
* The `cn()` helper from `@/shared/lib/utils` should be used everywhere a
  conditional className is needed.

### shadcn/ui

shadcn primitives live at `src/shared/components/ui/`. They are part of the
codebase (not an npm package) and may be edited freely. They import `cn` from
the local `./utils` re-export.

### MUI

MUI is used in a few specialised admin views. Prefer shadcn for new work;
reach for MUI only when a complex primitive is genuinely required.

---

## Data flow

```
Component → Hook (useVehicles) → Store (vehiclesStore)
                                    │
                                    ▼
                     Service (vehiclesApi.listVehicles)
                                    │
                                    ▼
                  api.get() → fetch() → /api/vehicles
                                    │  (failure)
                                    ▼
                      withDummyFallback → DUMMY_VEHICLES
```

Every list / detail call uses `withDummyFallback` so the UI is resilient
during the build-out phase.

---

## Imports

```ts
// ✅ Feature-internal
import { vehiclesApi } from './services/vehiclesApi';

// ✅ Cross-feature consumption goes through shared
import { Button }    from '@/shared/components/ui/button';
import { cn }        from '@/shared/lib/utils';
import { api }       from '@/shared/lib/api';

// ❌ Never import directly between features
// import { Vehicle } from '@/features/vehicles/types/vehicle.types'  ← FROM features/orders/* is forbidden
```

When orders genuinely need vehicles' types, the right move is to widen
`src/shared/types/` with the cross-cutting type, not to add a feature→feature
import.

---

## Conventions

* File naming: `kebab-case.ts(x)` for utilities/data, `PascalCase.tsx` for
  components, `useThing.ts` for hooks.
* Service files end in `Api.ts`. Type files end in `.types.ts`.
* Feature stores end in `Store.ts`. Selector hooks live next to the store.
* Public/visitor pages live under `src/app/(shop)/`. Admin pages under
  `src/app/admin/`. Auth pages would live under `src/app/(auth)/` (not yet
  implemented).
* All money values stored as integers in their smallest unit on the wire
  (yen for JPY) and formatted at the edge via `formatJPY` / `formatUSD`.
