duimstok.prorail.nl/_docs/session-summary-2026-04-16.md

11 KiB

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)