A modern, installable web app for Atlas Copco service technicians to generate, sign, and print intervention reports on any device β phone, tablet, or desktop. Works fully offline once installed.
Branded throughout β the official Atlas Copco colour palette (
#0092BC/ RGB 0,146,188), the horizontal AtlasCopco wordmark in the header, and a coloured teal bar on every printed PDF page.
- Auto-formatted dates β DD/MM/YYYY across every device, with a built-in calendar picker
- 24-hour time inputs β HH:MM, auto-inserted colon as you type
- 6-character unique report IDs β base36, collision-checked against the local database
- 46 inline tooltips β hover any label for guidance on what to fill in
- Dynamic rows with auto-calculated durations (handles overnight crossings)
- Live totals at the bottom of each table
- Pre-validated time format, no AM/PM ambiguity ever
- Draw with mouse, finger, or stylus
- Names auto-fill from Contact / Technician fields
- Signatures persist with the report β visible on the saved card and on the printed PDF
- Date stamps match the report date in DD/MM/YYYY format
- Date stamps preserved on re-print
- Optional attachments block between Notes and Work Time β toggleable when needed, hidden by default
- Drag-and-drop or click-to-browse for image files (PNG, JPG, GIF, SVG, WebP β up to 5 MB each)
- Per-image caption β printed in italics below the image on the PDF
- Multiple images β grid layout, each with thumbnail, caption input, file name, Remove button
- Round-trips through JSON β images stored as base64 data URLs so the saved-to-JSON β load-from-JSON flow preserves them exactly
- Prints to PDF β each image renders full-width between Notes and Work Time with its caption
- Carries over on Clone β unlike signatures (which are session-only), attachments are persisted data so they DO clone with the report
- Save Report β persists to the local SQLite database when run with
./serve.sh, or to browser localStorage on static hosting/GitHub Pages - Save to JSON β download a portable backup with a descriptive filename (
<customer>_<date>_<id>.json) β includes base64-encoded images - Load from JSON β round-trip restore of every field including attachments
- Clone β copy a saved report into a fresh form (images carry over)
- Delete individual or all reports
- Branded teal colour header on the first page β matches the web page header
- Official AtlasCopco wordmark in the upper-right of the printed header
- Images & Graphs section between Notes and Work Time when attachments are enabled
- PDF file gets the same filename pattern as JSON exports (
<customer>_<date>_<id>.pdf) so every saved PDF has a unique, descriptive name - 2β3 page A4 layout: form fields + Psets/notes + work/travel/signatures
- Saved Reports section is hidden in print β the PDF only contains the current report, never data from other customers or interventions
- Compact print styles, hides buttons and decorative chrome
- Add to Home Screen on Android / iOS
- Install as standalone app on desktop Chrome/Edge
- Service worker pre-caches the app shell β full offline use after first load
- Branded teal theme with the new AtlasCopco wordmark, 192/512/maskable icons
- Custom date/time inputs scale gracefully on 390 px-wide screens
- Action buttons stack vertically on mobile (full-width)
- Work Time / Travel Time tables scroll horizontally instead of being truncated
- The calendar picker is touch-friendly and stays on-screen
- Fill Demo button loads a complete Stellantis NV scenario
- Safety confirm before overwriting real data
- One click to see every feature in action
Run this from the project root:
./serve.shThe launcher starts the local Python server, creates ./data/intervention_reports.sqlite3, and opens http://127.0.0.1:8000/ when possible. Use a custom port or suppress browser launch like this:
./serve.sh 8765
./serve.sh --no-browserFor a fully portable/offline stick, keep the whole folder together and either:
- use a machine that already has Python 3 +
sqlite3, or - drop a portable interpreter under
runtime/python/bin/python3, or - point
INTERVENTION_PYTHONto a local interpreter path.
The database lives in ./data/ so the app and data travel together.
- macOS:
launch-macos.command - Linux:
launch-linux.shorlaunch-linux.desktop - Windows:
launch-windows.bat(standalone;launch-windows.cmdis also provided)
Both launchers start the same local server/database path and are meant for USB-stick use.
If you want a distributable .exe, run build-windows-exe.ps1 on Windows with PyInstaller installed. It produces a frozen app folder with an InterventionReport.exe that serves the same local files and writes its database to ./data/intervention_reports.sqlite3 next to the EXE.
- Your saved reports live in
./data/intervention_reports.sqlite3. - Before updating, keep the
data/folder or copy it somewhere safe. - Update only the app files (
index.html,server.py, launchers, docs, assets). - If you use Git, run
git pull. - If you use a USB copy, overwrite the app files but do not delete
data/.
The repo still works as a static app on GitHub Pages or from index.html. When /api/health is not available, the frontend falls back to the original browser localStorage behavior.
- Android Chrome / Edge β menu β Install app
- iOS Safari β Share β Add to Home Screen
- Desktop Chrome / Edge β install icon in the address bar
Once installed it opens full-screen, runs offline, and behaves like a native app.
- Fill the report β type or paste your data. Every label has a tooltip explaining what to enter.
- Sign β toggle the signature section, draw on both pads with your finger, mouse, or stylus.
- Track time β add rows for each work block and travel trip (e.g. outbound to site, return to office). Durations and totals are calculated automatically.
- Attach images (optional) β toggle the Add images / torque graphs block to drop in photos, screenshots, or torque traces. Each image can carry a caption that prints under it on the PDF.
- Save Report β the entry appears in the Saved Reports list with full details, time tables, signature thumbnails, and attachment thumbnails.
- Print to PDF β open the browser print dialog and choose Save as PDF. The saved file gets the same descriptive name as the JSON export (e.g.
stellantis-nv-aartselaar-plant_2025-12-04_VCXMFB.pdf) and shows the branded teal header with the AtlasCopco wordmark on the first page. Attached images appear between Notes and Work Time. Hand the file to the customer. - Back up β Save to JSON downloads a portable file with a descriptive name like
stellantis-nv-aartselaar-plant_2025-12-04_VCXMFB.json(customer name sanitized, ISO date, report ID). Images are embedded as base64 data URLs so they round-trip exactly. Load from JSON restores it on any device. - Fill Demo β explore the app with one click (asks for confirmation before overwriting real data).
- The form is a single page β scroll to find any section.
- After saving, the form resets its id and date but keeps your data so you can keep working. Click Clear to start truly fresh.
- Signatures survive Save Report β they only wipe on Clear, Clone, or Load from JSON.
- Attachments survive Save Report AND Clone β they're persisted data so they carry over with the report.
| App | Single-file index.html β vanilla HTML/CSS/JS, no build step |
| PWA | manifest.json + sw.js (cache-first strategy) |
| Icons | SVG sources in icons/, exported to PNG at 32/180/192/512 px |
| Storage | SQLite via the local Python API when available; browser localStorage fallback; FileReader + Blob for JSON I/O |
| Dependencies | None |
- Storage source of truth β when launched with
./serve.sh, reports are stored as JSON records inintervention_reports.sqlite3through/api/reports. On static hosting, every report lives inlocalStorageunder the keyreportsas before. - API fallback β the frontend probes
/api/healthon startup. If the API is absent or later fails, it keeps working with browser storage and visible warnings for write failures. - Custom date & time inputs β the native
<input type="date">and<input type="time">were replaced because too many browsers ignore thelangattribute and fall back to the OS locale (MM/DD/YYYY or AM/PM). The custom inputs always show DD/MM/YYYY and HH:MM (24h), independent of platform. - Signature persistence β the canvas pixel data is captured with
toDataURL('image/png')and stored as a base64 string on the report. Restoring is justdrawImageback onto a fresh canvas. - Service worker β pre-caches the app shell on install, falls back to
index.htmlfor navigation when offline, and serves cached files before the network on every subsequent load.
intervention-report/
βββ index.html β the whole app (HTML + CSS + JS)
βββ server.py β stdlib-only local static/API server
βββ serve.sh β startup script for server + browser launch
βββ manifest.json β PWA manifest
βββ sw.js β service worker (pre-caches the app shell)
βββ icons/
β βββ icon.svg β source vector for the PWA/app icon
β βββ icon-maskable.svg β maskable variant
β βββ icon-192.png β Android home screen
β βββ icon-512.png β Android splash
β βββ icon-maskable-512.png β adaptive launcher
β βββ apple-touch-icon.png β iOS home screen (180Γ180)
β βββ favicon-32.png β browser tab
β βββ atlas-copco-logo.png β official AtlasCopco wordmark used in the
β header (screen + print). Replaceable.
βββ docs/ β screenshots used by this README
β βββ screenshot-form.png β filled form (web view)
β βββ screenshot-attachments.png β Images & Graphs section
β βββ screenshot-pdf.png β printed PDF page 1
β βββ screenshot-pdf-page2.png β printed PDF page 2 (attachments)
β βββ screenshot-mobile.png β mobile view (390 px)
β βββ screenshot-mobile-calendar.png
β βββ screenshot-saved-card.png β saved report card
βββ .gitignore
This is an internal tool for Atlas Copco service engineers. If you have suggestions or bug reports, open an issue on this repo.
When working on the form:
- Use
lang="en-GB"(already set) so any future native inputs respect the right format. - New time-table rows must call
addTimeRow(tbodyId, data)β it wires up the auto-calculation. - New persistent fields must be added to
fieldMap(forcollectFormData/fillForm) and the JSON save handler. - Signatures should always round-trip through
collectSignatures()/restoreSignatures(). - Attachments should always round-trip through
collectAttachments()/restoreAttachments()β both are paired and called together in the save/load flow. - When updating the brand colour, derive all CSS variables from one source (the
:rootblock) and re-derive the dark/light/tint shades so every component stays in sync. - Test offline: open DevTools β Application β Service Workers β check Offline, then reload. Bump
CACHE_VERSIONinsw.jswhen you change the app shell so installed PWAs pick up new assets.
Internal use, Atlas Copco. All rights reserved.
Built for service technicians who need a fast, offline-capable report tool that just works on any device.





