Initial commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
// Standalone DB initializer (run with: npm run db:init)
|
||||
import 'dotenv/config';
|
||||
import db from './index.js';
|
||||
|
||||
console.log('SQLite database initialized.');
|
||||
console.log(`Tables: ${db
|
||||
.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
|
||||
.all()
|
||||
.map(r => r.name)
|
||||
.join(', ')}`);
|
||||
|
||||
db.close();
|
||||
@@ -0,0 +1,253 @@
|
||||
-- =====================================================================
|
||||
-- Crowdlending Tracker - SQLite schema
|
||||
-- =====================================================================
|
||||
-- Conventions:
|
||||
-- * Monetary amounts: REAL (cents-level precision OK for personal use)
|
||||
-- * Dates: TEXT in ISO 8601 (YYYY-MM-DD) for stable sort & SQLite date()
|
||||
-- * All tables use AUTOINCREMENT-free INTEGER PK (rowid alias)
|
||||
-- * created_at/updated_at: TEXT ISO timestamp, set by app
|
||||
-- =====================================================================
|
||||
|
||||
PRAGMA foreign_keys = ON;
|
||||
PRAGMA journal_mode = WAL;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- USERS (login accounts)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
display_name TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- INVESTISSEURS (profils d'investissement sous un même login)
|
||||
-- Ex.: "Monsieur", "Madame", "SCI Croguennec", "PEA-PME", ...
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS investisseurs (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
nom TEXT NOT NULL, -- nom complet (famille) ou raison sociale (entreprise)
|
||||
prenom TEXT, -- prénom (famille uniquement)
|
||||
type TEXT NOT NULL DEFAULT 'famille'
|
||||
CHECK(type IN ('famille','entreprise')),
|
||||
type_fiscal TEXT, -- 'PP', 'PM', 'SCI', 'SCPI'...
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE(user_id, nom)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_investisseurs_user ON investisseurs(user_id);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- PLATEFORMES (ClubFunding, October, Lendix, La Première Brique, ...)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS plateformes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
nom TEXT NOT NULL,
|
||||
url TEXT,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
domiciliation TEXT NOT NULL DEFAULT 'france',
|
||||
fiscalite TEXT NOT NULL DEFAULT 'flat_tax',
|
||||
taux_fiscalite_locale REAL,
|
||||
methode_remboursement TEXT NOT NULL DEFAULT 'portefeuille',
|
||||
investisseur_id INTEGER REFERENCES investisseurs(id) ON DELETE SET NULL,
|
||||
date_ouverture TEXT,
|
||||
logo_filename TEXT,
|
||||
UNIQUE(user_id, nom, investisseur_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_plateformes_user ON plateformes(user_id);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- DEPOTS_RETRAITS (mouvements de cash sur les plateformes)
|
||||
-- type: 'depot' (versement) | 'retrait' (retrait)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS depots_retraits (
|
||||
id INTEGER PRIMARY KEY,
|
||||
investisseur_id INTEGER NOT NULL REFERENCES investisseurs(id) ON DELETE CASCADE,
|
||||
plateforme_id INTEGER NOT NULL REFERENCES plateformes(id) ON DELETE RESTRICT,
|
||||
date_operation TEXT NOT NULL, -- ISO YYYY-MM-DD
|
||||
type TEXT NOT NULL CHECK(type IN ('depot','retrait')),
|
||||
montant REAL NOT NULL CHECK(montant >= 0),
|
||||
libelle TEXT,
|
||||
reference TEXT, -- ref bancaire / plateforme
|
||||
source TEXT NOT NULL DEFAULT 'manuel', -- 'manuel' | 'import_excel'
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_depret_inv ON depots_retraits(investisseur_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_depret_plat ON depots_retraits(plateforme_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_depret_date ON depots_retraits(date_operation);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- INVESTISSEMENTS (CF Investissements - liste des projets souscrits)
|
||||
-- statut: 'en_cours' | 'rembourse' | 'en_retard' | 'procedure' | 'cloture'
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS investissements (
|
||||
id INTEGER PRIMARY KEY,
|
||||
investisseur_id INTEGER NOT NULL REFERENCES investisseurs(id) ON DELETE CASCADE,
|
||||
plateforme_id INTEGER NOT NULL REFERENCES plateformes(id) ON DELETE RESTRICT,
|
||||
nom_projet TEXT NOT NULL,
|
||||
emetteur TEXT, -- nom de la société emprunteuse
|
||||
date_souscription TEXT NOT NULL,
|
||||
date_premiere_echeance TEXT, -- date de la 1ère échéance (intérêts / remboursement)
|
||||
date_cible TEXT, -- date contractuelle du dernier versement (calculée)
|
||||
montant_investi REAL NOT NULL CHECK(montant_investi > 0),
|
||||
taux_interet REAL, -- en % annuel (ex. 9.5)
|
||||
duree_mois INTEGER,
|
||||
type_remb TEXT, -- 'in_fine' | 'amortissable' | 'differe'
|
||||
freq_interets TEXT NOT NULL DEFAULT 'mensuel', -- 'mensuel' | 'trimestriel' | 'in_fine'
|
||||
statut TEXT NOT NULL DEFAULT 'en_cours'
|
||||
CHECK(statut IN ('en_cours','rembourse','en_retard','procedure','cloture')),
|
||||
reference TEXT, -- ID projet sur la plateforme
|
||||
source TEXT NOT NULL DEFAULT 'manuel',
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_inv_inv ON investissements(investisseur_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_inv_plat ON investissements(plateforme_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_inv_statut ON investissements(statut);
|
||||
CREATE INDEX IF NOT EXISTS idx_inv_date ON investissements(date_souscription);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- REMBOURSEMENTS (échéances perçues, réelles)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS remboursements (
|
||||
id INTEGER PRIMARY KEY,
|
||||
investissement_id INTEGER NOT NULL REFERENCES investissements(id) ON DELETE CASCADE,
|
||||
date_remb TEXT NOT NULL,
|
||||
capital REAL NOT NULL DEFAULT 0,
|
||||
interets_bruts REAL NOT NULL DEFAULT 0, -- intérêts AVANT prélèvements
|
||||
prelev_sociaux REAL NOT NULL DEFAULT 0, -- 17.2 % typiquement
|
||||
prelev_forfaitaire REAL NOT NULL DEFAULT 0, -- 12.8 % (PFU IR)
|
||||
cashback REAL NOT NULL DEFAULT 0, -- remboursement non taxé (bonus plateforme, etc.)
|
||||
interets_nets REAL NOT NULL DEFAULT 0, -- interets_bruts - prelev_sociaux - prelev_forfaitaire
|
||||
net_recu REAL NOT NULL DEFAULT 0, -- capital + cashback + interets_nets
|
||||
statut TEXT NOT NULL DEFAULT 'paye'
|
||||
CHECK(statut IN ('paye','retard','partiel','impaye')),
|
||||
source TEXT NOT NULL DEFAULT 'manuel',
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_remb_inv ON remboursements(investissement_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_remb_date ON remboursements(date_remb);
|
||||
CREATE INDEX IF NOT EXISTS idx_remb_statut ON remboursements(statut);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- SIMUL_REMBOURSEMENTS (échéances prévisionnelles / théoriques)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS simul_remboursements (
|
||||
id INTEGER PRIMARY KEY,
|
||||
investissement_id INTEGER NOT NULL REFERENCES investissements(id) ON DELETE CASCADE,
|
||||
numero_echeance INTEGER NOT NULL,
|
||||
date_prevue TEXT NOT NULL,
|
||||
capital_prevu REAL NOT NULL DEFAULT 0,
|
||||
interets_prevus REAL NOT NULL DEFAULT 0,
|
||||
total_prevu REAL NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE(investissement_id, numero_echeance)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_simul_inv ON simul_remboursements(investissement_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_simul_date ON simul_remboursements(date_prevue);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- IMPORTS (historique des imports Excel pour traçabilité)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS imports (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
investisseur_id INTEGER REFERENCES investisseurs(id) ON DELETE SET NULL,
|
||||
module TEXT NOT NULL, -- 'depots_retraits' | 'investissements' | ...
|
||||
filename TEXT NOT NULL,
|
||||
rows_total INTEGER NOT NULL DEFAULT 0,
|
||||
rows_inserted INTEGER NOT NULL DEFAULT 0,
|
||||
rows_skipped INTEGER NOT NULL DEFAULT 0,
|
||||
mapping_json TEXT, -- JSON: mappage colonnes
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_imports_user ON imports(user_id);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- CATEGORIES_PLATEFORME (tags libres associés à une plateforme)
|
||||
-- Semées par défaut à la première utilisation (voir route /categories)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS categories_plateforme (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
nom TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE(user_id, nom)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_catplat_user ON categories_plateforme(user_id);
|
||||
|
||||
-- Junction : une plateforme peut avoir plusieurs catégories
|
||||
CREATE TABLE IF NOT EXISTS plateforme_categories (
|
||||
plateforme_id INTEGER NOT NULL REFERENCES plateformes(id) ON DELETE CASCADE,
|
||||
categorie_id INTEGER NOT NULL REFERENCES categories_plateforme(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY(plateforme_id, categorie_id)
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- TAUX_PFU (historique Flat Tax France — table de référence globale)
|
||||
-- ---------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS taux_pfu (
|
||||
id INTEGER PRIMARY KEY,
|
||||
annee INTEGER NOT NULL UNIQUE,
|
||||
pfu_total REAL NOT NULL, -- ex. 30.0
|
||||
impot_revenu REAL NOT NULL, -- ex. 12.8
|
||||
prelev_sociaux REAL NOT NULL, -- ex. 17.2
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_pfu_annee ON taux_pfu(annee);
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- VUES utiles
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
-- Solde courant par (investisseur, plateforme)
|
||||
CREATE VIEW IF NOT EXISTS v_solde_plateforme AS
|
||||
SELECT
|
||||
dr.investisseur_id,
|
||||
dr.plateforme_id,
|
||||
SUM(CASE WHEN dr.type='depot' THEN dr.montant ELSE 0 END) AS total_depots,
|
||||
SUM(CASE WHEN dr.type='retrait' THEN dr.montant ELSE 0 END) AS total_retraits,
|
||||
SUM(CASE WHEN dr.type='depot' THEN dr.montant
|
||||
WHEN dr.type='retrait' THEN -dr.montant END) AS solde_net
|
||||
FROM depots_retraits dr
|
||||
GROUP BY dr.investisseur_id, dr.plateforme_id;
|
||||
|
||||
-- Synthèse investissements par investisseur
|
||||
CREATE VIEW IF NOT EXISTS v_synthese_inv AS
|
||||
SELECT
|
||||
i.investisseur_id,
|
||||
COUNT(*) AS nb_projets,
|
||||
SUM(i.montant_investi) AS total_investi,
|
||||
SUM(CASE WHEN i.statut='en_cours' THEN i.montant_investi ELSE 0 END) AS encours,
|
||||
SUM(CASE WHEN i.statut='rembourse' THEN i.montant_investi ELSE 0 END) AS rembourse,
|
||||
SUM(CASE WHEN i.statut IN ('en_retard','procedure') THEN i.montant_investi ELSE 0 END) AS en_defaut
|
||||
FROM investissements i
|
||||
GROUP BY i.investisseur_id;
|
||||
|
||||
-- Intérêts perçus par année (pour le 2778-SD)
|
||||
CREATE VIEW IF NOT EXISTS v_interets_annuels AS
|
||||
SELECT
|
||||
i.investisseur_id,
|
||||
substr(r.date_remb,1,4) AS annee,
|
||||
SUM(r.interets_bruts) AS interets_bruts,
|
||||
SUM(r.prelev_sociaux) AS prelev_sociaux,
|
||||
SUM(r.prelev_forfaitaire) AS prelev_forfaitaire,
|
||||
SUM(r.net_recu) AS net_recu
|
||||
FROM remboursements r
|
||||
JOIN investissements i ON i.id = r.investissement_id
|
||||
WHERE r.statut IN ('paye','partiel')
|
||||
GROUP BY i.investisseur_id, substr(r.date_remb,1,4);
|
||||
Reference in New Issue
Block a user