---
trigger: glob
globs: **/*.svelte.ts,**/*.svelte
---

# Convex + Svelte Best Practices

This document outlines the mandatory rules and best practices for integrating Convex with Svelte in this project.

## 1. Imports

Always use the following import paths. Do NOT use `$lib/convex` or relative paths for generated files unless specifically required by a local override.

### Correct Imports:

```typescript
import { useQuery, useConvexClient } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
import type { Id, Doc } from '@sgse-app/backend/convex/_generated/dataModel';
```

### Incorrect Imports (Avoid):

```typescript
import { convex } from '$lib/convex'; // Avoid direct client usage for queries
import { api } from '$lib/convex/_generated/api'; // Incorrect path
import { api } from '../convex/_generated/api'; // Relative path
```

## 2. Data Fetching

### Use `useQuery` for Reactivity

Instead of manually fetching data inside `onMount`, use the `useQuery` hook. This ensures your data is reactive and automatically updates when the backend data changes.

**Preferred Pattern:**

```svelte
<script lang="ts">
	import { useQuery } from 'convex-svelte';
	import { api } from '@sgse-app/backend/convex/_generated/api';

	const tasksQuery = useQuery(api.tasks.list, { status: 'pending' });
	const tasks = $derived(tasksQuery.data || []);
	const isLoading = $derived(tasksQuery.isLoading);
</script>
```

**Avoid Pattern:**

```svelte
<script lang="ts">
	import { onMount } from 'svelte';
	import { convex } from '$lib/convex';

	let tasks = [];

	onMount(async () => {
		// This is not reactive!
		tasks = await convex.query(api.tasks.list, { status: 'pending' });
	});
</script>
```

### Mutations

Use `useConvexClient` to access the client for mutations.

```svelte
<script lang="ts">
	import { useConvexClient } from 'convex-svelte';
	import { api } from '@sgse-app/backend/convex/_generated/api';

	const client = useConvexClient();

	async function completeTask(id) {
		await client.mutation(api.tasks.complete, { id });
	}
</script>
```

## 3. Type Safety

### No `any`

Strictly avoid using `any`. The Convex generated data model provides precise types for all your tables.

### Use Generated Types

Use `Doc<"tableName">` for full document objects and `Id<"tableName">` for IDs.

**Correct:**

```typescript
import type { Doc, Id } from '@sgse-app/backend/convex/_generated/dataModel';

let selectedTask: Doc<'tasks'> | null = $state(null);
let taskId: Id<'tasks'>;
```

**Incorrect:**

```typescript
let selectedTask: any = $state(null);
let taskId: string;
```

### Union Types for Enums

When dealing with status fields or other enums, define the specific union type instead of casting to `any`.

**Correct:**

```typescript
async function updateStatus(newStatus: 'pending' | 'completed' | 'archived') {
	// ...
}
```

**Incorrect:**

```typescript
async function updateStatus(newStatus: string) {
	// ...
	status: newStatus as any; // Avoid this
}
```
