- Dashboard projets Gitea (user + orgs) - Board Kanban 5 colonnes avec drag & drop (SortableJS) - Sync bidirectionnelle colonnes ↔ labels Gitea - Filtres milestone/label/assignee - Notes Markdown par projet - API REST (/api/health, /api/move, /api/col-mapping…) - Colonnes custom, WIP limits - Thème clair/sombre - Cache Gitea TTL - Docker + docker-compose - Tests pytest - Docs: README, ARCHITECTURE, CHANGELOG, ROADMAP
80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
"""FlowDeck — Database layer (SQLite with WAL mode)."""
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
from contextlib import contextmanager
|
|
from pathlib import Path
|
|
|
|
|
|
def get_db_path() -> Path:
|
|
from app.config import settings
|
|
return settings.db_path
|
|
|
|
|
|
def init_db():
|
|
"""Create tables if they don't exist."""
|
|
db_path = get_db_path()
|
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with get_conn() as conn:
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
conn.execute("PRAGMA foreign_keys=ON")
|
|
conn.executescript("""
|
|
CREATE TABLE IF NOT EXISTS boards (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
project_owner TEXT NOT NULL,
|
|
project_name TEXT NOT NULL,
|
|
columns_json TEXT NOT NULL DEFAULT '["Backlog","À faire","En cours","Révision","Terminé"]',
|
|
wip_limits_json TEXT DEFAULT '{}',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(project_owner, project_name)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS cards (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
board_id INTEGER NOT NULL REFERENCES boards(id),
|
|
gitea_issue_id INTEGER,
|
|
column_name TEXT NOT NULL DEFAULT 'Backlog',
|
|
position INTEGER NOT NULL DEFAULT 0,
|
|
priority TEXT DEFAULT 'Medium',
|
|
due_date TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS notes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
project_owner TEXT NOT NULL,
|
|
project_name TEXT NOT NULL,
|
|
title TEXT NOT NULL DEFAULT 'Notes',
|
|
content TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(project_owner, project_name, title)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS col_mapping (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
board_id INTEGER NOT NULL REFERENCES boards(id),
|
|
column_name TEXT NOT NULL,
|
|
gitea_label TEXT NOT NULL,
|
|
close_issue BOOLEAN NOT NULL DEFAULT 0,
|
|
UNIQUE(board_id, column_name)
|
|
);
|
|
""")
|
|
conn.commit()
|
|
|
|
|
|
@contextmanager
|
|
def get_conn():
|
|
"""Yield a SQLite connection (WAL mode, foreign keys on)."""
|
|
db_path = get_db_path()
|
|
conn = sqlite3.connect(str(db_path))
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
conn.execute("PRAGMA foreign_keys=ON")
|
|
try:
|
|
yield conn
|
|
finally:
|
|
conn.close()
|