157 lines
4.5 KiB
JavaScript
Executable File
157 lines
4.5 KiB
JavaScript
Executable File
import { Low } from 'lowdb';
|
|
import { JSONFile } from 'lowdb/node';
|
|
import { mkdirSync } from 'fs';
|
|
import { dirname } from 'path';
|
|
|
|
const DB_PATH = process.env.DB_PATH || './data/budget.json';
|
|
|
|
const DEFAULT = {
|
|
categories: [
|
|
{ id: 1, name: 'Kivra', sort_order: 1, color: '#7C3AED' },
|
|
{ id: 2, name: 'eFaktura', sort_order: 2, color: '#2563EB' },
|
|
{ id: 3, name: 'Manuella', sort_order: 3, color: '#D97706' },
|
|
{ id: 4, name: 'Autogiro', sort_order: 4, color: '#059669' },
|
|
],
|
|
months: [],
|
|
income: [],
|
|
bills: [],
|
|
subscriptions: [],
|
|
loans: [],
|
|
payments: [],
|
|
banking: {
|
|
enable_banking: {
|
|
enabled: false,
|
|
status: 'not_connected',
|
|
institution: '',
|
|
last_sync_at: null,
|
|
notes: '',
|
|
application_id: '',
|
|
private_key_pem: '',
|
|
redirect_url: '',
|
|
country: 'SE',
|
|
psu_type: 'personal',
|
|
auto_sync_enabled: false,
|
|
sync_interval_minutes: 360,
|
|
import_from_date: null,
|
|
incremental_sync_days: 7,
|
|
pending_state: null,
|
|
last_callback_at: null,
|
|
last_callback_url: '',
|
|
last_callback_code_present: false,
|
|
last_callback_state: '',
|
|
last_callback_exchange_at: null,
|
|
last_callback_exchange_error: '',
|
|
session_id: null,
|
|
session_expires_at: null,
|
|
session_created_at: null,
|
|
account_aliases: {},
|
|
transaction_categories: {},
|
|
accounts: [],
|
|
transactions: [],
|
|
last_sync_summary: null,
|
|
last_error: null,
|
|
},
|
|
},
|
|
auth: {
|
|
settings: {
|
|
enabled: false,
|
|
issuer: '',
|
|
discovery_url: '',
|
|
client_id: '',
|
|
client_secret: '',
|
|
redirect_uri: '',
|
|
scope: 'openid profile email groups',
|
|
session_secret: '',
|
|
allowed_groups: '',
|
|
allowed_emails: '',
|
|
allowed_domains: '',
|
|
session_ttl_hours: 12,
|
|
},
|
|
sessions: [],
|
|
pending: [],
|
|
},
|
|
ai: {
|
|
ollama: {
|
|
enabled: false,
|
|
base_url: 'http://host.docker.internal:11434',
|
|
model: '',
|
|
vision_model: '',
|
|
system_prompt: '',
|
|
include_budget_context: true,
|
|
include_banking_context: true,
|
|
},
|
|
conversations: [],
|
|
},
|
|
app_settings: {
|
|
finance_profile: {
|
|
salary_day_of_month: 25,
|
|
buffer_days_target: 7,
|
|
salary_account_uid: '',
|
|
recurring_income_note: '',
|
|
},
|
|
account_view: {
|
|
primary_account_uid: '',
|
|
include_savings_in_ai: false,
|
|
hide_zero_balance_accounts: false,
|
|
},
|
|
notifications: {
|
|
ntfy_enabled: false,
|
|
ntfy_base_url: 'https://ntfy.sh',
|
|
ntfy_topic: '',
|
|
ntfy_access_token: '',
|
|
ntfy_title: 'Enkelbudget',
|
|
ntfy_tags: 'money_with_wings,bank',
|
|
ntfy_click_url: '',
|
|
ntfy_priority: 3,
|
|
notify_new_transactions: true,
|
|
include_pending_transactions: false,
|
|
minimum_transaction_amount: 0,
|
|
last_error: '',
|
|
last_sent_at: null,
|
|
},
|
|
},
|
|
_seq: { categories: 4, months: 0, income: 0, bills: 0, subscriptions: 0, loans: 0, payments: 0 },
|
|
};
|
|
|
|
let _db = null;
|
|
|
|
export async function getDb() {
|
|
if (!_db) {
|
|
mkdirSync(dirname(DB_PATH), { recursive: true });
|
|
const adapter = new JSONFile(DB_PATH);
|
|
_db = new Low(adapter, DEFAULT);
|
|
await _db.read();
|
|
_db.data ||= structuredClone(DEFAULT);
|
|
_db.data.categories ||= structuredClone(DEFAULT.categories);
|
|
_db.data.months ||= [];
|
|
_db.data.income ||= [];
|
|
_db.data.bills ||= [];
|
|
_db.data.subscriptions ||= [];
|
|
_db.data.loans ||= [];
|
|
_db.data.payments ||= [];
|
|
_db.data.banking ||= structuredClone(DEFAULT.banking);
|
|
_db.data.banking.enable_banking ||= structuredClone(DEFAULT.banking.enable_banking);
|
|
_db.data.auth ||= structuredClone(DEFAULT.auth);
|
|
_db.data.auth.settings ||= structuredClone(DEFAULT.auth.settings);
|
|
_db.data.auth.sessions ||= [];
|
|
_db.data.auth.pending ||= [];
|
|
_db.data.ai ||= structuredClone(DEFAULT.ai);
|
|
_db.data.ai.ollama ||= structuredClone(DEFAULT.ai.ollama);
|
|
_db.data.ai.conversations ||= [];
|
|
_db.data.app_settings ||= structuredClone(DEFAULT.app_settings);
|
|
_db.data.app_settings.finance_profile ||= structuredClone(DEFAULT.app_settings.finance_profile);
|
|
_db.data.app_settings.account_view ||= structuredClone(DEFAULT.app_settings.account_view);
|
|
_db.data.app_settings.notifications ||= structuredClone(DEFAULT.app_settings.notifications);
|
|
_db.data._seq ||= {};
|
|
for (const [key, value] of Object.entries(DEFAULT._seq)) {
|
|
_db.data._seq[key] ??= value;
|
|
}
|
|
}
|
|
return _db;
|
|
}
|
|
|
|
export function nextId(db, table) {
|
|
db.data._seq[table] = (db.data._seq[table] ?? 0) + 1;
|
|
return db.data._seq[table];
|
|
}
|