Migrate all repos into monorepo context folders

Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
This commit is contained in:
2026-06-30 20:39:52 +02:00
parent 2f2b295531
commit a5f8fb49ab
1717 changed files with 447332 additions and 0 deletions
@@ -0,0 +1,229 @@
import { describe, it, expect, beforeEach, afterAll } from 'vitest';
import fs from 'fs';
import path from 'path';
import { Score } from '../../shared/types.js';
const DATA_DIR = path.join(process.cwd(), 'server', 'data');
const SESSION_FILE = path.join(DATA_DIR, 'session.json');
const SEED_FILE = path.join(DATA_DIR, 'seed.json');
const BACKUP_FILE = path.join(DATA_DIR, 'session.json.bak');
// Import the store module — initialization runs on import
import * as store from '../store.js';
describe('server/store', () => {
// Reset session.json from seed before each test for isolation
beforeEach(() => {
const seedData = fs.readFileSync(SEED_FILE, 'utf-8');
fs.writeFileSync(SESSION_FILE, seedData, 'utf-8');
// Remove backup if it exists
if (fs.existsSync(BACKUP_FILE)) {
fs.unlinkSync(BACKUP_FILE);
}
});
// Clean up after all tests
afterAll(() => {
// Restore session.json from seed
const seedData = fs.readFileSync(SEED_FILE, 'utf-8');
fs.writeFileSync(SESSION_FILE, seedData, 'utf-8');
if (fs.existsSync(BACKUP_FILE)) {
fs.unlinkSync(BACKUP_FILE);
}
});
it('getStore() returns valid StoreData', () => {
const data = store.getStore();
expect(data).toHaveProperty('session');
expect(data).toHaveProperty('teams');
expect(data).toHaveProperty('jurors');
expect(data).toHaveProperty('scores');
expect(data.session.id).toBe('unikat-2026');
});
it('getStore() returns seed data structure', () => {
const data = store.getStore();
expect(data.teams).toHaveLength(11);
expect(data.jurors).toHaveLength(6);
expect(data.scores).toEqual([]);
});
it('saveStore() creates a .bak backup', () => {
const data = store.getStore();
store.saveStore(data);
expect(fs.existsSync(BACKUP_FILE)).toBe(true);
});
it('saveStore() writes data atomically (persists changes)', () => {
const data = store.getStore();
data.session.status = 'active';
store.saveStore(data);
const reloaded = store.getStore();
expect(reloaded.session.status).toBe('active');
});
it('saveStore() backup contains previous data', () => {
const originalData = store.getStore();
const originalStatus = originalData.session.status;
originalData.session.status = 'active';
store.saveStore(originalData);
const backupContent = JSON.parse(fs.readFileSync(BACKUP_FILE, 'utf-8'));
expect(backupContent.session.status).toBe(originalStatus);
});
it('getSession() returns the session', () => {
const session = store.getSession();
expect(session.id).toBe('unikat-2026');
expect(session.status).toBe('setup');
expect(session.config.criteria).toHaveLength(5);
});
it('getTeams() returns all teams', () => {
const teams = store.getTeams();
expect(teams).toHaveLength(11);
expect(teams[0]).toHaveProperty('id');
expect(teams[0]).toHaveProperty('name');
expect(teams[0]).toHaveProperty('number');
});
it('getJurors() returns all jurors', () => {
const jurors = store.getJurors();
expect(jurors).toHaveLength(6);
expect(jurors[0]).toHaveProperty('id');
expect(jurors[0]).toHaveProperty('name');
expect(jurors[0]).toHaveProperty('active');
});
it('getScores() returns empty scores array initially', () => {
const scores = store.getScores();
expect(Array.isArray(scores)).toBe(true);
expect(scores).toHaveLength(0);
});
it('addScore() adds a new score', () => {
const score: Score = {
jurorId: 'finke',
teamId: 'dual',
criterionId: 'gesamtidee',
value: 8,
updatedAt: new Date().toISOString(),
};
store.addScore(score);
const scores = store.getScores();
expect(scores).toHaveLength(1);
expect(scores[0].jurorId).toBe('finke');
expect(scores[0].teamId).toBe('dual');
expect(scores[0].criterionId).toBe('gesamtidee');
expect(scores[0].value).toBe(8);
});
it('addScore() updates existing score (match by jurorId+teamId+criterionId)', () => {
const score1: Score = {
jurorId: 'finke',
teamId: 'dual',
criterionId: 'gesamtidee',
value: 7,
updatedAt: '2026-05-19T10:00:00Z',
};
store.addScore(score1);
const score2: Score = {
jurorId: 'finke',
teamId: 'dual',
criterionId: 'gesamtidee',
value: 9,
updatedAt: '2026-05-19T10:01:00Z',
};
store.addScore(score2);
const scores = store.getScores();
const matching = scores.filter(
(s) =>
s.jurorId === 'finke' &&
s.teamId === 'dual' &&
s.criterionId === 'gesamtidee'
);
expect(matching).toHaveLength(1);
expect(matching[0].value).toBe(9);
expect(matching[0].updatedAt).toBe('2026-05-19T10:01:00Z');
});
it('addScore() does not affect scores for different criteria', () => {
const score1: Score = {
jurorId: 'finke',
teamId: 'dual',
criterionId: 'gesamtidee',
value: 7,
updatedAt: '2026-05-19T10:00:00Z',
};
const score2: Score = {
jurorId: 'finke',
teamId: 'dual',
criterionId: 'markt',
value: 9,
updatedAt: '2026-05-19T10:01:00Z',
};
store.addScore(score1);
store.addScore(score2);
const scores = store.getScores();
expect(scores).toHaveLength(2);
});
it('updateSession() merges partial updates', () => {
const updated = store.updateSession({
status: 'active',
startedAt: '2026-05-19T18:00:00Z',
});
expect(updated.status).toBe('active');
expect(updated.startedAt).toBe('2026-05-19T18:00:00Z');
expect(updated.id).toBe('unikat-2026');
expect(updated.config.criteria).toHaveLength(5);
});
it('updateSession() persists changes', () => {
store.updateSession({ status: 'active' });
const session = store.getSession();
expect(session.status).toBe('active');
});
it('updateJuror() updates a juror by ID', () => {
const updated = store.updateJuror('finke', { active: true });
expect(updated).not.toBeNull();
expect(updated!.active).toBe(true);
expect(updated!.name).toBe('Finke');
expect(updated!.id).toBe('finke');
});
it('updateJuror() persists changes', () => {
store.updateJuror('finke', { active: true });
const jurors = store.getJurors();
const finke = jurors.find((j) => j.id === 'finke');
expect(finke!.active).toBe(true);
});
it('updateJuror() returns null for unknown jurorId', () => {
const result = store.updateJuror('unknown-juror', { active: true });
expect(result).toBeNull();
});
it('initializes from seed.json if session.json does not exist', () => {
// Delete session.json
fs.unlinkSync(SESSION_FILE);
expect(fs.existsSync(SESSION_FILE)).toBe(false);
// Manually call the initialization logic by writing seed
const seedData = fs.readFileSync(SEED_FILE, 'utf-8');
fs.writeFileSync(SESSION_FILE, seedData, 'utf-8');
// Verify the store reads correctly
const data = store.getStore();
expect(data.session.id).toBe('unikat-2026');
expect(data.teams).toHaveLength(11);
expect(data.jurors).toHaveLength(6);
});
});