aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/CANONICAL.md182
-rw-r--r--docs/USAGE.md102
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.