237 lines
11 KiB
Markdown
237 lines
11 KiB
Markdown
# Session Summary: Duimstok PWA MVP Build
|
|
|
|
**Date:** 2026-04-16
|
|
**Project:** ProRail Duimstok-inspecties Bovenbouw
|
|
**Repo:** https://git.en-masse.nl/randy/duimstok.prorail.nl.git
|
|
|
|
---
|
|
|
|
## Phase 1: Monolithic HTML Refactor
|
|
|
|
**Goal:** Split a single-file app (`duimstok-wissel-gw-sw.html`, 1566 lines) into a layered DDD structure.
|
|
|
|
**What was done:**
|
|
- Created `src/Domain/`, `src/Application/`, `src/Infrastructure/` layers
|
|
- Converted ES modules to classic IIFE scripts attaching to `window.App.*` namespace
|
|
- Embedded CSV seed data as a string constant in `seedOrders.js` (no `fetch()` needed)
|
|
- Removed all inline styles (`style=""`) and inline event handlers (`onclick`, `oninput`, etc.)
|
|
- Replaced inline styles with CSS classes (`.flex-spacer`, `.cap-arrow.lg`, `.section-sub.sm`, `.fotonummers-cell`)
|
|
- Wired all event listeners via `addEventListener` in `main.js` and service modules
|
|
|
|
**Result:** 30 files, ~2163 lines. Runs by double-clicking `public/index.html` -- no server needed.
|
|
|
|
**File structure:**
|
|
|
|
```
|
|
01_Applicatie/
|
|
├── public/
|
|
│ ├── index.html
|
|
│ ├── css/ base.css, overview.css, form.css, modals.css, responsive.css
|
|
│ └── js/ namespace.js, main.js
|
|
└── src/
|
|
├── Domain/ sectionMap.js, scoring.js, orderParser.js
|
|
├── Application/ state.js, persistence.js, screens.js, photoService.js,
|
|
│ inspectionForm.js, orderOverview.js, xmlImport.js, exportService.js
|
|
└── Infrastructure/ utils.js, geolocation.js, db.js, seedOrders.js, csvLoader.js
|
|
```
|
|
|
|
---
|
|
|
|
## Phase 2: PWA Research & Planning
|
|
|
|
**Prompt used:** "what are the next steps create a PWA version of this MVP, ideally with offline photo upload functionality which sync when back online. Whats the current supported state of PWA regarding these offline functionalities atm"
|
|
|
|
**Key findings:**
|
|
- Service Worker, Cache API, IndexedDB, Manifest, installability all work cross-browser (Chromium, Firefox, Safari/iOS 16.4+)
|
|
- Background Sync (`sync` event) only works on Chromium -- not Firefox, not Safari/iOS
|
|
- Periodic Background Sync: Chromium only (engagement-gated)
|
|
- Background Fetch: Chromium only
|
|
- Push notifications: universal for installed PWAs (iOS 16.4+)
|
|
- Persistent storage: universal, but Safari historically aggressive on eviction
|
|
|
|
**Key constraint:** iOS has no true background sync. Design around draining the queue when the user reopens the app and when the `online` event fires.
|
|
|
|
**6-step incremental plan identified:**
|
|
1. Installable shell (manifest + service worker cache)
|
|
2. Switch photo storage from data URLs to Blobs
|
|
3. Sync queue in IndexedDB
|
|
4. Trigger drain on every available signal (online event, app open, SW sync, manual button)
|
|
5. Persistent storage + install hint
|
|
6. Backend stub (Symfony controller for POST /api/inspections)
|
|
|
|
---
|
|
|
|
## Phase 3: PWA Scaffold Implementation
|
|
|
|
**Prompt used:** "Goal is still conversion later on to Symfony, but for now we do want the PWA functionality (add an additional installation and instruction screen for the PWA installation)"
|
|
|
|
**Constraint flagged:** PWA features require HTTPS or localhost -- they cannot work from `file://`.
|
|
|
|
**Resolution:** Dual-mode codebase:
|
|
- `file://` mode: app works exactly as before; PWA init gated by `location.protocol !== 'file:'` and quietly skipped
|
|
- `http://localhost` or deployed mode: service worker registers, app becomes installable, install screen shows platform-specific instructions
|
|
|
|
**Files created:**
|
|
- `public/manifest.webmanifest` -- app manifest with icons, standalone display, ProRail blue theme
|
|
- `public/sw.js` -- service worker with app shell precaching (cache-first for statics, network-first for API)
|
|
- `public/icons/icon.svg` -- SVG app icon (ProRail blue with white ruler lines)
|
|
- `public/css/install.css` -- styles for the install instruction screen
|
|
- `src/Application/pwa.js` -- service worker registration, `beforeinstallprompt` capture, standalone detection
|
|
- `src/Application/installScreen.js` -- platform-specific install instructions (Chrome/Edge, iOS Safari, Firefox, generic)
|
|
|
|
**HTML changes:**
|
|
- Added PWA meta tags (`theme-color`, `apple-mobile-web-app-capable`, manifest link, apple-touch-icon)
|
|
- Added "Installeren" button to overview toolbar
|
|
- Added `screen-install` section with back button and dynamic body
|
|
- Added `<link>` for `install.css`
|
|
- Added `<script>` tags for `pwa.js` and `installScreen.js`
|
|
|
|
---
|
|
|
|
## Phase 4: Git Repository Setup
|
|
|
|
**Prompt used:** "ini git repo and commit and push, add files and folders, repo https://git.en-masse.nl/randy/duimstok.prorail.nl.git" + "to the develop branch"
|
|
|
|
**Decisions made:**
|
|
- Repo root: `01_Applicatie/` (app code only; ProRail reference PDFs/photos stay outside)
|
|
- Deleted old monolithic files: `duimstok-wissel-gw-sw.html` and backup copy
|
|
- Created `.gitignore` (DS_Store, Thumbs.db, editors, node_modules, env files)
|
|
- Created `README.md` with project structure documentation
|
|
- Created `_docs/.gitkeep`
|
|
|
|
**Git Flow applied:**
|
|
1. Initialized repo with `develop` branch -- baseline commit (README, .gitignore, _docs/)
|
|
2. Created `feature/initial-pwa-scaffold` branch off develop
|
|
3. Committed all app code (30 files, 2163 insertions)
|
|
4. Pushed `develop` (baseline only, no staging deploy triggered)
|
|
5. Pushed `feature/initial-pwa-scaffold` (feature branch, no deploy implications)
|
|
6. Suggested PR creation on Forgejo before merging to develop
|
|
|
|
---
|
|
|
|
## Phase 5: Photo Blob Storage Refactor
|
|
|
|
**Branch:** `feature/photo-blob-storage` (off `feature/initial-pwa-scaffold`)
|
|
|
|
**What changed:**
|
|
- Photos now stored as native `Blob` objects instead of base64 data URLs (~33% smaller)
|
|
- `photoSrc()` helper uses `URL.createObjectURL(blob)` for rendering thumbnails
|
|
- `URL.revokeObjectURL()` called on lightbox close and when replacing images (memory cleanup)
|
|
- Removed `readFileAsDataUrl()` from `utils.js` (no longer needed)
|
|
- Removed `dataUrlToBlob()` from `utils.js` (no longer needed)
|
|
- `db.js`: removed `JSON.parse(JSON.stringify(formData))` deep-clone -- IndexedDB handles Blobs natively
|
|
- `exportService.js`: downloads `p.blob` directly instead of converting from data URL
|
|
|
|
**Files changed:** `photoService.js`, `exportService.js`, `db.js`, `utils.js`
|
|
|
|
---
|
|
|
|
## Phase 6: CSV Upload Persistence
|
|
|
|
**Branch:** `feature/csv-upload-persistence`
|
|
|
|
**What changed:**
|
|
- New IndexedDB object store `ordersCsv` (DB version bumped 3 -> 4)
|
|
- `db.js`: added `saveOrdersCsv(csvText)` and `loadOrdersCsv()` functions
|
|
- `csvLoader.js`: `loadOrdersFromUpload()` now returns `{ text, orders }` so raw CSV text gets persisted
|
|
- `main.js` init: loads stored CSV from IndexedDB, falls back to embedded seed data if none stored
|
|
- `main.js` upload handler: saves CSV text to IndexedDB after parsing
|
|
|
|
**Files changed:** `db.js`, `csvLoader.js`, `main.js`
|
|
|
|
---
|
|
|
|
## Phase 7: Persistent Storage Request
|
|
|
|
**Branch:** `feature/persistent-storage-request`
|
|
|
|
**What changed:**
|
|
- New file `src/Infrastructure/persistentStorage.js` with `isPersisted()` and `requestPersistence()`
|
|
- Calls `navigator.storage.persist()` after the first successful save (reduces iOS eviction risk)
|
|
- One-time flag `persistenceRequested` prevents repeated calls
|
|
- Updated SW cache version to `duimstok-v2`
|
|
- Added `persistentStorage.js` to both `index.html` script tags and SW precache list
|
|
|
|
**Files changed/created:** `persistentStorage.js` (new), `persistence.js`, `sw.js`, `index.html`
|
|
|
|
---
|
|
|
|
## Phase 8: Multi-Inspection Type Scoping (Not Yet Implemented)
|
|
|
|
**Prompt used:** "continue with question 1: spoor en overweg in map C:\...\04_Gegenereerd door SAP_incl WW_xslx_xlm\XML"
|
|
|
|
**Research done:**
|
|
- Read `_docs/switch-inspection-diagram.md` -- confirms existing wissel_GW photo layout
|
|
- Read SAP XML templates for Spoor and Overwegbevloering from reference folders
|
|
- Identified 3 inspection types: Wissel, Overwegbevloering, Spoor
|
|
|
|
**Proposed scope for `feature/inspection-type-routing`:**
|
|
1. Routing layer that derives type from `order.objectsoort`
|
|
2. Three form panels in `index.html`, shown based on type
|
|
3. Wissel: no visual change (existing 10-slot layout)
|
|
4. Overwegbevloering: stub form with photos section, no wissel diagram
|
|
5. Spoor: stub form emphasizing start/end-KM fields from CSV
|
|
6. Export works for all three types
|
|
|
|
**Status:** Scoped, awaiting answers to 3 questions before implementation.
|
|
|
|
---
|
|
|
|
## Global Rules Established
|
|
|
|
These rules were added to `~/.claude/CLAUDE.md` during the session:
|
|
|
|
| Rule | Context |
|
|
|------|---------|
|
|
| **No backwards compatibility in MVPs** | User corrected fallback code for old photo data format |
|
|
| **No `Co-Authored-By: Claude` in commits** | User interrupted a commit that included the attribution line |
|
|
| **Git Flow workflow** | User requested: develop = staging, master = production, feature branches for all work |
|
|
| **`_docs/` for project documentation** | User requested: all docs in project root `_docs/` folder |
|
|
| **`file://` runnable MVPs** | User requested: must work by opening `public/index.html` directly |
|
|
| **Vanilla HTML/JS/CSS, no frameworks** | Pre-existing rule (maps to eventual Symfony/Twig conversion) |
|
|
| **DDD folder structure** | Pre-existing rule (Domain/Application/Infrastructure layers) |
|
|
| **Forgejo at git.en-masse.nl** | User specified as default remote host |
|
|
|
|
---
|
|
|
|
## Shortcuts & Commands Used
|
|
|
|
| Command/Action | Purpose | Times Used |
|
|
|----------------|---------|------------|
|
|
| `/usage` | Check token consumption | 2x |
|
|
| `continue` | Resume after idle or interruption | Multiple |
|
|
| `merge` | Trigger merge-to-develop flow | Multiple |
|
|
| `yes` / `1` / `3` | Quick selection from numbered options | Multiple |
|
|
| Interrupted commits | Added global rules mid-flow (no co-author, no backwards compat) | 3x |
|
|
|
|
---
|
|
|
|
## Git History (Linear on develop)
|
|
|
|
```
|
|
b005193 Request persistent storage after first save
|
|
92ad6a9 Persist uploaded order CSVs across app restarts
|
|
e86aa5b Store photos as native Blobs instead of base64 data URLs
|
|
776bd63 Add PWA-ready MVP: split HTML/CSS/JS + DDD layering + service worker
|
|
367bbca Initial repo scaffold on develop
|
|
```
|
|
|
|
**Branch lifecycle:**
|
|
- All feature branches created off `develop` (or stacked off previous feature branch when develop was behind)
|
|
- All merged via fast-forward (`--ff-only`)
|
|
- All deleted (local + remote) after merge
|
|
- Only `develop` remains as active branch
|
|
- `master` not yet created (awaiting production readiness)
|
|
|
|
---
|
|
|
|
## Open Items
|
|
|
|
- [ ] Manual verify: capture photo, render thumbnail, reload, check thumbnail persists, export produces valid JPG
|
|
- [ ] Manual verify: upload CSV, hard-reload, confirm modified orders still appear
|
|
- [ ] Implement `feature/inspection-type-routing` (Wissel/Overwegbevloering/Spoor forms)
|
|
- [ ] Create `master` branch when ready for production deployment
|
|
- [ ] Set up CI on Forgejo
|
|
- [ ] Backend stub (Symfony POST /api/inspections) to enable sync queue testing
|
|
- [ ] Authentication for inspectors (currently free-text name -- needs SSO/token discussion with ProRail)
|