feat: admin page with dynamic converter loading

Implements full admin interface for managing units and groups.
Migrates converter from static imports to server-side data loading.

- Switch adapter-static → adapter-node
- Add bcryptjs session auth with HMAC-signed cookies
- Add data/units.json and data/config.json data layer
- Add atomic file writes via temp-file rename
- Add public GET /api/units endpoint
- Add auth-gated admin CRUD API for units and groups
- Add two-panel admin UI with group tree and edit forms
- Add YOLO mode toggle for cross-group conversions
- Add visual group dividers in converter results grid
- Update ResultItem type for nullable convertedValue and isYolo flag
- Group deletion supports reassign/orphan with toBase recalculation

Rollback point: 067fd44

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Falkan
2026-03-17 13:55:11 -04:00
parent 067fd445ef
commit d1f51c141e
27 changed files with 1915 additions and 81 deletions

20
scripts/set-password.js Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env node
import bcrypt from 'bcryptjs';
import { readFileSync, writeFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const configPath = resolve(__dirname, '../data/config.json');
const password = process.argv[2];
if (!password) {
console.error('Usage: node scripts/set-password.js <password>');
process.exit(1);
}
const hash = await bcrypt.hash(password, 12);
const config = JSON.parse(readFileSync(configPath, 'utf8'));
config.passwordHash = hash;
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
console.log('Password set successfully.');