4.6 KiB
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:
<!-- 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:
<!-- 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-mutedbg-theme,bg-theme-cardborder-themeshadow-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:
- Explicitly set
grid-cols-1(don't rely on CSS grid's implicit single column) - Add
min-w-0on grid items with flex content to allow proper shrinking
<!-- 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:
<!-- 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:
<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():
<!-- 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:
<!-- 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:
import {formatDate} from '$lib/utils/date';
<!-- Returns empty string for null/undefined, so add fallback -->
{formatDate(startDate) || '—'}
File Organization
- Place
.svelte.tsfiles (stores, shared state) insrc/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
isConditionalfield on tasks is legacy and should always be set tofalse - 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:
frequency: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'triannual' | 'annual' | 'as_needed';
JSON import (createScopeTemplateFromJson) - uppercase is acceptable:
{ "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