docs: restructure AGENTS.md into hierarchical knowledge base
This commit is contained in:
parent
157cbc425e
commit
470d49b061
3 changed files with 339 additions and 47 deletions
132
frontend/AGENTS.md
Normal file
132
frontend/AGENTS.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# Frontend
|
||||
|
||||
SvelteKit 2 + Svelte 5 (Runes) web UI. Adapter: `@sveltejs/adapter-node` (required for form actions).
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
frontend/src/
|
||||
├── app.css # Tailwind v4 theme + editorial design system (1420 lines)
|
||||
├── app.html # HTML shell (Cormorant Infant + Manrope fonts)
|
||||
├── hooks.server.ts # Paraglide i18n middleware
|
||||
├── routes/ # SvelteKit file-based routing
|
||||
│ ├── +layout.svelte # App shell, sidebar, mobile drawer, domain-based theming
|
||||
│ ├── +page.svelte # Dashboard (routines, snapshots, lab results)
|
||||
│ ├── products/ # List, [id] detail/edit, new, suggest (AI)
|
||||
│ ├── routines/ # List, [id] detail/edit, new, suggest (AI), grooming-schedule/
|
||||
│ ├── health/ # medications/ (list, new), lab-results/ (list, new)
|
||||
│ ├── skin/ # Snapshots list, new (with photo analysis)
|
||||
│ └── profile/ # User profile
|
||||
└── lib/
|
||||
├── api.ts # Typed fetch wrappers (server: PUBLIC_API_BASE, browser: /api)
|
||||
├── types.ts # TypeScript types mirroring backend models (manual sync)
|
||||
├── utils.ts # cn() class merger, bits-ui types
|
||||
├── utils/ # forms.ts (preventIfNotConfirmed), skin-display.ts (label helpers)
|
||||
├── paraglide/ # Generated i18n runtime — DO NOT EDIT
|
||||
└── components/
|
||||
├── ui/ # bits-ui primitives: button, card, badge, input, label, select, tabs, table, separator
|
||||
├── forms/ # DRY helpers: SimpleSelect, GroupedSelect, HintCheckbox, LabeledInputField, FormSectionCard, form-classes.ts
|
||||
├── product-form/ # Sectioned form: Basic, Details, Classification, Assessment, Notes
|
||||
├── PageHeader.svelte # Reusable page header (kicker, title, subtitle, backlink, actions via snippets)
|
||||
├── ProductForm.svelte # Main product form (tabbed, 737 lines)
|
||||
├── ProductFormAiModal.svelte # AI text-to-product parsing modal
|
||||
├── FlashMessages.svelte # Error/success/warning/info alerts
|
||||
├── StructuredErrorDisplay.svelte # Parses semicolon-separated backend errors into list
|
||||
├── ValidationWarningsAlert.svelte # LLM validation warnings display
|
||||
├── ReasoningChainViewer.svelte # AI reasoning chain viewer (collapsible)
|
||||
├── MetadataDebugPanel.svelte # Token metrics, model info (collapsible)
|
||||
├── AutoFixBadge.svelte # Auto-fix indicator
|
||||
└── LanguageSwitcher.svelte # i18n locale toggle
|
||||
```
|
||||
|
||||
## Design System
|
||||
|
||||
**MUST READ**: `docs/frontend-design-cookbook.md` — update when introducing new UI patterns.
|
||||
|
||||
- **Typography**: `Cormorant Infant` (display/headings), `Manrope` (body/UI).
|
||||
- **Colors**: CSS variables in `app.css`. Domain accents per route: products (green), routines (cyan), skin (orange), profile (blue), health-labs (purple), health-meds (teal).
|
||||
- **Layout wrappers**: `.editorial-page`, `.editorial-hero`, `.editorial-panel`, `.editorial-toolbar`, `.editorial-backlink`, `.editorial-alert`.
|
||||
- **Page header**: Use `PageHeader.svelte` for consistent title hierarchy, backlinks, and actions.
|
||||
- **Accent rule**: ~10-15% of visual area. Never full backgrounds or body text.
|
||||
- **Motion**: Short purposeful reveals. Always respect `prefers-reduced-motion`.
|
||||
|
||||
## Route Patterns
|
||||
|
||||
Every page: `+page.svelte` (UI) + `+page.server.ts` (load + actions).
|
||||
|
||||
Load functions fetch from API, return data:
|
||||
```typescript
|
||||
export const load: PageServerLoad = async () => {
|
||||
const data = await getProducts();
|
||||
return { products: data };
|
||||
};
|
||||
```
|
||||
|
||||
Form actions parse FormData, call API, return result or `fail()`:
|
||||
```typescript
|
||||
export const actions = {
|
||||
default: async ({ request }) => {
|
||||
const form = await request.formData();
|
||||
try {
|
||||
const result = await createProduct(payload);
|
||||
return { success: true, product: result };
|
||||
} catch (e) {
|
||||
return fail(500, { error: (e as Error).message });
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Component Conventions
|
||||
|
||||
- Prefer `SimpleSelect` / `GroupedSelect` over bits-ui `ui/select` unless search/rich popup UX needed.
|
||||
- Use `form-classes.ts` tokens (`baseSelectClass`, `baseTextareaClass`) for consistent form styling.
|
||||
- Svelte 5 runes: `$props()`, `$state()`, `$derived()`, `$effect()`, `$bindable()`.
|
||||
- Snippet-based composition in `PageHeader` (actions, meta, children snippets).
|
||||
- Compound components: Card → CardHeader, CardContent, CardFooter, etc.
|
||||
|
||||
## i18n
|
||||
|
||||
- Source messages: `frontend/messages/{en,pl}.json`.
|
||||
- Generated runtime: `src/lib/paraglide/` (via Vite plugin).
|
||||
- Import: `import * as m from '$lib/paraglide/messages.js'`.
|
||||
- **No hardcoded English labels.** Use `m.*` keys. Add new keys to message files if needed.
|
||||
- Fallback display: use `m.common_unknown()` not hardcoded `n/a`.
|
||||
|
||||
## API Client
|
||||
|
||||
`src/lib/api.ts` — typed fetch wrappers.
|
||||
|
||||
```typescript
|
||||
const base = browser ? "/api" : PUBLIC_API_BASE;
|
||||
// Browser: /api (nginx proxies, strips prefix to backend)
|
||||
// Server-side (SSR): PUBLIC_API_BASE (http://localhost:8000)
|
||||
```
|
||||
|
||||
Methods: `api.get<T>()`, `api.post<T>()`, `api.patch<T>()`, `api.del()`.
|
||||
File upload: `analyzeSkinPhotos()` uses FormData (not JSON).
|
||||
Error handling: throws `Error` with `.detail` from backend response.
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Default | Set at |
|
||||
|----------|---------|--------|
|
||||
| `PUBLIC_API_BASE` | `http://localhost:8000` | Build time |
|
||||
|
||||
Production: `PUBLIC_API_BASE=http://innercontext.lan/api pnpm build`.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
pnpm dev # Dev server (API proxied to :8000)
|
||||
pnpm check # Type check + Svelte validation
|
||||
pnpm lint # ESLint
|
||||
pnpm format # Prettier
|
||||
pnpm build # Production build → build/
|
||||
```
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- No frontend tests exist. Only linting + type checking.
|
||||
- ESLint `svelte/no-navigation-without-resolve` has `ignoreGoto: true` workaround (upstream bug sveltejs/eslint-plugin-svelte#1327).
|
||||
- `src/paraglide/` is a legacy output path — active i18n output is in `src/lib/paraglide/`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue