SnapOtter używa PostgreSQL 17 z [Drizzle ORM](https://orm.drizzle.team/) (pg-core / node-postgres) do trwałego przechowywania danych. Schemat jest zdefiniowany w `apps/api/src/db/schema.ts`.
Połączenie konfiguruje się za pomocą zmiennej środowiskowej `DATABASE_URL` (domyślnie `postgres://snapotter:snapotter@postgres:5432/snapotter`). W Docker Compose kontener Postgres przechowuje swoje dane w nazwanym wolumenie `SnapOtter-pgdata`.
## Tabele {#tables}
### users {#users}
Przechowuje konta użytkowników. Tworzone automatycznie przy pierwszym uruchomieniu na podstawie `DEFAULT_USERNAME` i `DEFAULT_PASSWORD`.
| Kolumna | Typ | Uwagi |
|---|---|---|
| `id` | uuid | Klucz główny |
| `username` | varchar | Unikalna, wymagana |
| `passwordHash` | varchar | Hash scrypt |
| `role` | varchar | `admin`, `editor` lub `user` |
Trwała biblioteka plików. Zapisana edycja jest domyślnie wstawiana jako niezależny wiersz główny („zapisz jako nowy": `version` 1, `parentId` null, więc oryginał pozostaje na liście) albo jako wersja powiązana z rodzicem, gdy nadpisujesz oryginał (`parentId` ustawiony, `version` zwiększony, zastępując go). Kolumna `toolChain` zapisuje zastosowane narzędzia.
Stan interfejsu dla poszczególnych użytkowników, kluczowany nazwą preferencji. Przechowuje przypięte narzędzia strony głównej, zapisywane przez `PUT /api/v1/preferences`.
| Kolumna | Typ | Uwagi |
|---|---|---|
| `userId` | text | Klucz obcy do users, kasowanie kaskadowe. Razem z `key` tworzy klucz główny |
| `key` | text | Nazwa preferencji. Razem z `userId` tworzy klucz główny |
Ten zrzut bazy danych nie zawiera zapisanych obiektów biblioteki w `/data/files` ani trwałego stanu BullMQ w Redis. Utwórz kopię zapasową i przywróć te dane, stosując skoordynowaną procedurę w [Bezpieczeństwo i wzmacnianie](/pl/guide/security#backup-and-recovery).
Nie kopiuj aktywnego katalogu danych PostgreSQL za pomocą `tar`. Twórz przedrostki nazw woluminów według projektu, więc rozpoznaj identyfikatory zamontowanych woluminów z `docker inspect` lub platformy pamięci masowej, zamiast przyjmować dosłowną etykietę `SnapOtter-pgdata`.
### Migracja z 1.x (SQLite) {#migrating-from-1-x-sqlite}
Aktualizacja z SnapOtter 1.x ma własny przewodnik: zobacz [Aktualizacja z 1.x do 2.0](./upgrading). W skrócie, użyj ponownie istniejącego wolumenu `/data`, a 2.0 automatycznie wykryje i zaimportuje `/data/snapotter.db` przy pierwszym uruchomieniu (lub ustaw `SQLITE_MIGRATE_PATH`, aby wskazać go jawnie). Najpierw utwórz kopię zapasową całego wolumenu `/data`, a nie tylko `snapotter.db`: 1.x używa trybu SQLite WAL, więc zatrzymany kontener często pozostawia większość swoich danych w `snapotter.db-wal` obok niemal pustego `snapotter.db`.