MASER Engineering × ICAM Toulouse · Saint-Nazaire

OLAProduction tracking for shipbuilding, from the PDF deck plan to the shop floor, offline.

Client
Maser Engineering
Role
Full-stack & AI vision pipeline
Team
Ori Dhumez-Biagi
Period
January 2025 – May 2026
Status
In production, pilot team · APK v3.0
OLA annotated deck plan with colour-coded cabin markers
Annotated deck plan · one colour square per cabin
01 · The problemMaser Engineering · cruise-ship cabins

Hundreds of cabins, tracked one by one, in zones with no network.

Progress lived on paper and scattered spreadsheets. No consolidated view, no forecast, and the ship’s steel blocks radio. OLA turns the PDF deck plan into a live production tracker that works offline on a tablet.

02 · How it worksThree moments
1

Prepare

  • Drop the PDF plan and the Excel schedule.
  • YOLO + OCR detect every cabin and read its number.
  • Thousands of tasks are generated. No manual entry.
AI import screen
AI import · tasks generated
2

Clock in the field

  • Tap a cabin on the annotated plan.
  • Update states, log hours and photos.
  • Fully offline; syncs when the network returns.
DoneBlockedTo do
Field entry dialog
Field entry · states per wagon
3

Steer

  • Progress per lot, planned vs actual hours, blockers.
  • Predicted end date from the team’s velocity.
  • Excel and PDF exports.
Dashboard
Dashboard · KPIs and end-date forecast
03 · Three technical locksSolved
Lock 01

Same square on every screen

Plan annotations drifted between PC and tablet. Fixed with normalised PDF-space coordinates. Client-validated.

Lock 02

Offline sync

IndexedDB mirror and an outbox that replays on reconnect. Conflicts resolve per task; offline wins. e2e 13/13.

Lock 03

Lots read from the plan

OCR maps each PDF page to its lot and cross-checks cabin numbers against the client nomenclature.

04 · Under the hoodWhat I actually wrote

Three layers, one source of truth.

  • Frontend. Vue 3 + Quasar SPA. pdf.js renders the deck plan, Fabric.js draws the cabin squares, pins and lines on top. A PouchDB-shaped client mirrors the project to IndexedDB and queues writes in an outbox.
  • API. Node / Express 5, routes → services → repositories on node-postgres. JWT HS256 signed server-side, bcrypt cost 12, project-scope authorisation on every route. Input hardening: UUID asserts, integer parsing, status allow-lists, transactions.
  • Data. PostgreSQL, 18 business tables + 2 auth tables + 7 analytical views, 3NF around a projet root (one project = one ship). UUID keys, cascade on the project tree. The API self-heals missing columns and views at boot.
  • AI. YOLO cabin detection through Roboflow, key proxied server-side; OCR on the PDF annotations; results cross-checked against the Excel nomenclature.
  • Ops. Docker Compose (db · api · frontend · nginx · pgAdmin), Capacitor APK for the tablets, deploy → smoke test → log, 42 times.
// offline outbox · replay on reconnect (simplified)
async function flushOutbox() {
  for (const op of await idb.getAll('outbox')) {
    try {
      await api.send(op);                   // projet:put · tache_session
      await idb.delete('outbox', op.id);
    } catch (e) {
      if (e.status !== 409) throw e;
      const server = await api.get(op.ref);
      op.body = mergeProjetLots(server, op.body); // offline wins per task
      if (op.retries++) await idb.put('dead-letter', op); // double 409
      else await idb.put('outbox', op);
    }
  }
}
window.addEventListener('online', flushOutbox);
Sync worker · IndexedDB · conflict = 409 → re-base → retry
18+2

business tables + auth tables

7

analytical SQL views feeding the dashboard

05 · ResultsIn production, pilot team
42

production deployments, smoke-tested

9 330

tasks generated in one real project

79/100

QA bugs fixed

29 pages

user guide · tablet APK v3.0

Vue 3 · QuasarNode · ExpressPostgreSQLIndexedDBDockerCapacitorYOLO · OCR