feat: FlowDeck v0.2.0 — Kanban Gitea intégré
- 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
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user