# Mini-projet — FareMarks
Gestionnaire de bookmarks taggés.
Pour découvrir Prisma, Supabase, server actions Next 16, TanStack Form, Zod, Biome, Shadcn, Sonner.
Commit quand ça te semble adapté (à chaque étape par exemple)
---
## Prérequis
Node 24, [`pnpm`](https://pnpm.io/installation), compte Supabase, éditeur de code au choix (je recommande [Zed](https://zed.dev/)) avec extension Biome.
---
## Setup
### 1. Créer le projet
```bash
pnpm create next-app@latest faremarks
cd faremarks
```
TS oui, ESLint **non**, Tailwind oui, `src/` oui, App Router oui, Turbopack
oui, alias `@/*` oui.
### 2. Dépendances
```bash
pnpm add @prisma/client @tanstack/react-form zod sonner nuqs clsx \
tailwind-merge class-variance-authority lucide-react
pnpm add -D prisma @biomejs/biome tsx
```
### 3. Biome
[biomejs.dev](https://biomejs.dev/)
```bash
pnpm biome init
```
Remplace `biome.json` par [Annexe A](#annexe-a--biomejson). Test :
`pnpm biome check --write`.
### 4. Shadcn
[ui.shadcn.com](https://ui.shadcn.com/)
```bash
# Initialise shadcn, avec les styles et paramètres par défaut
pnpm dlx shadcn@latest init
# Commence par ajouter quelques composants, tu pourras en ajouter plus tard si besoin
pnpm dlx shadcn@latest add button card input textarea label badge dialog sonner
```
Style Default, Neutral, CSS variables oui.
### 5. Supabase
[supabase.com](https://supabase.com)
**Accueil > Get Connected > ORM** :
- **Transaction pooler** (port 6543) → `DATABASE_URL`
- **Direct connection** (port 5432) → `DIRECT_URL`
### 6. `.env`
Voir [Annexe B](#annexe-b--env). Ajoute `.env` à `.gitignore` si pas déjà dedans.
### 7. Prisma
```bash
pnpm prisma init
```
Remplace `prisma/schema.prisma` :
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
model Bookmark {
id String @id @default(cuid())
url String
title String
createdAt DateTime @default(now())
}
```
```bash
pnpm prisma migrate dev --name init
```
### 8. Client Prisma — `src/lib/prisma.ts`
```ts
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
```
> Cela évite de créer N instances en dev (hot reload).
### 9. Providers — `src/app/layout.tsx`
[sonner.emilkowal.ski](https://sonner.emilkowal.ski/)
[nuqs.dev](https://nuqs.47ng.com/)
```tsx
import { NuqsAdapter } from "nuqs/adapters/next/app";
import { Toaster } from "@/components/ui/sonner";
// dans le
, enveloppe {children} :
{children}
```
### 10. Run
```bash
pnpm dev
```
---
## Étape 1 — CRUD minimal
À construire :
- `src/app/page.tsx` (Server Component) : liste les bookmarks + form +
bouton delete par item
- `src/actions/bookmarks/create.ts` (server action) — voir [Annexe C](#annexe-c--squelette-server-action)
- `src/actions/bookmarks/delete.ts` (même pattern, prend `id`)
- `src/components/BookmarkForm.tsx` (Client) — voir [Annexe D](#annexe-d--squelette-client-form)
- `src/components/DeleteButton.tsx` (Client, `startTransition` + toast)
Schéma Zod déclaré côté server action, types importés côté client via
`import type`. Toast vert au succès, rouge en erreur.
Docs : [TanStack Form](https://tanstack.com/form/latest)
· [Zod v4](https://zod.dev/)
---
## Étape 2 — Enrichir le modèle
Ajoute au modèle `Bookmark` :
```prisma
description String?
updatedAt DateTime @updatedAt
```
```bash
pnpm prisma migrate dev --name add_description_and_updated_at
```
Lis le SQL généré dans `prisma/migrations/`.
À faire : champ description (Textarea) dans le form + feature édition
(modale `