chore: unify name to "Meeting Mixer", README tech stack, name magic numbers (#16)

- Canonical name "Meeting Mixer" everywhere: <title>, README, .vch-description
  (now non-technical per convention) and package.json (meeting-mixer).
- README gains a Tech-Stack section and an accurate, non-misleading port note.
- Magic numbers replaced by named constants: LOW_PRIORITY_PENALTY in
  algorithm.js; MIN/MAX_MODERATORS_PER_DAY in utils.js, used by data.js,
  calendar.js and app.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ferdi2goandClaude Opus 4.8 committed 2026-06-03 13:44:45 +00:00
1 parent b3eeca50b3
commit 836d0eeda5
9 files changed
+38 -12

No files matched your search

+1
View File
@@ -0,0 +1 @@
Meeting Mixer – Werkzeug zur fairen, automatischen Einteilung von Moderatoren für wiederkehrende Meetings. Es verteilt die Moderation gleichmäßig über das Team, berücksichtigt Verfügbarkeiten und Urlaube und erstellt fertige Monatspläne zum Export. Für Teams, die ihre Meeting-Moderation organisiert rotieren möchten.
+15 -3
View File
@@ -1,6 +1,6 @@
# Morning Meeting Planner
# Meeting Mixer
Web-App zur Planung und Verwaltung von Morning-Meeting-Moderatoren.
Web-App zur Planung und Verwaltung von Meeting-Moderatoren.
## Features
@@ -12,13 +12,25 @@ Web-App zur Planung und Verwaltung von Morning-Meeting-Moderatoren.
- **Verlauf** – Vergangene Monatspläne einsehen und wiederherstellen
- **Persistenz** – Automatische Speicherung im Browser (localStorage)
## Tech-Stack
- **Vanilla JavaScript (ES-Module)** – kein Framework, **kein Build-Schritt**
- **Persistenz:** Browser-`localStorage` (kein Backend, keine Datenbank)
- **Excel-Im-/Export:** [SheetJS](https://sheetjs.com/) (per CDN, mit SRI eingebunden)
- **Statisches Serving:** [`serve`](https://www.npmjs.com/package/serve) (Dev)
- **Tests:** Node-Assertions (`node:assert`), ohne externe Abhängigkeiten
Voraussetzung: ein moderner Browser mit ES-Modul-Unterstützung.
## Starten
```bash
npm start
```
Die App läuft auf **http://localhost:3001**.
Startet einen statischen Server. Der genutzte Port wird beim Start ausgegeben
(Standard 3001; weicht automatisch aus, falls belegt). Öffne anschließend die
angezeigte URL im Browser.
## Tests
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://cdn.sheetjs.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data:; object-src 'none'; base-uri 'self'">
<title>Morning Meeting Planner</title>
<title>Meeting Mixer</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
+4 -1
View File
@@ -1,5 +1,8 @@
import { toISO, getWeekday } from './utils.js';
// Score penalty applied when a candidate is low-priority on the given weekday.
const LOW_PRIORITY_PENALTY = 5;
function isOnVacation(employee, isoDate) {
return employee.constraints.vacations.some(v => v.from <= isoDate && isoDate <= v.to);
}
@@ -60,7 +63,7 @@ function scoreCandidate(employee, isoDate, histCount, randomFn) {
let score = -myTotal;
// Low priority: increase negative score (less likely to be picked)
if (employee.constraints.lowPriorityDays.includes(wd)) score -= 5;
if (employee.constraints.lowPriorityDays.includes(wd)) score -= LOW_PRIORITY_PENALTY;
// Jitter ±0.49
score += (randomFn() - 0.5) * 0.98;
+3 -1
View File
@@ -2,6 +2,7 @@ import { renderEmployees } from './employees.js';
import { renderCalendar } from './calendar.js';
import { renderDataTab } from './history.js';
import { normalizeEmployees } from './data.js';
import { MIN_MODERATORS_PER_DAY, MAX_MODERATORS_PER_DAY } from './utils.js';
const STORAGE_KEY = 'morning-planner-state';
@@ -22,7 +23,8 @@ try {
if (parsed.calendar) state.calendar = parsed.calendar;
if (Array.isArray(parsed.history)) state.history = parsed.history;
if (parsed.settings && Number.isInteger(parsed.settings.moderatorsPerDay)
&& parsed.settings.moderatorsPerDay >= 1 && parsed.settings.moderatorsPerDay <= 5) {
&& parsed.settings.moderatorsPerDay >= MIN_MODERATORS_PER_DAY
&& parsed.settings.moderatorsPerDay <= MAX_MODERATORS_PER_DAY) {
state.settings = { moderatorsPerDay: parsed.settings.moderatorsPerDay };
}
}
+3 -2
View File
@@ -2,7 +2,8 @@ import { state, saveState } from './app.js';
import { getWorkdays, generatePlan } from './algorithm.js';
import { toggleHoliday, toggleClosure, addHistoryEntries, removeHistoryEntry } from './data.js';
import { exportSchedule, downloadBlob } from './excel.js';
import { toISO, monthPrefix, getWeekday, buildNameMap } from './utils.js';
import { toISO, monthPrefix, getWeekday, buildNameMap,
MIN_MODERATORS_PER_DAY, MAX_MODERATORS_PER_DAY } from './utils.js';
const MONTHS = ['Januar','Februar','März','April','Mai','Juni',
'Juli','August','September','Oktober','November','Dezember'];
@@ -61,7 +62,7 @@ export function renderCalendar() {
const slotsSel = document.createElement('select');
slotsSel.id = 'cal-slots';
for (let n = 1; n <= 5; n++) {
for (let n = MIN_MODERATORS_PER_DAY; n <= MAX_MODERATORS_PER_DAY; n++) {
const opt = document.createElement('option');
opt.value = String(n);
opt.textContent = String(n);
+4 -2
View File
@@ -1,3 +1,5 @@
import { MIN_MODERATORS_PER_DAY, MAX_MODERATORS_PER_DAY } from './utils.js';
function generateId() {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
@@ -17,8 +19,8 @@ function generateId() {
function parseSettings(raw) {
const n = raw?.moderatorsPerDay;
const valid = Number.isInteger(n) && n >= 1 && n <= 5;
return { moderatorsPerDay: valid ? n : 1 };
const valid = Number.isInteger(n) && n >= MIN_MODERATORS_PER_DAY && n <= MAX_MODERATORS_PER_DAY;
return { moderatorsPerDay: valid ? n : MIN_MODERATORS_PER_DAY };
}
function defaultConstraints() {
+6 -1
View File
@@ -1,4 +1,9 @@
// Shared pure helpers used across modules.
// Shared pure helpers and constants used across modules.
// Allowed range for the "moderators per day" setting.
export const MIN_MODERATORS_PER_DAY = 1;
export const MAX_MODERATORS_PER_DAY = 5;
// "YYYY-MM-DD" from numeric parts.
export function toISO(year, month, day) {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "morning-meeting-planner",
"name": "meeting-mixer",
"version": "1.0.0",
"private": true,
"type": "module",