Add multi-account support
- Schema: account_id FK on checks and layout_fields; UNIQUE per-account on check_no and field_name - DB: runtime migration recreates both tables to add account_id (assigns existing rows to account 1) - Routes: GET /api/accounts lists all; GET /api/account/:id replaces hardcoded id=1; POST /api/account/setup always creates a new account and returns accountId - checks.js: all queries scoped by account_id; POST requires account_id in body - pdf.js: resolves account from check's account_id instead of id=1; layout fields fetched per-account - import-mdb.js: always INSERTs a new account (never deletes existing); all records tagged with new accountId - Frontend: account switcher in header; activeAccountId persisted to localStorage; all API calls pass account_id; switching accounts reloads checks; wizard and import auto-switch to newly created account
This commit is contained in:
+72
-2
@@ -7,7 +7,6 @@ const path = require('path');
|
||||
const DB_PATH = process.env.DB_PATH || path.join(__dirname, '../../data/ezcheck.db');
|
||||
const SCHEMA_PATH = path.join(__dirname, 'schema.sql');
|
||||
|
||||
// Ensure data directory exists
|
||||
const dataDir = path.dirname(DB_PATH);
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
@@ -15,7 +14,6 @@ if (!fs.existsSync(dataDir)) {
|
||||
|
||||
const db = new Database(DB_PATH);
|
||||
|
||||
// Enable WAL mode for better concurrent read performance
|
||||
db.pragma('journal_mode = WAL');
|
||||
db.pragma('foreign_keys = ON');
|
||||
|
||||
@@ -23,4 +21,76 @@ db.pragma('foreign_keys = ON');
|
||||
const schema = fs.readFileSync(SCHEMA_PATH, 'utf8');
|
||||
db.exec(schema);
|
||||
|
||||
// --- Runtime migrations for schema upgrades ---
|
||||
|
||||
// Migration: add account_id to checks, fix UNIQUE to be per-account
|
||||
const checksInfo = db.prepare('PRAGMA table_info(checks)').all();
|
||||
if (!checksInfo.some(c => c.name === 'account_id')) {
|
||||
db.exec(`
|
||||
ALTER TABLE checks RENAME TO checks_old;
|
||||
CREATE TABLE checks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL DEFAULT 1 REFERENCES account(id),
|
||||
check_no INTEGER NOT NULL,
|
||||
payee TEXT NOT NULL,
|
||||
amount REAL NOT NULL,
|
||||
check_date TEXT NOT NULL,
|
||||
memo TEXT,
|
||||
note1 TEXT,
|
||||
note2 TEXT,
|
||||
payee_address1 TEXT,
|
||||
payee_address2 TEXT,
|
||||
payee_address3 TEXT,
|
||||
payee_address4 TEXT,
|
||||
printed INTEGER NOT NULL DEFAULT 0,
|
||||
add_date TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
mdb_check_id INTEGER,
|
||||
UNIQUE(account_id, check_no)
|
||||
);
|
||||
INSERT INTO checks (id, account_id, check_no, payee, amount, check_date, memo, note1, note2,
|
||||
payee_address1, payee_address2, payee_address3, payee_address4, printed, add_date, mdb_check_id)
|
||||
SELECT id, 1, check_no, payee, amount, check_date, memo, note1, note2,
|
||||
payee_address1, payee_address2, payee_address3, payee_address4, printed, add_date, mdb_check_id
|
||||
FROM checks_old;
|
||||
DROP TABLE checks_old;
|
||||
CREATE INDEX IF NOT EXISTS idx_checks_date ON checks(check_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_checks_printed ON checks(printed);
|
||||
CREATE INDEX IF NOT EXISTS idx_checks_check_no ON checks(check_no);
|
||||
CREATE INDEX IF NOT EXISTS idx_checks_account ON checks(account_id);
|
||||
`);
|
||||
}
|
||||
|
||||
// Migration: add account_id to layout_fields, change UNIQUE to per-account
|
||||
const lfInfo = db.prepare('PRAGMA table_info(layout_fields)').all();
|
||||
if (!lfInfo.some(c => c.name === 'account_id')) {
|
||||
db.exec(`
|
||||
ALTER TABLE layout_fields RENAME TO layout_fields_old;
|
||||
CREATE TABLE layout_fields (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL DEFAULT 1 REFERENCES account(id),
|
||||
field_name TEXT NOT NULL,
|
||||
field_text TEXT,
|
||||
font_name TEXT NOT NULL DEFAULT 'Helvetica',
|
||||
font_size REAL NOT NULL DEFAULT 10,
|
||||
font_bold INTEGER NOT NULL DEFAULT 0,
|
||||
field_type TEXT NOT NULL DEFAULT 'Regular',
|
||||
line_thick INTEGER NOT NULL DEFAULT 1,
|
||||
x_pos REAL NOT NULL DEFAULT 0,
|
||||
y_pos REAL NOT NULL DEFAULT 0,
|
||||
x_end_pos REAL NOT NULL DEFAULT 0,
|
||||
y_end_pos REAL NOT NULL DEFAULT 0,
|
||||
visible INTEGER NOT NULL DEFAULT 1,
|
||||
not_for_preprint INTEGER NOT NULL DEFAULT 0,
|
||||
UNIQUE(account_id, field_name)
|
||||
);
|
||||
INSERT INTO layout_fields (id, account_id, field_name, field_text, font_name, font_size, font_bold,
|
||||
field_type, line_thick, x_pos, y_pos, x_end_pos, y_end_pos, visible, not_for_preprint)
|
||||
SELECT id, 1, field_name, field_text, font_name, font_size, font_bold,
|
||||
field_type, line_thick, x_pos, y_pos, x_end_pos, y_end_pos, visible, not_for_preprint
|
||||
FROM layout_fields_old;
|
||||
DROP TABLE layout_fields_old;
|
||||
CREATE INDEX IF NOT EXISTS idx_layout_account ON layout_fields(account_id);
|
||||
`);
|
||||
}
|
||||
|
||||
module.exports = db;
|
||||
|
||||
Reference in New Issue
Block a user