Servidor Fastify + Socket.IO + Drizzle/Postgres; front Vite+React (EN/ES, tema claro/oscuro). Tableros por columnas con plantillas, notas privadas/públicas, agrupación, votos configurables (multivoto), timer compartido con alarma, fases, action items, export Markdown/JSON e import, autodestrucción, gestión de columnas. Imagen única (front servido por el servidor) y CI que la construye y publica.
97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import postgres from "postgres";
|
|
|
|
// DDL self-contained: crea la base de datos de test desde cero (idempotente).
|
|
const DDL = `
|
|
DROP TABLE IF EXISTS action_items, votes, notes, groups, columns, boards CASCADE;
|
|
|
|
CREATE TABLE boards (
|
|
id text PRIMARY KEY,
|
|
title text NOT NULL,
|
|
phase text NOT NULL DEFAULT 'writing',
|
|
revealed boolean NOT NULL DEFAULT false,
|
|
votes_revealed boolean NOT NULL DEFAULT false,
|
|
votes_per_user integer NOT NULL DEFAULT 3,
|
|
allow_multi_vote boolean NOT NULL DEFAULT true,
|
|
moderation_mode text NOT NULL DEFAULT 'everyone',
|
|
show_card_creators boolean NOT NULL DEFAULT true,
|
|
locked boolean NOT NULL DEFAULT false,
|
|
timer_ends_at timestamptz,
|
|
timer_running boolean NOT NULL DEFAULT false,
|
|
moderator_token text NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
expires_at timestamptz
|
|
);
|
|
|
|
CREATE TABLE columns (
|
|
id text PRIMARY KEY,
|
|
board_id text NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
|
|
title text NOT NULL,
|
|
position integer NOT NULL
|
|
);
|
|
|
|
CREATE TABLE groups (
|
|
id text PRIMARY KEY,
|
|
board_id text NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
|
|
column_id text NOT NULL REFERENCES columns(id) ON DELETE CASCADE,
|
|
title text NOT NULL DEFAULT '',
|
|
position double precision NOT NULL DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE notes (
|
|
id text PRIMARY KEY,
|
|
board_id text NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
|
|
column_id text NOT NULL REFERENCES columns(id) ON DELETE CASCADE,
|
|
group_id text REFERENCES groups(id) ON DELETE SET NULL,
|
|
author_id text NOT NULL,
|
|
author_name text NOT NULL,
|
|
text text NOT NULL,
|
|
color text,
|
|
revealed boolean NOT NULL DEFAULT false,
|
|
position double precision NOT NULL DEFAULT 0,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE votes (
|
|
board_id text NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
|
|
target_type text NOT NULL,
|
|
target_id text NOT NULL,
|
|
participant_id text NOT NULL,
|
|
count integer NOT NULL DEFAULT 1
|
|
);
|
|
CREATE UNIQUE INDEX votes_target_participant_uniq ON votes (target_id, participant_id);
|
|
|
|
CREATE TABLE action_items (
|
|
id text PRIMARY KEY,
|
|
board_id text NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
|
|
text text NOT NULL,
|
|
owner text,
|
|
done boolean NOT NULL DEFAULT false,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
`;
|
|
|
|
export async function setup() {
|
|
// globalSetup no recibe `test.env`; replicamos el default de vitest.config.ts.
|
|
const url =
|
|
process.env.TEST_DATABASE_URL ??
|
|
process.env.DATABASE_URL ??
|
|
"postgres://retro:retro@localhost:5433/retro_test";
|
|
// Asegura que exista la base de datos de test (crea retro_test si falta).
|
|
const dbName = new URL(url).pathname.slice(1);
|
|
const adminUrl = url.replace(`/${dbName}`, "/postgres");
|
|
const admin = postgres(adminUrl, { max: 1 });
|
|
try {
|
|
const exists = await admin`SELECT 1 FROM pg_database WHERE datname = ${dbName}`;
|
|
if (exists.length === 0) await admin.unsafe(`CREATE DATABASE ${dbName}`);
|
|
} finally {
|
|
await admin.end();
|
|
}
|
|
|
|
const sql = postgres(url, { max: 1 });
|
|
try {
|
|
await sql.unsafe(DDL);
|
|
} finally {
|
|
await sql.end();
|
|
}
|
|
}
|