diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/CANONICAL.md | 182 | ||||
| -rw-r--r-- | docs/USAGE.md | 102 |
2 files changed, 284 insertions, 0 deletions
diff --git a/docs/CANONICAL.md b/docs/CANONICAL.md new file mode 100644 index 0000000..84c8f7e --- /dev/null +++ b/docs/CANONICAL.md @@ -0,0 +1,182 @@ +# Canonical ShiftPlanner — measurement record + +Date: 2026-11-09 +Scope: five divergent copies of the same application found under `spaces/`. +No source file was edited, moved, or deleted. All copies were read only, then +copied into this product tree. + +## 1. Measured feature table + +Produced by one pass over each file with `wc`, `md5sum` and `grep -o | wc -l`. +Pasted verbatim: + +```text +FILE LINES BYTES MD5 OLLAMA AIWIRE DND EXPORT CDN VERSION +spaces/mindtech/shiftplanner.html 2163 110972 5dc466b446ae3c19fffd9cd80f91461a 0 0 0 4 0 2.1 +spaces/mindtech/downloads/shiftplanner-v12-ai.html 2789 136212 37207b2227899603f90c42e59ff1875a 4 126 0 4 0 2.1 +spaces/mindtech/downloads/shiftplanner.html 1910 98435 a59dedc7608243985aad1d59b880bddd 0 0 0 4 0 2.0 +spaces/mindtech/shiftplanner_v1.3.html 1434 70415 daa2a71c94c2d0e5cb585857be5e4721 23 26 4 2 0 1.2 +spaces/agando/shiftplanner_v1.3.html 1627 81158 710875062b293ed78698d774696058ec 45 27 4 2 0 1.3 +``` + +Column definitions (all counts are occurrences of the regex, not lines): + +| Column | Meaning | +|---|---| +| `LINES` / `BYTES` | `wc -l` / `wc -c` | +| `MD5` | `md5sum` of the source file | +| `OLLAMA` | `grep -o -i 'ollama'` — case-insensitive occurrences | +| `AIWIRE` | `grep -o -i -E '\bai\b\|assistant'` — AI/assistant wiring tokens | +| `DND` | `grep -o -i -E 'draggable\|dragstart'` — real drag-and-drop handlers | +| `EXPORT` | `grep -o -E 'exportCSV\|toBlob\|download'` — export code paths | +| `CDN` | `grep -o -E 'src="http'` — external `<script src="http…>` dependencies | +| `VERSION` | the version literal the file itself declares (`version:'x.y'` in its save/export payload, or `version:'2.x'` in state) | + +Notes on measurement honesty: + +- `DND` deliberately excludes the bare word `drop`, because `drop` also matches + `dropdown` and `backdrop-filter`. Under the looser + `draggable|dragstart|drop` regex the three v2.x files score 1–2, but those + hits are CSS/UI strings only: `dragstart` is 0 and `draggable` is 0 in all + three v2.x files, so they have **no** drag-and-drop. +- `CDN` is 0 for every file. A wider sweep for `src="http`, `href="http`, + `@import` and `fonts.googleapis` also returned nothing, so all five copies + are self-contained single files with no network dependency at load time. +- `AIWIRE` 126 vs. the "~96" figure in the task context: 96 is reproducible as + the count of *lines* containing an AI token. The table reports occurrence + count, which is the more meaningful measure of wiring density. + +### Reconciling the "ollama" numbers + +The task context states the canonical copy has 0 `ollama` refs and the two +v1.3 copies have 12 and 21. Measured result: + +| File | `grep -o 'ollama'` (case-sensitive occurrences) | `grep -c 'ollama'` (matching lines) | `grep -o -i 'ollama'` (any case) | +|---|---|---|---| +| canonical (v12-ai) | **0** | 0 | 4 | +| mindtech v1.3 | 13 | **12** | 23 | +| agando v1.3 | 25 | **21** | 45 | + +So the context figures are case-sensitive *line* counts. They are correct as +stated, but they understate the canonical file's Ollama usage: the canonical +contains four capitalised `Ollama` strings and calls the Ollama HTTP API +directly. The claim "the canonical has no Ollama path" would be false. What is +true is that the canonical's AI path is **Ollama-native and endpoint-driven**, +while the v1.3 copies carry a **multi-provider** abstraction (Ollama + OpenAI + +Anthropic) — a different architecture, not a strictly larger one. See §4. + +## 2. Decision + +**Canonical: `spaces/mindtech/downloads/shiftplanner-v12-ai.html`** +→ published here as `src/index.html` (md5 `37207b2227899603f90c42e59ff1875a`, +136,212 bytes, 2,789 lines). + +One-line reason: it is a strict functional superset — it contains every +function present in both other v2.x copies (verified by set difference of +`function` names: **zero** functions unique to either sibling) and adds the +entire AI advisor panel on top, while remaining a single self-contained file +with no CDN dependency. + +Evidence for the superset claim — the function-name set of each sibling minus +the canonical's set is empty: + +```text +=== spaces/mindtech/shiftplanner.html (functions NOT in canonical): + +=== spaces/mindtech/downloads/shiftplanner.html (functions NOT in canonical): + +``` + +The two v1.3 copies, by contrast, are a **different, older codebase** +(1,434 / 1,627 lines vs 2,789) with roughly 50 functions absent from the +canonical. They have **no** shift templates (`saveTemplate`/`applyTemplate` +count 0; their only "template" matches are `grid-template-columns` CSS), **no** +day notes (`dayNote` count 0) and **no** CSV export (`exportCSV` count 0). +They do keep automatic generation (`autoGeneratePlan`), fairness options +(`Wochenende fair verteilen` / "distribute weekends fairly") and conflict +handling (`detectAllConflicts`, `clearAllConflicts`), under a different +codebase and with a **German-language UI**. They also add real drag-and-drop +and a multi-provider AI chat. They are therefore not candidates for canonical, +but they are worth archiving as feature donors. + +## 3. Archived copies + +| Archive file | Origin | Verdict | +|---|---|---| +| `archive/mindtech__shiftplanner.html` | `spaces/mindtech/shiftplanner.html` | **nothing found** — identical feature set to the canonical minus the AI panel; 0 functions and 0 features unique to it. | +| `archive/mindtech__downloads__shiftplanner.html` | `spaces/mindtech/downloads/shiftplanner.html` | **nothing found** — the v2.0 predecessor; a strict subset of the canonical in both functions and UI strings. | +| `archive/mindtech__shiftplanner_v1.3.html` | `spaces/mindtech/shiftplanner_v1.3.html` | **adds real drag-and-drop** and a 3-provider AI layer (see below). | +| `archive/agando__shiftplanner_v1.3.html` | `spaces/agando/shiftplanner_v1.3.html` | **adds real drag-and-drop** plus the most complete Ollama integration of the five (proxy path, model refresh, timeouts, connection test). | + +What the two v1.3 copies have that the canonical does not, verified by grep: + +- **Drag-and-drop scheduling** — `draggable="true"`, `ondragstart`, + `ondragover`, `ondrop`, and handlers `onDragStart` / `onDrop` / + `onDragOver` / `onDragLeave` / `onDragEnd`. The canonical has **0** of these + (`draggable` 0, `dragstart` 0); it assigns workers via modals instead. +- **Multi-provider AI** — both define `callLLM`, `sendChat`, `processChatMessage`, + `applyChatAction`, `chatAction`, `mockAgent`, `onProviderChange`; the + canonical's AI is single-provider (Ollama) and conversational only. + Endpoints observed: + - `http://localhost:11434` (Ollama) + - `https://api.openai.com/v1/chat/completions` + `https://api.openai.com/v1/models` + - `https://api.anthropic.com/v1/messages` (with `anthropic-version` and + `anthropic-dangerous-direct-browser-access` headers in the agando copy) +- **Different localStorage schema** — key `schichtplan_v12` with + `loadState` / `saveState`, versus the canonical's key `shiftplanner_v2` with + `loadFromStorage` / `saveToStorage`. Any migration between the two needs an + explicit field mapping: the v1.3 payloads carry + `employees` / `plan` / `vacations` / `absences` / `customShifts` / `settings`, + the canonical carries `workers` / `shifts` / `assignments` / `customShifts` / + `templates` / `settings`. +- **Extra functions unique to the agando copy** — `refreshOllamaModels`, + `testConnection`, `withTimeout`, `callProvider`, `providerName`, + `dateKeyOf`, `esc`. +- **Export formats differ in the other direction** — both v1.3 copies export + **JSON only** (`exportCSV` count 0); the canonical exports **both JSON and + CSV**. This is a genuine canonical advantage. + +## 4. What the canonical's AI path actually calls + +The AI panel in `src/index.html` is wired to a locally running Ollama server. +Exact strings, from grep: + +```text +921: let aiEndpoint = 'http://localhost:11434'; +922: let aiModel = localStorage.getItem('sp_ai_model') || 'llama3.2'; +2478: fetch(aiEndpoint + '/api/tags', { +2479: method: 'GET', +2556: fetch(aiEndpoint + '/api/generate', { +2486 (testAIConnection) models = data.models || [] +869: <input ... id="aiEndpointInput" value="http://localhost:11434" placeholder="http://localhost:11434"> +870: <div class="help-text">Ollama server URL. Leave default for local Ollama.</div> +``` + +- **Base URL:** `http://localhost:11434` (editable in Settings, persisted to + `localStorage['sp_ai_endpoint']`). +- **Endpoints called:** + - `GET {endpoint}/api/tags` — connectivity check / model discovery. + - `POST {endpoint}/api/generate` — chat completion, body: + `{ model, prompt, stream: false, options: { temperature: 0.4, num_predict: 1024 } }`, + reply read from `data.response`. +- **Model identifiers offered in the UI select:** `llama3.2` (default), + `mistral`, `llama3.1`, `phi3`, `gemma2`, `minimax-m3:cloud`. + The model choice persists to `localStorage['sp_ai_model']`. +- **No cloud inference endpoint is contacted.** There is no `api.openai.com`, + `api.anthropic.com` or `generativelanguage` reference anywhere in the + canonical; the only network calls are to the user-configured Ollama base URL. +- **Graceful degradation:** on failure the panel reports + `Not connected (start Ollama)` and the rest of the app is unaffected, so the + scheduler works fully with no server running. + +## 5. Provenance + +`src/index.html` is a byte-for-byte copy of the canonical source: + +```text +37207b2227899603f90c42e59ff1875a products/shiftplanner/src/index.html +37207b2227899603f90c42e59ff1875a spaces/mindtech/downloads/shiftplanner-v12-ai.html +``` + +All four archived files were verified md5-identical to their sources after +copying. The originals under `spaces/` are unchanged. diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 0000000..8a5ca00 --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,102 @@ +# Using ShiftPlanner — step by step + +No installation, no account, no internet required. + +--- + +## 1. Open the app + +Find the file `index.html` inside the `src` folder. Double-click it, or drag it +into your browser window (Chrome, Edge, Firefox or Safari). The app opens like +a normal web page. You can also copy this one file to a USB stick and open it on +another computer — it is the whole program. + +## 2. Add your people + +1. Click the **`+ Worker`** button in the top bar. +2. Fill in the name, role and **Contracted Hours/Week**. +3. Press **Save**. +4. Repeat for each employee. + +The **👥 Workers** tab on the left lists everyone. Click an entry to edit it, or +delete it from the same window. + +## 3. Create your shift types + +1. Click the **📋** button (templates) in the top bar. +2. Add a template: name, start time, end time, colour, and how many people the + shift needs. +3. Save it. + +You now have reusable shifts such as "Early", "Late" or "Night" and do not have +to retype the times each day. + +## 4. Build the month + +1. Use the arrows at the top to go to the month you want to plan. +2. Click a day in the calendar to open **Day Details**. +3. Add a shift to that day (either from your templates or as a one-off). +4. Assign the people who should work it — the app shows who is free. +5. Use **Day Note** for anything worth remembering about that date. + +To start a day over, use **Clear Day**. + +## 5. Let the app draft the rota for you + +1. Click **✨ Auto** in the top bar. +2. Choose which workers to include. +3. Choose what "fair" should mean: **Equal Number of Shifts**, **Equal Total + Hours**, or **Equal Weekend Shifts**. +4. Set your limits: **Max Consecutive Days**, **Min Rest Hours**, **Max + Workers** per shift. +5. Step through the generator and press **Apply**. + +The draft can always be changed by hand afterwards. Nothing is final until you +say so. + +## 6. Record holidays and sickness + +Open a worker and add a **vacation**, a **sick day**, or a **day off**. The +planner will not schedule that person while the absence is active. + +## 7. Check for clashes + +The app continuously looks for problems — someone booked twice, too little rest +between shifts, or too many days in a row. A badge appears when something is +wrong. Use **Fix conflicts** to see them and **Clear Day** to reset a day that +has become tangled. + +## 8. Save and back up + +Your work is saved automatically in this browser on this computer. That is the +only place it is stored — there is no cloud and no server. + +Because of that, **back up regularly**: + +- **📊** exports the month's rota as a **CSV spreadsheet** — for printing, + emailing or opening in Excel. +- **📤** exports the **whole plan as a JSON file** — this is your real backup; + it contains every worker, shift and assignment. +- **📥** loads a JSON backup back in. + +If you clear your browser's site data, the plan is gone. Keep a JSON export +somewhere safe. + +## 9. Optional: turn on the AI advisor + +Only do this if you want the chat panel on the right-hand side. + +1. Install Ollama on your computer and start it (default address + `http://localhost:11434`). +2. Open **⚙️ Settings** and confirm the **AI Endpoint** — normally leave it as + it is, or type the address given in your Ollama settings if it is different. +3. Pick a model in the panel's **Model** dropdown. +4. Ask a question such as "who is working too many weekends?" and press Enter. + +If Ollama is not running, the panel simply says "Not connected (start Ollama)". +Everything else in the app keeps working. + +## 10. Make it easier on the eyes + +Click **☀** to switch between the light and dark theme. The choice is +remembered. |