Closes #578. Rewrites the user file library save-mode description in the English database.md and architecture.md guides (independent-new by default, parent-linked on overwrite) and updates all 20 translated copies of each, with i18n_source_hash re-stamped so the parity gate stays green.
7.5 KiB
description, i18n_source_hash, i18n_provenance, i18n_output_hash
| description | i18n_source_hash | i18n_provenance | i18n_output_hash |
|---|---|---|---|
| Esquema de la base de datos PostgreSQL, tablas, migraciones y procedimientos de copia de seguridad de SnapOtter. | 50d5d4f220cf | human | 70b4aa5ae152 |
Base de datos
SnapOtter usa PostgreSQL 17 con Drizzle ORM (pg-core / node-postgres) para la persistencia de datos. El esquema se define en apps/api/src/db/schema.ts.
La conexión se configura mediante la variable de entorno DATABASE_URL (por defecto postgres://snapotter:snapotter@postgres:5432/snapotter). En Docker Compose, el contenedor de Postgres almacena sus datos en el volumen con nombre SnapOtter-pgdata.
Tablas
users
Almacena las cuentas de usuario. Se crea automáticamente en el primer arranque a partir de DEFAULT_USERNAME y DEFAULT_PASSWORD.
| Columna | Tipo | Notas |
|---|---|---|
id |
uuid | Clave primaria |
username |
varchar | Único, obligatorio |
passwordHash |
varchar | hash scrypt |
role |
varchar | admin, editor o user |
mustChangePassword |
boolean | Indicador de restablecimiento de contraseña forzado |
createdAt |
timestamp | Momento de creación |
updatedAt |
timestamp | Momento de última actualización |
sessions
Sesiones de inicio de sesión activas. Cada fila vincula un token de sesión a un usuario.
| Columna | Tipo | Notas |
|---|---|---|
id |
varchar | Clave primaria (token de sesión) |
userId |
uuid | Clave foránea a users.id |
expiresAt |
timestamp | Momento de expiración |
createdAt |
timestamp | Momento de creación |
teams
Grupos para organizar usuarios. Los administradores pueden asignar usuarios a equipos.
| Columna | Tipo | Descripción |
|---|---|---|
id |
uuid | Clave primaria |
name |
varchar (único, máx. 50 caracteres) | Nombre del equipo |
createdAt |
timestamp | Momento de creación |
api_keys
Claves de API para acceso programático. La clave sin procesar se muestra una sola vez al crearla; solo se almacena el hash.
| Columna | Tipo | Notas |
|---|---|---|
id |
uuid | Clave primaria |
userId |
uuid | Clave foránea a users.id |
keyHash |
varchar | hash scrypt de la clave |
name |
varchar | Etiqueta proporcionada por el usuario |
createdAt |
timestamp | Momento de creación |
lastUsedAt |
timestamp | Actualizado en cada solicitud autenticada |
Las claves llevan el prefijo si_ seguido de 96 caracteres hexadecimales (48 bytes aleatorios).
pipelines
Cadenas de herramientas guardadas que los usuarios crean en la interfaz.
| Columna | Tipo | Notas |
|---|---|---|
id |
uuid | Clave primaria |
name |
varchar | Nombre del pipeline |
description |
varchar | Descripción opcional |
steps |
jsonb | Array de objetos { toolId, settings } |
createdAt |
timestamp | Momento de creación |
user_files
Biblioteca de archivos persistente. Una edición guardada se inserta de forma predeterminada como una fila raíz independiente ("guardar como nuevo": version 1, parentId null, de modo que el original sigue listado), o como una versión enlazada a su padre cuando sobrescribes el original (parentId establecido, version incrementado, reemplazándolo). La columna toolChain registra las herramientas aplicadas.
| Columna | Tipo | Descripción |
|---|---|---|
id |
uuid | Clave primaria |
userId |
uuid | FK a users (CASCADE DELETE) |
originalName |
varchar | Nombre de archivo original de la subida |
storedName |
varchar | Nombre de archivo en disco |
mimeType |
varchar | Tipo MIME |
size |
integer | Tamaño del archivo en bytes |
width |
integer | Ancho de la imagen en px |
height |
integer | Alto de la imagen en px |
version |
integer | Número de versión (1 = original) |
parentId |
uuid o null | FK a user_files (versión padre) |
toolChain |
jsonb | IDs de las herramientas aplicadas en orden para producir esta versión |
createdAt |
timestamp | Momento de creación |
jobs
Realiza el seguimiento de los trabajos de procesamiento para el reporte de progreso y la limpieza.
| Columna | Tipo | Notas |
|---|---|---|
id |
uuid | Clave primaria |
type |
varchar | Identificador de la herramienta o el pipeline |
status |
varchar | queued, processing, completed o failed |
progress |
real | Fracción de 0.0 a 1.0 |
inputFiles |
jsonb | Array de rutas de archivos de entrada |
outputPath |
varchar | Ruta al archivo de resultado |
settings |
jsonb | Ajustes de la herramienta utilizados |
error |
varchar | Mensaje de error si falló |
createdAt |
timestamp | Momento de creación |
completedAt |
timestamp | Momento de finalización |
settings
Almacén clave-valor para ajustes de todo el servidor que los administradores pueden cambiar desde la interfaz.
| Columna | Tipo | Notas |
|---|---|---|
key |
varchar | Clave primaria |
value |
varchar | Valor del ajuste |
updatedAt |
timestamp | Momento de última actualización |
roles
Roles personalizados con permisos granulares.
| Columna | Tipo | Notas |
|---|---|---|
id |
uuid | Clave primaria |
name |
varchar | Nombre de rol único |
description |
varchar | Descripción opcional |
permissions |
jsonb | Array de cadenas de permisos |
createdAt |
timestamp | Momento de creación |
audit_log
Registro de acciones relevantes para la seguridad.
| Columna | Tipo | Notas |
|---|---|---|
id |
uuid | Clave primaria |
userId |
uuid | FK a users |
action |
varchar | Tipo de acción |
details |
jsonb | Datos específicos de la acción |
createdAt |
timestamp | Momento de la acción |
Migraciones
Drizzle gestiona las migraciones del esquema. Los archivos de migración están en apps/api/drizzle/. Durante el desarrollo:
cd apps/api
npx drizzle-kit generate # generate a migration from schema changes
npx drizzle-kit migrate # apply pending migrations
En producción, las migraciones pendientes se aplican automáticamente al arrancar.
Copia de seguridad y restauración
La base de datos relacional reside en el volumen SnapOtter-pgdata del contenedor de Postgres, no en el volumen /data de la aplicación.
Opción 1: pg_dump (recomendada)
# Dump the database while the stack is running
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
# Restore into a fresh database
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
Opción 2: Instantánea del volumen
# Stop the stack, then snapshot the pgdata volume
docker compose down
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
Migrar desde 1.x (SQLite)
Actualizar desde SnapOtter 1.x tiene su propia guía: consulta Actualizar de 1.x a 2.0. En resumen, reutiliza tu volumen /data existente y 2.0 detecta e importa automáticamente /data/snapotter.db en el primer arranque (o define SQLITE_MIGRATE_PATH para apuntar a él explícitamente). Haz primero una copia de seguridad de todo el volumen /data, no solo de snapotter.db: 1.x usa el modo WAL de SQLite, por lo que un contenedor detenido suele dejar la mayor parte de sus datos en snapotter.db-wal junto a un snapotter.db casi vacío.