mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
bef8fc20f1
- A restore (admin panel or RESTORE_FROM_BACKUP) now leaves data/.trek-reclaim-reset before it swaps the database in. Boot reconcile resets the reclaim state when it finds the file, whatever install id the database names, and removes it afterwards; a successful reopen removes it too. A restart after a failed reopen, or a boot restore of this installation's own backup, no longer keeps the old switch, marks and confirmations. The id mismatch reset stays. - The release job skips a tick (install_mismatch) while the database names another installation or a reset is still pending. - An allowed owner verdict is cached for 15 minutes, a refusal for 26 hours. The local driver reads a list prefix as a folder, so the category root is still listed whole, at most once per category per window. - Each tick reads every allowed category's due rows separately, an equal share of the 200 each, so a category whose deletes keep failing cannot starve the others. - Rows dropped after 30 days overdue and releases refused by a full queue are logged at warn with their counts.
80 lines
3.3 KiB
TypeScript
80 lines
3.3 KiB
TypeScript
import { readEnv, type AppEnv } from './env';
|
|
|
|
import path from 'node:path';
|
|
|
|
/**
|
|
* `<server>/`, the directory holding package.json. `src/app-config` and
|
|
* `dist/app-config` both sit two levels below it, so the anchor is the same
|
|
* under vitest, `npm run dev` and the built image.
|
|
*/
|
|
export const SERVER_ROOT = path.resolve(__dirname, '..', '..');
|
|
|
|
/**
|
|
* Where TREK keeps what it writes. In the image `data/` and `uploads/` are
|
|
* symlinks into `/app`, which is why every consumer used to anchor on its own
|
|
* `__dirname` and why none of them may use `process.cwd()` instead.
|
|
*/
|
|
export interface DataPaths {
|
|
/** `<server>/data`: the database, the key files, backups, logs and plugin trees. */
|
|
readonly dataDir: string;
|
|
/** `<server>/uploads`: the local upload categories (files, covers, photos, ...). */
|
|
readonly uploadsDir: string;
|
|
/** `data/backups`: archives written by the manual and the automatic backup. */
|
|
readonly backupsDir: string;
|
|
/** `data/tmp`: driver-agnostic scratch space (restore spool, mirror staging). */
|
|
readonly tmpDir: string;
|
|
/** `data/logs`: the rotating `trek.log`. */
|
|
readonly logsDir: string;
|
|
/** `data/.jwt_secret`: written on first start and by the admin's JWT rotation. */
|
|
readonly jwtSecretFile: string;
|
|
/** `data/.encryption_key`: the at-rest key when ENCRYPTION_KEY does not provide it. */
|
|
readonly encryptionKeyFile: string;
|
|
/**
|
|
* `data/.trek-install-id`: this installation's random id, written on first
|
|
* start. It never enters a backup and no restore writes it, so a database
|
|
* restored or copied from another install is told apart by it (storage reclaim).
|
|
*/
|
|
readonly installIdFile: string;
|
|
/**
|
|
* `data/.trek-reclaim-reset`: left by a restore right before it swaps the
|
|
* database in, removed once storage reclaim has dropped the state the swapped
|
|
* database brought. A start that finds it resets that state first, so a
|
|
* restore whose reopen failed, or one at boot, is covered even when the
|
|
* backup came from this installation. Never part of a backup.
|
|
*/
|
|
readonly reclaimResetFile: string;
|
|
/**
|
|
* The SQLite file a non-test process opens: TREK_DB_FILE when set, else
|
|
* `data/travel.db`. Under NODE_ENV=test the connection is `:memory:` instead
|
|
* (db/db-path.ts), which is a property of the connection, not of the layout.
|
|
*/
|
|
readonly dbFile: string;
|
|
}
|
|
|
|
/**
|
|
* The data layout, derived from the server root and the live environment.
|
|
*
|
|
* The only variable involved is TREK_DB_FILE, read through `readEnv()` like
|
|
* every other live value, so a test that points it somewhere else is seen on
|
|
* the next call. Nothing here touches the disk: creating a directory is the
|
|
* caller's decision.
|
|
*/
|
|
export function resolveDataPaths(
|
|
env: { db: Pick<AppEnv['db'], 'trekDbFile'> } = readEnv(),
|
|
root: string = SERVER_ROOT,
|
|
): DataPaths {
|
|
const dataDir = path.join(root, 'data');
|
|
return {
|
|
dataDir,
|
|
uploadsDir: path.join(root, 'uploads'),
|
|
backupsDir: path.join(dataDir, 'backups'),
|
|
tmpDir: path.join(dataDir, 'tmp'),
|
|
logsDir: path.join(dataDir, 'logs'),
|
|
jwtSecretFile: path.join(dataDir, '.jwt_secret'),
|
|
encryptionKeyFile: path.join(dataDir, '.encryption_key'),
|
|
installIdFile: path.join(dataDir, '.trek-install-id'),
|
|
reclaimResetFile: path.join(dataDir, '.trek-reclaim-reset'),
|
|
dbFile: env.db.trekDbFile || path.join(dataDir, 'travel.db'),
|
|
};
|
|
}
|