diff --git a/.agent/rules/convex-svelte-guidelines.md b/.agent/rules/convex-svelte-guidelines.md new file mode 100644 index 0000000..f61e324 --- /dev/null +++ b/.agent/rules/convex-svelte-guidelines.md @@ -0,0 +1,275 @@ +--- +trigger: glob +globs: **/*.svelte, **/*.ts, **/*.svelte.ts +--- + +# Convex + Svelte Guidelines + +## Overview + +These guidelines describe how to write **Convex** backend code **and** consume it from a **Svelte** (SvelteKit) frontend. The syntax for Convex functions stays exactly the same, but the way you import and call them from the client differs from a React/Next.js project. Below you will find the adapted sections from the original Convex style guide with Svelte‑specific notes. + +--- + +## 1. Function Syntax (Backend) + +> **No change** – keep the new Convex function syntax. + +```typescript +import { + query, + mutation, + action, + internalQuery, + internalMutation, + internalAction +} from './_generated/server'; +import { v } from 'convex/values'; + +export const getUser = query({ + args: { userId: v.id('users') }, + returns: v.object({ name: v.string(), email: v.string() }), + handler: async (ctx, args) => { + const user = await ctx.db.get(args.userId); + if (!user) throw new Error('User not found'); + return { name: user.name, email: user.email }; + } +}); +``` + +--- + +## 2. HTTP Endpoints (Backend) + +> **No change** – keep the same `convex/http.ts` file. + +```typescript +import { httpRouter } from 'convex/server'; +import { httpAction } from './_generated/server'; + +const http = httpRouter(); + +http.route({ + path: '/api/echo', + method: 'POST', + handler: httpAction(async (ctx, req) => { + const body = await req.bytes(); + return new Response(body, { status: 200 }); + }) +}); +``` + +--- + +## 3. Validators (Backend) + +> **No change** – keep the same validators (`v.string()`, `v.id()`, etc.). + +--- + +## 4. Function Registration (Backend) + +> **No change** – use `query`, `mutation`, `action` for public functions and `internal*` for private ones. + +--- + +## 5. Function Calling from **Svelte** + +### 5.1 Install the Convex client + +```bash +npm i convex @convex-dev/convex-svelte +``` + +> The `@convex-dev/convex-svelte` package provides a thin wrapper that works with Svelte stores. + +### 5.2 Initialise the client (e.g. in `src/lib/convex.ts`) + +```typescript +import { createConvexClient } from '@convex-dev/convex-svelte'; + +export const convex = createConvexClient({ + url: import.meta.env.VITE_CONVEX_URL // set in .env +}); +``` + +### 5.3 Using queries in a component + +```svelte + + +{#if loading} +

Loading…

+{:else if error} +

{error}

+{:else if user} +

{user.name}

+

{user.email}

+{/if} +``` + +### 5.4 Using mutations in a component + +```svelte + + + + +{#if error}

{error}

{/if} +``` + +### 5.5 Using **actions** (Node‑only) from Svelte + +Actions run in a Node environment, so they cannot be called directly from the browser. Use a **mutation** that internally calls the action, or expose a HTTP endpoint that triggers the action. + +--- + +## 6. Scheduler / Cron (Backend) + +> Same as original guide – define `crons.ts` and export the default `crons` object. + +--- + +## 7. File Storage (Backend) + +> Same as original guide – use `ctx.storage.getUrl()` and query `_storage` for metadata. + +--- + +## 8. TypeScript Helpers (Backend) + +> Keep using `Id<'table'>` from `./_generated/dataModel`. + +--- + +## 9. Svelte‑Specific Tips + +| Topic | Recommendation | +| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| **Store‑based data** | If you need reactive data across many components, wrap `convex.query` in a Svelte store (`readable`, `writable`). | +| **Error handling** | Use `try / catch` around every client call; surface the error in the UI. | +| **SSR / SvelteKit** | Calls made in `load` functions run on the server; you can use `convex.query` there without worrying about the browser environment. | +| **Environment variables** | Prefix with `VITE_` for client‑side access (`import.meta.env.VITE_CONVEX_URL`). | +| **Testing** | Use the Convex mock client (`createMockConvexClient`) provided by `@convex-dev/convex-svelte` for unit tests. | + +--- + +## 10. Full Example (SvelteKit + Convex) + +### 10.1 Backend (`convex/users.ts`) + +```typescript +import { mutation, query } from './_generated/server'; +import { v } from 'convex/values'; + +export const createUser = mutation({ + args: { name: v.string() }, + returns: v.id('users'), + handler: async (ctx, args) => { + return await ctx.db.insert('users', { name: args.name }); + } +}); + +export const getUser = query({ + args: { userId: v.id('users') }, + returns: v.object({ name: v.string() }), + handler: async (ctx, args) => { + const user = await ctx.db.get(args.userId); + if (!user) throw new Error('Not found'); + return { name: user.name }; + } +}); +``` + +### 10.2 Frontend (`src/routes/+page.svelte`) + +```svelte + + + + +{#if createdId}

Created user id: {createdId}

{/if} +{#if error}

{error}

{/if} +``` + +--- + +## 11. Checklist for New Files + +- ✅ All Convex functions use the **new syntax** (`query({ … })`). +- ✅ Every public function has **argument** and **return** validators. +- ✅ Svelte components import the generated `api` object from `convex/_generated/api`. +- ✅ All client calls use the `convex` instance from `$lib/convex`. +- ✅ Environment variable `VITE_CONVEX_URL` is defined in `.env`. +- ✅ Errors are caught and displayed in the UI. +- ✅ Types are imported from `convex/_generated/dataModel` when needed. + +--- + +## 12. References + +- Convex Docs – [Functions](https://docs.convex.dev/functions) +- Convex Svelte SDK – [`@convex-dev/convex-svelte`](https://github.com/convex-dev/convex-svelte) +- SvelteKit Docs – [Loading Data](https://kit.svelte.dev/docs/loading) + +--- + +_Keep these guidelines alongside the existing `svelte-rules.md` so that contributors have a single source of truth for both frontend and backend conventions._