---
alwaysApply: true
---
# Banco de Dados: Frontend → Remote Functions (SvelteKit) + Drizzle (Server)

Neste projeto, **o frontend NÃO se comunica diretamente com o banco**. Toda leitura/escrita no DB deve acontecer **no servidor**, usando **SvelteKit Remote Functions** (`*.remote.ts`) e **Drizzle ORM**.

## Regras obrigatórias

- **NUNCA** importe/instancie `db` ou tabelas do Drizzle no client:
  - Proibido em `.svelte`, `+page.ts`, `+layout.ts`, `src/lib/**` (código compartilhado) etc.
  - `db` e o schema (`$lib/server/db/**`) são **server-only**.
- Qualquer acesso ao DB deve ficar em **`*.remote.ts` co-localizado com a rota**.
- Remote functions devem:
  - Importar `query`, `command`, `form` de `$app/server`
  - Validar input com `z` de `zod/v4`
  - Usar Drizzle via `db` de `$lib/server/db` e tabelas de `$lib/server/db/schema`
- O frontend deve consumir **apenas** as remote functions, e usar:
  - `$derived(remoteQuery(args))` para promessas reativas
  - `.updates(remoteQuery(args))` após `command()`/`form()` para invalidar seletivamente

## Exemplo 1: Query (leitura) com Drizzle

```ts
// src/routes/admin/users/users.remote.ts
import { query } from '$app/server';
import z from 'zod/v4';
import { ilike, or } from 'drizzle-orm';

import { db } from '$lib/server/db';
import { user } from '$lib/server/db/schema';

export const listUsers = query(
	z.object({
		search: z.string().trim().min(1).optional()
	}),
	async ({ search }) => {
		const where =
			search
				? or(ilike(user.name, `%${search}%`), ilike(user.email, `%${search}%`))
				: undefined;

		return await db
			.select({
				id: user.id,
				name: user.name,
				email: user.email,
				createdAt: user.createdAt
			})
			.from(user)
			.where(where);
	}
);
```

## Exemplo 2: Command (mutação) com Drizzle + invalidação

```ts
// src/routes/admin/users/users.remote.ts
import { command } from '$app/server';
import z from 'zod/v4';
import { eq } from 'drizzle-orm';

import { db } from '$lib/server/db';
import { user } from '$lib/server/db/schema';

export const deleteUser = command(z.object({ id: z.string().min(1) }), async ({ id }) => {
	await db.delete(user).where(eq(user.id, id));
	// Se fizer sentido, você pode forçar refresh global da query para todos os clientes:
	// await listUsers({ search: undefined }).refresh();
});
```

## Exemplo 3: Form (submit) com Drizzle

```ts
// src/routes/admin/users/users.remote.ts
import { form } from '$app/server';
import z from 'zod/v4';
import { eq } from 'drizzle-orm';

import { db } from '$lib/server/db';
import { user } from '$lib/server/db/schema';

export const updateUserName = form(
	z.object({
		id: z.string().min(1),
		name: z.string().trim().min(2).max(100)
	}),
	async ({ id, name }) => {
		await db.update(user).set({ name }).where(eq(user.id, id));
		return { success: true as const };
	}
);
```

## Exemplo 4: Frontend consumindo remote functions (sem acesso ao DB)

```svelte
<!-- src/routes/admin/users/+page.svelte -->
<script lang="ts">
	import { listUsers, deleteUser, updateUserName } from './users.remote';

	let search = $state('');
	let usersPromise = $derived(listUsers({ search: search || undefined }));
</script>

<input bind:value={search} placeholder="Buscar por nome ou email" />

{#await usersPromise then users}
	<ul>
		{#each users as u}
			<li>
				<strong>{u.name}</strong> ({u.email})
				<button
					type="button"
					onclick={async () => {
						await deleteUser({ id: u.id }).updates(listUsers({ search: search || undefined }));
					}}
				>
					Remover
				</button>
			</li>
		{/each}
	</ul>
{/await}

<form
	{...updateUserName.enhance(async ({ submit }) => {
		await submit().updates(listUsers({ search: search || undefined }));
	})}
>
	<!-- inputs do updateUserName.fields.* -->
	<button type="submit">Salvar</button>
</form>
```

## Checklist rápido (antes de abrir PR)

- A leitura/escrita no DB está **somente** em `*.remote.ts`?
- O `.svelte` importa apenas remote functions (e não `db`/schema)?
- Inputs das remote functions estão validados com `zod/v4`?
- Mutação faz `.updates()` (ou `.refresh()` server-side) quando precisa atualizar listas?