diff --git a/.cursor/rules/db-remote-functions-drizzle.mdc b/.cursor/rules/db-remote-functions-drizzle.mdc
new file mode 100644
index 0000000..92798cb
--- /dev/null
+++ b/.cursor/rules/db-remote-functions-drizzle.mdc
@@ -0,0 +1,143 @@
+---
+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}
+
+ {#each users as u}
+
+ {u.name} ({u.email})
+
+
+ {/each}
+
+{/await}
+
+
+```
+
+## 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?
\ No newline at end of file
diff --git a/.cursor/rules/migrations.mdc b/.cursor/rules/migrations.mdc
new file mode 100644
index 0000000..4414831
--- /dev/null
+++ b/.cursor/rules/migrations.mdc
@@ -0,0 +1,28 @@
+---
+globs: src/lib/server/db/schema.ts
+description: Fluxo de migrações ao editar o schema do banco de dados
+---
+
+## Fluxo obrigatório ao alterar [schema.ts](mdc:src/lib/server/db/schema.ts)
+
+Sempre que realizar edits em `src/lib/server/db/schema.ts`, execute este fluxo de migrações:
+
+1. Empurrar alterações usando uma base de teste local (porta 5433):
+
+```bash
+DATABASE_URL=postgres://postgres:postgres@localhost:5433/saas_test_db bun run drizzle-kit push
+```
+
+2. Sincronizar a base padrão do projeto:
+
+```bash
+bun run db:push
+```
+
+3. Aviso para commits na branch `main`:
+
+Antes de abrir PR/commit para `main`, gere os artefatos do Drizzle:
+
+```bash
+bun run db:generate
+```
diff --git a/.cursor/rules/svelte-async.mdc b/.cursor/rules/svelte-async.mdc
new file mode 100644
index 0000000..b4ebda0
--- /dev/null
+++ b/.cursor/rules/svelte-async.mdc
@@ -0,0 +1,116 @@
+---
+description: Guia detalhado de uso do modo experimental async no Svelte 5
+alwaysApply: false
+---
+# Guia: Modo Async Experimental no Svelte 5
+
+Este documento detalha como utilizar o modo `experimental.async` ativado neste projeto.
+
+## 🛠 Como Habilitar
+
+Já está configurado no seu `svelte.config.js`:
+
+```javascript
+compilerOptions: {
+ experimental: {
+ async: true;
+ }
+}
+```
+
+## 📖 Regras de Uso
+
+### 1. Top-Level Await
+
+Agora você pode usar `await` diretamente no seu `
+
+
{data.message}
+```
+
+### 2. $derived Assíncrono
+
+Valores derivados podem aguardar promessas. Eles se tornam reativos: se uma dependência dentro do `$derived` mudar, a promessa é disparada novamente e o valor é atualizado automaticamente.
+
+**✅ Exemplo:**
+
+```javascript
+let id = $state(1);
+let user = $derived(await getUser(id));
+```
+
+### 3. Estados de Carregamento (Loading)
+
+Como o componente "suspende", precisamos de uma forma de mostrar que algo está carregando.
+
+- **Para o carregamento inicial:** Use ``.
+- **Para atualizações reativas:** Use `$effect.pending()`.
+
+```svelte
+
+
+ {#snippet pending()}
+
Carregando dados iniciais...
+ {/snippet}
+
+```
+
+---
+
+## 🚫 O que NÃO fazer
+
+### ❌ Async no $effect
+
+O Svelte não permite `async` diretamente em `$effect`. Se precisar de lógica assíncrona lá, use uma IIFE (Immediately Invoked Function Expression).
+
+**Errado:**
+
+```javascript
+$effect(async () => {
+ await doSomething();
+});
+```
+
+**Correto:**
+
+```javascript
+$effect(() => {
+ (async () => {
+ await doSomething();
+ })();
+});
+```
+
+### ❌ Evite Loops de Suspensão
+
+Não use `await` em valores que mudam muitas vezes por segundo, pois isso fará o componente entrar e sair do estado de "pending" constantemente, prejudicando a UX.
+
+---
+
+## 🔗 Integração com Remote Functions
+
+Este projeto usa `remoteFunctions`. A melhor forma de usá-las com o modo async é:
+
+```svelte
+
+
+{#if $effect.pending()}
+
+{/if}
+
+{#each items as item}
+
{item.name}
+{/each}
+```
diff --git a/.cursor/rules/svelte-guide.mdc b/.cursor/rules/svelte-guide.mdc
new file mode 100644
index 0000000..588af37
--- /dev/null
+++ b/.cursor/rules/svelte-guide.mdc
@@ -0,0 +1,28 @@
+---
+trigger: glob
+globs: *.svelte,*.svelte.ts
+---
+
+You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
+
+## Available MCP Tools:
+
+### 1. list-sections
+
+Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths.
+When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections.
+
+### 2. get-documentation
+
+Retrieves full documentation content for specific sections. Accepts single or multiple sections.
+After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task.
+
+### 3. svelte-autofixer
+
+Analyzes Svelte code and returns problems and suggestions.
+You MUST use this tool whenever you write Svelte code before submitting it to the user. Keep calling it until no problems or suggestions are returned. Remember that this does not eliminate all lint errors, so still keep checking for lint errors before proceeding.
+
+### 4. playground-link
+
+Generates a Svelte Playground link with the provided code.
+After completing the code, ask the user if they want a playground link. Only call this tool after user confirmation and NEVER if code was written to files in their project.
\ No newline at end of file
diff --git a/.cursor/rules/svelte-remote-functions.mdc b/.cursor/rules/svelte-remote-functions.mdc
new file mode 100644
index 0000000..4e8101b
--- /dev/null
+++ b/.cursor/rules/svelte-remote-functions.mdc
@@ -0,0 +1,145 @@
+---
+alwaysApply: true
+---
+# Svelte Remote Functions (Experimental)
+
+This project uses SvelteKit's experimental `remoteFunctions` feature. Follow these rules when working with server-side logic and data fetching.
+
+## 1. Definition & Structure
+
+- Logic MUST be defined in `*.remote.ts` files co-located with the route.
+- Import `form`, `query`, and `command` from `$app/server`.
+- Import `z` from `zod/v4`.
+
+## 2. Creating Remote Functions
+
+### Queries (Data Fetching)
+
+Use `query` for reading data. It behaves like a GET request.
+
+```typescript
+import { query } from '$app/server';
+import z from 'zod/v4';
+
+export const getData = query(z.object({ id: z.string() }), async ({ id }) => {
+ return await db.select(...);
+});
+```
+
+### Commands (Mutations)
+
+Use `command` for direct logic execution (RPC style), typically for actions like delete, toggle, or specific updates.
+
+```typescript
+import { command } from '$app/server';
+
+export const deleteItem = command(z.string(), async (id) => {
+ await db.delete(...);
+});
+```
+
+### Forms (Form Submissions)
+
+Use `form` for handling HTML form submissions with progressive enhancement and field validation.
+
+```typescript
+import { form } from '$app/server';
+
+export const updateItem = form(schema, async (data) => {
+ await db.update(...);
+ return { success: true };
+});
+```
+
+## 3. Frontend Usage
+
+### Reactivity with Queries
+
+Queries can be called inside `$derived` to create reactive promises that update when their arguments change.
+
+```svelte
+
+
+{#await itemsPromise then items}
+
+ {#each items as item}
+ ...
+ {/each}
+
+{/await}
+```
+
+### Executing Commands & Invalidating Data
+
+Commands are called as functions. To refresh relevant data after a command finishes, use the `.updates()` method and pass it the query call that should be refreshed.
+
+```svelte
+
+
+
+```
+
+### Using Forms
+
+Use `.enhance` on the form object. You can also use `.updates()` on the `submit()` result.
+
+```svelte
+
+```
+
+## 4. Invalidation Patterns
+
+### Client-Side (Selective)
+
+Use `.updates(queryCall())` on the mutation result in the frontend. This is preferred for fine-grained updates.
+
+### Server-Side (Global for that file)
+
+You can refresh queries directly in the remote function definition in `data.remote.ts`:
+
+```typescript
+export const deleteItem = command(z.string(), async (id) => {
+ await db.delete(...);
+ // Refresh listItems query for all clients
+ await listItems().refresh();
+});
+```
+
+### Global Refresh
+
+If logic requires a full page refresh (all loaders), use `refreshAll()` from `$app/navigation`.
+
+```typescript
+import { refreshAll } from '$app/navigation';
+// ...
+await myCommand();
+await refreshAll();
+```
diff --git a/.vscode/settings.json b/.vscode/settings.json
index bc31e15..c5c1f12 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,31 @@
{
- "files.associations": {
- "*.css": "tailwindcss"
- }
-}
+ "eslint.useFlatConfig": true,
+ "eslint.workingDirectories": [
+ {
+ "pattern": "apps/*"
+ },
+ {
+ "pattern": "packages/*"
+ }
+ ],
+ "eslint.validate": [
+ "javascript",
+ "typescript",
+ "svelte"
+ ],
+ "eslint.options": {
+ "cache": true,
+ "cacheLocation": ".eslintcache"
+ },
+ "editor.formatOnSave": true,
+ "[typescript]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "[jsonc]": {
+ "editor.defaultFormatter": "vscode.json-language-features"
+ },
+ "[svelte]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
+ },
+ "editor.tabSize": 2
+}
\ No newline at end of file