Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 68 additions & 112 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,75 +22,6 @@ This is a TypeScript monorepo using a Convex backend and SvelteKit frontend with
- `packages/client/` - SvelteKit frontend with Tauri integration
- `packages/convex/` - Convex backend with database schema and functions

## Development Commands

### Setup

```bash
bun install --frozen-lockfile
```

### Development Servers

```bash
# Main development (Convex + Web Client)
bun dev

# All development servers including Storybook
bun dev:all

# Individual servers
bun dev:web # Web client at http://localhost:5173
bun dev:convex # Convex at http://localhost:3210, Dashboard at http://localhost:6790
bun dev:storybook # Storybook at http://localhost:6006
bun dev:tauri # Desktop app (conflicts with web client)
```

### Building and Testing

```bash
# Build all apps
bun run --filter=* build

# Run tests
bun test

# Type checking and linting
bun check # Runs lint + format + all app checks
bun check:lint # Biome linting only
bun check:format # Prettier formatting check only

# Auto-fix
bun fix # Auto-fix lint + format issues
bun fix:lint # Biome auto-fix
bun fix:format # Prettier auto-format
```

### Convex Operations

```bash
# Convex CLI commands
bun convex [command]

# Code generation (run after schema changes)
bun sync
```

### Internationalization

```bash
# Compile i18n messages
bun paraglide
```

## Code Architecture

### Svelte Documentation

When working with Svelte code, always reference the latest documentation:

- **Latest Svelte Docs**: https://svelte.dev/llms-small.txt

### Frontend (SvelteKit)

- **Routes**: Standard SvelteKit routing in `packages/client/src/routes/`
Expand All @@ -100,9 +31,33 @@ When working with Svelte code, always reference the latest documentation:
- `@@` → `../..` (workspace root)
- `$components` → `src/components`
- `~` → `src/`
- `@packages/{package}` → monorepo
- **Convex Integration**: Uses `convex-svelte` for reactive queries
- **State Pattern**: Logic components (e.g., TaskList.svelte) separate from presentation (TaskListSkin.svelte)

### Backend (Convex)

- **Schema**: Defined in `packages/convex/src/convex/schema.ts`
- **Functions**: Database operations in `packages/convex/src/convex/[feature].ts`
- **Type Safety**: Auto-generated types from schema shared with frontend via workspace dependency

### Data Flow

1. Convex schema defines database structure
2. Convex functions provide type-safe CRUD operations
3. Frontend uses `convex-svelte` hooks for reactive data
4. Automatic type generation ensures type safety across stack

## Framework - Convex

### Convex の Import について

```ts
import { api, type Id } from "@packages/convex";

// use api and type Id ...
```

### 注意点: convex-svelte の `useQuery` について

`useQuery` に渡す引数は、関数の形式で渡してください。そうでないと、期待しない動作を引き起こす可能性があります。
Expand Down Expand Up @@ -141,60 +96,61 @@ createOrganization.processing; // boolean, use for button disabled state / loadi
createOrganization.error; // string | null, use for error messages
```

### Backend (Convex)

- **Schema**: Defined in `packages/convex/src/convex/schema.ts`
- **Functions**: Database operations in `packages/convex/src/convex/[feature].ts`
- **Type Safety**: Auto-generated types from schema shared with frontend via workspace dependency

### Data Flow
## Framework - Svelte

1. Convex schema defines database structure
2. Convex functions provide type-safe CRUD operations
3. Frontend uses `convex-svelte` hooks for reactive data
4. Automatic type generation ensures type safety across stack
### Syntax

## Code Quality
Never use logacy svelte syntax. This project uses Svelte 5 runes mode.

### Linting and Formatting
- ❌ FORBIDDEN: `$: reactiveVar = ...` (reactive statements)
- ❌ FORBIDDEN: `let count = 0` for reactive state
- ✅ REQUIRED: `let count = $state(0)` for reactive state
- ✅ REQUIRED: `$effect(() => { ... })` for side effects
- ✅ REQUIRED: `const sum = $derived(a + b);` for derived variables
- ✅ REQUIRED: `const sum = $derived.by(() => { if (a + b < 0) return 0; return a + b; );` for derived variables which needs a block.

- **Biome**: Primary linter with strict rules
- **Prettier**: Code formatting (Biome formatter disabled)
- **Lefthook**: Pre-commit hooks for code generation and formatting
### Svelte Capabilities

### Special Biome Rules
- clsx: Svelte has clsx builtin to its class. `<div class={["text-lg", isError && "text-error"]}>{text}</div>`

- Svelte files have relaxed rules for unused variables/imports
- Convex files exempt from import extension requirements
- Strict style rules including parameter assignment, const assertions
- reactive class: Svelte allows defining reactive controller classes inside ".svelte.ts" files for reusability and separation of concerns.

### Pre-commit Hooks

- Automatic code generation (`bun sync`)
- Automatic formatting (`bun fix:format`)
```ts
// my-controller.svelte.ts
class MyController {
foo = $state(3);
bar: number;
baz = $derived.by(() => bar + baz); // use derived.by if it needs to be lazy-initialized
doubleQux: number;
// unless it doesn't change at runtime (e.g. static configuration - initBar in this example),
// using getter function is better for reactivity.
constructor(initBar: number, props: () => { qux: number }) {
this.bar = $state(initBar);
this.doubleQux = $derived(props().qux * 2);
}
}
```

## Tauri Desktop App
## Code Quality / Coding Rules

Tauri integration requires separate development workflow:
### Common Rules

```bash
# Start backend first
bun dev:convex
- FILE LENGTH: Prefer short files, 30 ~ 50 lines recommended, 100 lines MAX.
- CHECK: Always run `bun check` after writing code.
- DOCUMENTATION: document the behavior (and optionally the expected usage) of the code, not the implementation

# Then start Tauri (in separate terminal)
bun dev:tauri
```
### Svelte

Tauri conflicts with the web development server and requires more resources for compilation.
- NAMING: Name snippets with camelCase instead of PascalCase to avoid confusion with components.
- ALIAS: Use TypeScript import alias for client code. `import component from "~/features/foo/component.svelte";`
- STYLING: Don't use style blocks in Svelte components, instead use TailwindCSS and DaisyUI.
- STYLING: Always prefer using DaisyUI classes, and use minimal Tailwind classes.
- SEPARATE COMPONENTS: Separate components into smallest pieces for readability.
- SEPARATE LOGIC: Separate Logic from .svelte files into .svelte.ts files.
- .svelte.ts files should handle Calculation / Reactivity, while .svelte files should handle UI changes (e.g. navigation, modal open).
- if it has any reusable utility function, it should be separated again into plain .ts files / .svelte.ts
- An Ideal import tree would look like this: `UI component [.svelte] -> controller [.svelte.ts] -> processor [.svelte.ts] -> pure logic utility [.ts]`

## Coding Instructions
### Convex Rules

- **🚫 NEVER USE LEGACY SVELTE SYNTAX**: This project uses Svelte 5 runes mode
- ❌ FORBIDDEN: `$: reactiveVar = ...` (reactive statements)
- ❌ FORBIDDEN: `let count = 0` for reactive state
- ✅ REQUIRED: `const reactiveVar = $derived(...)`
- ✅ REQUIRED: `let count = $state(0)` for reactive state
- ✅ REQUIRED: `$effect(() => { ... })` for side effects
- Always prefer using DaisyUI classes, and use minimal Tailwind classes.
- Separate components into smallest pieces for readability.
- Name snippets with camelCase instead of PascalCase to avoid confusion with components.
- AUTHORIZATION: write authorization determinator in `packages/convex/src/convex/perms.ts`
Loading