nexus-5-frontend-3/CLAUDE.md
2026-01-26 11:30:40 -05:00

178 lines
4.6 KiB
Markdown

# Claude Code Guidelines
## Project Overview
This is a SvelteKit 2.x application using Svelte 5 with Tailwind CSS v4.
## Code Style Rules
### SVG Attributes
When using SVG elements, use `style` attribute instead of `fill` attribute to avoid IDE obsolete attribute warnings:
```svelte
<!-- Correct -->
<svg style="fill: currentColor" ...>
<svg style="fill: none" ...>
<!-- Incorrect (triggers obsolete attribute warning) -->
<svg fill="currentColor" ...>
<svg fill="none" ...>
```
### Svelte 5 Runes
- Use `$state()` for reactive state
- Use `$derived()` for computed values
- Use `$props()` for component props
- Use `$effect()` for side effects
### Page Store
Use `$app/state` instead of `$app/stores` for the page object:
```svelte
<!-- Correct -->
import {page} from '$app/state'; const path = page.url.pathname;
<!-- Incorrect -->
import {page} from '$app/stores'; const path = $page.url.pathname;
```
### Theme Classes
Use the custom theme utility classes defined in `layout.css`:
- `text-theme`, `text-theme-secondary`, `text-theme-muted`
- `bg-theme`, `bg-theme-card`
- `border-theme`
- `shadow-theme`, `shadow-theme-lg`
### Hover/Active States
Use consistent hover/active patterns:
```
hover:bg-black/5 dark:hover:bg-white/10
active:bg-black/10 dark:active:bg-white/15
```
### Mobile Grid Layouts
For card grids that should display single-column on mobile and multi-column on larger screens, always:
1. Explicitly set `grid-cols-1` (don't rely on CSS grid's implicit single column)
2. Add `min-w-0` on grid items with flex content to allow proper shrinking
```svelte
<!-- Correct -->
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div class="card-example flex min-w-0 items-center justify-between">
<div class="min-w-0 flex-1">...</div>
</div>
</div>
<!-- Incorrect (may overflow on mobile) -->
<div class="grid gap-4 sm:grid-cols-2">
<div class="card-example flex items-center justify-between">...</div>
</div>
```
### Button Element Content
Button elements can only contain phrasing content (inline elements). Use `<span>` instead of `<div>`, `<p>`, or `<h1>`-`<h6>` inside buttons:
```svelte
<!-- Correct -->
<button>
<span class="flex items-center gap-2">
<span>Click me</span>
</span>
</button>
<!-- Incorrect (triggers HTML validation warning) -->
<button>
<div class="flex items-center gap-2">
<p>Click me</p>
</div>
</button>
```
For multi-line button content, use `<span class="block">` to create line breaks:
```svelte
<button>
<span class="flex items-center gap-2">Title</span>
<span class="text-muted block text-sm">Subtitle on new line</span>
</button>
```
### SvelteSet Reactivity
`SvelteSet` from `svelte/reactivity` is already reactive and does NOT need to be wrapped in `$state()`:
```svelte
<!-- Correct -->
import { SvelteSet } from 'svelte/reactivity';
let expandedItems = new SvelteSet<string>();
<!-- Incorrect (unnecessary wrapper) -->
let expandedItems = $state(new SvelteSet<string>());
```
### Each Block Keys
Always provide a key for `{#each}` blocks to avoid ESLint warnings:
```svelte
<!-- Correct -->
{#each items as item (item.id)}
{#each days as day (day)}
<!-- Incorrect -->
{#each items as item}
```
### Date Formatting
Use the date utilities from `$lib/utils/date` which use `date-fns` to properly handle ISO date strings without timezone offset issues:
```svelte
import {formatDate} from '$lib/utils/date';
<!-- Returns empty string for null/undefined, so add fallback -->
{formatDate(startDate) || '—'}
```
### File Organization
- Place `.svelte.ts` files (stores, shared state) in `src/lib/stores/`, not in component folders
- GraphQL mutations go in `src/lib/graphql/mutations/{entity}/`
- GraphQL queries go in `src/lib/graphql/queries/{entity}/`
### Backend Integration Notes
- The backend uses a unique constraint allowing only ONE active scope per address
- The `isConditional` field on tasks is legacy and should always be set to `false`
- GraphQL inputs use camelCase (e.g., `isActive`, `accountId`) which maps to snake_case in Django
### Task Frequency Values
The backend `TaskFrequencyChoices` enum uses **lowercase** values. Handle frequency differently depending on the operation:
**Individual mutations** (create/update task or task template) - use lowercase:
```typescript
frequency: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'triannual' | 'annual' | 'as_needed';
```
**JSON import** (`createScopeTemplateFromJson`) - uppercase is acceptable:
```json
{ "frequency": "DAILY" }
```
The backend's `build_scope_template` service normalizes uppercase to lowercase automatically.
Valid frequency values: `daily`, `weekly`, `monthly`, `quarterly`, `triannual`, `annual`, `as_needed`