--- 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 {#await usersPromise then users}