# Setup — SEO Insight (proto)

Tout ce qu'il faut savoir pour faire tourner le repo depuis un clone frais.

## Prérequis

- **bun** (runtime + package manager + test runner)
- **Rust toolchain** (`cargo`, `rustc`) + **wasm-pack** — pour le crate `crates/import-core` compilé en WASM
  ```bash
  cargo install wasm-pack
  ```
- **PostgreSQL** local (Homebrew `postgresql@18`, auth trust, user `humperdoo`)

## Premier setup (clone frais)

> ⚠️ **Le build WASM doit précéder `bun install`.** Le package `import-core` est une
> dépendance `file:` (`package.json` → `"import-core": "file:src/lib/backlink/import-core"`)
> qui pointe sur la **sortie de build wasm-pack**, laquelle est **gitignorée** (ce n'est
> pas du code source — la source est `crates/import-core/`). Donc sur un clone frais,
> `bun install` échoue tant que le dossier n'existe pas. Ordre obligatoire :

```bash
cargo install wasm-pack        # une fois
bun run build:wasm             # génère src/lib/backlink/import-core/ (gitignoré)
bun install                    # résout le file: dep une fois le build présent
```

> Après **chaque** modification du crate Rust, rebuild **et** réinstalle (le `file:` dep
> est copié dans `node_modules`, pas symlinké) :
> ```bash
> bun run build:wasm && bun install
> ```

## Base de données

Deux bases (cf. `.env` / `.env.test`) :
- `seo_insight_dev` (`.env`) — dev
- `seo_insight_test` (`.env.test`, chargée quand `NODE_ENV=test`) — tests

```bash
bun run db:migrate          # applique les migrations (dev)
bun run db:seed             # seed démo (org, sites, ~380 link sources, keywords)
# DB de test :
DATABASE_URL=postgresql://humperdoo@localhost:5432/seo_insight_test NODE_ENV=test bun run src/lib/db/migrate.ts
DATABASE_URL=postgresql://humperdoo@localhost:5432/seo_insight_test bun run src/lib/db/seed.ts
```

## Lancer / vérifier

```bash
bun run dev                 # Next 16 (Turbopack) sur :3000
bun run lint                # biome
cargo test -p import-core   # tests du crate Rust
bun test                    # tests unit (les tests DB sont skippés sans DB_TESTS=1)
```

### Tests DB — ⚠️ garde anti-prod

Les tests d'intégration DB font des `db.delete(...)`. Un garde `assertTestDb()`
(`src/lib/db/assert-test-db.ts`) **refuse toute base dont le nom ne finit pas par
`_test`**. Parce que `DATABASE_URL` est souvent **exportée dans l'environnement**
(pointant sur la dev), elle prime sur `.env.test` — il faut donc **forcer** l'URL test :

```bash
DATABASE_URL=postgresql://humperdoo@localhost:5432/seo_insight_test DB_TESTS=1 \
  bun test src/lib/sites src/lib/backlink src/lib/db
```
Ne **jamais** lancer un test DB sans cette URL : le garde throw, mais c'est le filet de
sécurité, pas le mode d'emploi.

## Architecture (rappel)

- **Reservoir import** : `crates/import-core` (Rust pur : parse CSV, normalize, `slug_id`
  path-aware, validate) → **WASM** (`wasm-bindgen` target `nodejs`, chargé in-process via
  `serverExternalPackages: ["import-core"]` dans `next.config.ts`) → server actions Next
  (`src/lib/backlink/import-actions.ts`) → persistance Drizzle (`upsertLinkSources`).
- Le crate est la **frontière stable** : un futur worker à file d'attente le réutilisera
  nativement.

## Différé (volontairement hors scope pour l'instant)

- **Worker / file d'attente** sur serveur séparé (le crate `import-core` est prêt à être
  réutilisé natif).
- **Role-gate owner/admin** du write reservoir — la session Better Auth n'alimente pas
  encore `getActiveOrgId()` / `getActiveUserId()` (stub `demo-org`/`seed-owner`).
- **id composite multi-org** : `link_sources.id` est un slug global (PK) ; deux orgs
  partageant une URL entreraient en collision. Des gardes org (`setWhere` sur l'upsert,
  filtres org sur les queries) sont déjà en place ; le passage à un id composite est à
  faire quand le multi-org réel arrivera.

Détails : `docs/superpowers/specs/2026-06-04-reservoir-import-design.md`.
