Lumiis — Swedish Aesthetic Clinic SaaS

Phase 1 Progress Demo

20 working demos covering Week 1 foundation, Week 2 compliance backbone, Week 3 clinical core, and Week 4 communication + dashboards. SSMFS §13/§14/§15 compliance, GDPR-safe audit trail, Marknadsföringslagen-compliant unsubscribe landing, multi-tenant security, 3-language UI (Swedish + English + Arabic with right-to-left) from day one.

📅 21 May → 30 June 2026 🏥 Sweden EU compliance 🔒 Multi-tenant RLS
⚠️

Cosmetic polishing is still pending

All 20 demos below are functionally complete and end-to-end tested. The visual presentation — spacing, animations, micro-interactions, brand polish — will be refined in the final polish pass before go-live on 30 June. Pass 4 added Clinic Settings, Clinic Uploads, Chat UI, and Staff list screenshots. The Broadcast composer is intentionally held back from this client demo until its filed sticky-action-bar polish finding is fixed.

Phase 1 status snapshot

Week 1 — Foundation ✓ Complete

Environments, multi-tenant database with Row-Level Security, authentication for all 4 roles, full design system applied, light/dark/auto theming, Swedish locale plus English + Arabic (over-delivered).

Week 2 — Compliance Foundation ✓ Complete

Device register §15, delivery inspection §13, functional check §14 with cron-driven blocking + 7-day overdue auto-block, immutable audit log, GDPR consent versioning, cert expiry alerts at 90/60/30/7 days, SuperAdmin dashboards — all live and tested.

Week 3 — Clinical Core ✓ Complete

8-step Treatment Wizard (consent + photo + signature + completion), Form Builder with drag-and-drop and all 12 field types, Client Register with patient-ID-based search, Staff & Permissions schema with flag toggles, Swedish PDF/A archival with cryptographic signing — all live end-to-end.

Week 4 — Communication & Dashboards 🟡 In Progress (~85%)

Clinic Owner home menu, KPI dashboard, Clinic Settings, Clinic Uploads, Chat UI, broadcast backend, aftercare cron, SMTP delivery, and patient inbox API are live. Broadcast composer is live in the app but its screenshot is held from the client deck pending a small sticky action-bar visual fix.

Table of contents

1. Multi-role authentication + 3-language UI

✓ Delivered

The Week 1 foundation milestone. Login + four role-based dashboards + 3-language switching.

Promised

"OAuth + session-based authentication, role-based routing scaffold for all 4 roles, layout shells, design system with light/dark/auto themes, Swedish locale + i18n structure (future-ready English & Arabic slots)."

Source: Weekly Timeline, W1 Foundation deliverables

Delivered

All 4 role shells live + design system + light/dark/auto theming + all 3 languages fully working from day one (Swedish, English, Arabic with right-to-left layout flip). Originally we'd only promised the i18n structure with future Arabic — we shipped the complete translations as a bonus.

Walkthrough

Step 1.1 — Open the app

Navigating to http://lumiis.se redirects to the Swedish login screen (default locale).

Swedish login page

Step 1.2 — Switch language to English

The language switcher (top-right) flips the entire UI. URL prefix changes from /sv/ to /en/.

English login page

Step 1.3 — SuperAdmin lands on /admin

Andreas Olsson (platform owner) signs in with [email protected]. Lands on the cross-clinic admin dashboard.

SuperAdmin landing page

Step 1.4 — ClinicOwner lands on /clinic

Anna Lindqvist (Stockholm Skin Studio owner) lands on her clinic-scoped dashboard. Row-Level Security means she literally cannot see Gothenburg data even if she manipulates URLs.

Clinic Owner landing page

Step 1.5 — Practitioner lands on /practitioner

Erik Johansson (laser therapist at Stockholm) lands on his role-specific shell.

Practitioner landing page

Step 1.6 — Patient lands on /patient

Sofia Bergman (Stockholm patient) lands on her patient portal.

Patient landing page

Step 1.7 — Arabic with right-to-left layout

Switching to Arabic flips the entire layout direction automatically — buttons, text alignment, padding, scroll direction all mirror. Built-in for future expansion into MENA markets.

Arabic login page with RTL layout

Step 1.8 — Dark mode (automatic via OS preference + manual toggle)

Every page across every role has light, dark, and auto theming. The auto mode follows the user's operating system preference; users can override with the theme switcher. All colours come from design tokens so dark mode is consistent everywhere.

SuperAdmin landing — dark

Dark mode SuperAdmin landing

Device list — dark

Dark mode device list

Audit log — dark

Dark mode audit log

Arabic login — dark + RTL combined

Dark mode Arabic login with RTL

2. Device Register (SSMFS §15)

✓ Delivered

The first half of the Week 2 compliance backbone. Mandatory device register per SSMFS 2026:1 §15.

Promised

"Device register (SSMFS §15) — full schema, six-tab detail view, certificate upload with expiry alerts (90/60/30/7 days)."

Source: Weekly Timeline, W2 Compliance Foundation

Delivered

Device CRUD + 6-tab device detail + certificate PDF upload backed by Cloudflare R2 (EU jurisdiction for data residency) + expiry traffic-light badges. Cron-driven expiry alerts (90/60/30/7 days) shipped together with Demo 4.

Walkthrough

Step 2.1 — Device list

Anna's device list shows 4 seeded devices: Candela GentleLase Pro (Class 4 laser), Lumenis M22 IPL (Class 3B), Cynosure PicoSure (Class 4 — currently Blocked), and a "Test Overdue Device" demonstrating the cron-driven blocking from Demo 4.

Device list

Step 2.2 — Device detail (Overview tab)

Clicking a device opens the 6-tab detail page: Overview, Certificate, Delivery inspection, Functional checks, Treatment history (W3), Audit trail. Tabs use the WAI-ARIA tablist pattern with keyboard navigation (Arrow keys, Home, End).

Device detail Overview tab

Step 2.3 — Certificate tab

Active certificate with expiry traffic-light badge. The "Upload new certificate" button opens a form that streams the PDF to Cloudflare R2 in EU jurisdiction (data residency requirement met). On success, the previous certificate is automatically archived to the history list.

Certificate tab

Step 2.4 — Audit trail tab

Every status change, certificate upload, and inspection submission for this device — all permanent, append-only, never deletable (enforced at the database trigger level, even SuperAdmin cannot bypass).

Audit trail tab

Step 2.5 — Create-device form with inline validation

Zod schema validates client-side AND server-side. Notice the inline error on Serial number when a lowercase value is entered — the schema enforces uppercase A-Z, digits, and hyphens (4–32 chars). Form keeps focus on the invalid field for accessibility.

Create device form with validation error

3. Delivery Inspection Wizard (SSMFS §13)

✓ Delivered

The mandatory 5-step delivery inspection per SSMFS 2026:1 §13. Heart of the clinical compliance flow.

Promised

"Delivery inspection wizard (SSMFS §13) — 5-step flow with photo gating, signature, Approved/Conditional/Rejected outcome."

Source: Weekly Timeline, W2 Compliance Foundation

Delivered

5-step wizard with URL-persisted state (resumable mid-session), photo gating at step 2 (minimum 2 photos enforced), digital signature pad at step 5, three-state outcome with automatic device status propagation, full atomic transaction (signature + outcome + status flip all commit or nothing commits).

Walkthrough

Step 3.1 — Wizard Step 1: Device identification

The wizard's first step asks the inspector to confirm the serial number matches the physical device. The serial is read-only from the database (not editable by the inspector); a typed mismatch blocks advancement.

Inspection wizard Step 1

Step 3.2 — Step 2: Physical condition photos

Multi-file photo upload to Cloudflare R2 (EU jurisdiction). Counter enforces minimum 2 photos before advancing. Each photo is presigned for secure access; thumbnails render via presigned read URLs with 15-minute TTL.

Inspection wizard Step 2 with photos uploaded

Steps 3.3 – 3.4 — Documentation check + functional pre-check

Step 3 displays the current certificate summary so the inspector can verify against the physical paperwork. Step 4 asks the inspector to confirm the device powers on and basic functions work. Both gates require explicit confirmation before advancing.

Step 3.5 — Final step: outcome + signature

Three outcome radio options (Approved / Conditional approval / Rejected) with explanation copy. Conditional and Rejected outcomes require a note (min 10 chars). Below the outcome, a canvas signature pad captures the inspector's signature — works with mouse and touchscreen. The review summary above the submit button shows all step results + photo count + outcome + signature preview.

Inspection wizard Step 5 outcome + signature

Atomic transaction guarantee

When the inspector clicks "Submit inspection", all four operations happen inside a single database transaction: (1) inspection record saved with photos + signature, (2) device status flipped to Active (for Approved/Conditional) or remains Awaiting (for Rejected), (3) status history row written, (4) audit log entry recorded. If any step fails, the entire transaction rolls back — no half-state. This is critical for regulatory compliance.

4. Functional Check Wizard (SSMFS §14) + Cron Blocking

✓ Delivered

Recurring functional check wizard per SSMFS §14 — same engine adapted for periodic safety checks. Plus a daily cron job that automatically blocks overdue devices.

Promised

"Functional check wizard (SSMFS §14) — same engine, kind-flag toggle, cron-driven 7-day reminder." Plus: "Treatment-blocking logic when device status ≠ Active or inspection overdue."

Source: Weekly Timeline, W2 Compliance Foundation

Delivered

5-step check wizard with Passed/Failed outcomes, automatic next_check_due calculation (default 6 months), Failed result immediately blocks the device, plus a daily cron job (09:00 Europe/Stockholm time) that scans every clinic and blocks any device whose check is more than 7 days overdue — with email + in-app notification to the Clinic Owner.

Walkthrough

Step 4.1 — Check wizard Step 1

Same wizard engine as the inspection wizard, adapted for functional checks. Step 1 confirms the serial number and shows the last passed check date.

Check wizard Step 1

Step 4.2 — Step 2: Output measurement + photo of reading

The technician enters the measured value (free-text — units vary by device class) and uploads a photo of the measurement display as evidence. Photo gating enforces minimum 1 measurement photo before advancing.

Functional check Step 2 measurement input + photo

Steps 4.3 – 4.5 — Safety systems, calibration, outcome

Step 3 is a safety systems checklist (emergency stop / cooling / interlock). Step 4 verifies calibration date (must be within last 5 years) and within-tolerance reading. Step 5 captures Passed/Failed outcome + signature. Passed devices stay Active with next_check_due = today + 6 months; Failed devices immediately flip to Blocked with mandatory note.

🤖 Daily cron job — invisible compliance enforcement

Every day at 09:00 Stockholm time, two cron jobs run automatically inside the production server:

  • Overdue check scan: any Active device whose next_check_due is in the past gets automatically Blocked. Clinic Owner receives an email and an in-app notification.
  • Certificate expiry scan: any active certificate hitting the 90, 60, 30, or 7 day expiry thresholds triggers a Clinic Owner email + notification (each threshold sent exactly once via a deduplication table).

No human intervention required — compliance violations are caught automatically and the clinic is notified through their normal alerts channel.

5. Audit Log + Personnummer Security

✓ Delivered

Append-only, immutable audit log per SSMFS and GDPR requirements. Every action permanently recorded. Personnummer (Swedish personal numbers) never exposed in searchable fields.

Promised

"Immutable audit log infrastructure (append-only, queryable). Audit log queries for the SuperAdmin dashboard. GDPR consent versioning with full-text snapshot + IP/UA logging. Patient register schema with public ID (8-char) and personal-number storage (search-excluded)."

Source: Weekly Timeline, W2 Compliance Foundation

Delivered

Audit log table with database-level immutability triggers (no UPDATE, no DELETE — not even SuperAdmin can edit a row), filterable viewer for Clinic Owners scoped to their own clinic, cross-clinic viewer for SuperAdmin via separate database role bypass, full personnummer protection at both client and server validation layers.

Walkthrough

Step 5.1 — Clinic Owner audit log

Anna sees only Stockholm Skin Studio rows. Filters by action type, resource type, date range, actor. Search by 8-character patient public ID. Page size 50 with cursor-based pagination (handles unbounded growth).

Clinic Owner audit log viewer

Step 5.2 — Personnummer rejection (GDPR security demo)

When anyone types a personnummer-shaped value into the search box (e.g., 19920315-1234), the system rejects it with an inline error and no server call is made. Defense-in-depth: the rejection is enforced at both the client validation layer and the server Zod schema. Patients are always referenced by their 8-character public ID (e.g., SF3K9X8M) throughout the platform.

Personnummer rejection demo

Step 5.3 — Cross-clinic SuperAdmin audit view

Andreas (SuperAdmin) sees rows from every clinic with an extra Klinik column + Clinic filter dropdown. This bypass goes through a separate PostgreSQL database role (lumiis_superadmin) with explicit BYPASSRLS privilege — Anna's role can never reach this code path even if she manually crafts URLs.

SuperAdmin cross-clinic audit view

6. SuperAdmin Dashboards

✓ Delivered (narrow scope)

Platform-wide read views: clinic register, user register, cross-clinic audit, cert-expiry watchlist. Full create/suspend/plan-change management deferred to a follow-up slice pending product decisions on plan tiers and suspension semantics.

Promised

"SuperAdmin dashboard live (KPI cards, recent activity feed). User Register module (filterable directory). Clinic Register module (list, filter, detail page)."

Source: Weekly Timeline, W2 Compliance Foundation

Delivered

Clinic register list + detail with cross-module stats (device count / inspections 30d / checks 30d / staff breakdown / recent activity feed). User register with filters (role / clinic / verified) and search (name / email / public ID — never personnummer). Cross-clinic audit log viewer. Certificate expiry watchlist widget on /admin landing.

Walkthrough

Step 6.1 — Admin landing page

Three navigation chips (Audit log / Clinics / Users) plus the "Certificates expiring soon" widget showing devices with cert expiring within 90 days, sorted by closest first.

Admin landing page

Step 6.2 — Clinic register list

Both seeded clinics (Stockholm Skin Studio + Gothenburg Laser Center) with columns for org. number, owner, address, device count, inspection count (30 days), check count (30 days), and creation date.

Admin clinics list

Step 6.3 — Clinic detail with cross-module stats

Detail page shows clinic info card, owner card, 4-cell stats grid (Devices breakdown by status / Delivery inspections 30d by outcome / Functional checks 30d by result / Staff breakdown by role), and a recent activity feed with the latest 10 audit rows for this clinic.

Clinic detail page

Step 6.4 — User register

All 8 seeded users across both clinics with role badges, clinic affiliation, email-verified status, public IDs. Filters: role, clinic, email status, and search by name/email/public ID.

Admin users list

Step 6.5 — User detail with GDPR consent

Sofia's detail page shows account info + linked clinic + GDPR consent card (version + accepted date + IP address + browser User-Agent — frozen at the moment of consent). The full consent text snapshot is available via a disclosure for compliance audits. Personnummer is encrypted in the database and never appears anywhere on this page.

Sofia's user detail page

7. Bell-Icon Notifications + Cron Alerts

✓ Delivered (ahead of plan)

In-app notification system. Cron jobs emit alerts here. Clinic Owners and SuperAdmins see real-time bell-icon badges. Originally planned for Week 4 — shipped early as Week 2 collateral.

Promised

Implicit in W2 ("certificate upload with expiry alerts 90/60/30/7 days" — delivery channel originally email only). Explicit notification system was scoped for Week 4 Communication track.

Source: Weekly Timeline, W2 + W4

Delivered

In-app notification table with Row-Level Security per user, bell icon in Clinic Owner and SuperAdmin shells with unread count badge, dropdown showing latest 10 notifications with mark-as-read and mark-all-as-read actions. Wired directly to the cron jobs from Demo 4 (device blocked + cert expiring notifications).

Walkthrough

Step 7.1 — Bell icon with unread count

Top-right corner of the Clinic Owner shell shows the bell icon with a count badge for unread notifications. When the daily cron runs, fresh notifications appear here without requiring a page reload (current implementation requires re-navigation; real-time WebSocket push is queued for Week 4 Chat infrastructure).

Bell icon with unread badge

Step 7.2 — Notification dropdown

Clicking the bell opens a dropdown with the latest 10 notifications. Each entry shows the event type (Device blocked / Certificate expiring) with the device name and contextual detail (days overdue, days until expiry, expiry date). Clicking a notification navigates to the relevant device detail page and marks the notification as read. "Mark all as read" clears the badge.

Notification dropdown opened

8. Clinic Owner home — 11-card menu landing

✓ Delivered

The Clinic Owner's daily-driver landing page. Built to the spec's §5.1 layout: a clinic identity card with a copy-to-clipboard Clinic ID, then 11 navigation cards grouped into Treatment / Inspections / Register / Communication, with an inline theme switcher at the bottom. Mobile-first single-column on phones, responsive multi-column on tablet/desktop.

Promised

Per spec §5.1: clinic identity card, sections for Treatment (3 cards), Inspections (2 cards), Register (2 cards), Communication (2 cards), and Appearance (theme toggle). Mobile-first single-column layout.

Source: Lumiis spec §5.1 — Clinic Owner Home / Dashboard

Delivered

All 11 menu cards live with iconography and subtitles. Clinic ID badge with one-click copy and visual feedback. Three not-yet-shipped destinations (consultation variant, staff management, broadcast composer) carry a "Coming soon" badge and remain focusable for keyboard users. Inline three-option theme switch persists across reloads via cookie + localStorage. Full sv/en/ar parity including right-to-left layout flip on Arabic.

Walkthrough

Step 8.1 — Swedish, light theme

The default state after Anna (clinic owner) signs in. Five sections, eleven cards, identity card with the clinic's 8-character Klinik-ID (CFBD1164) ready to copy. Subdued "Översikt" + "Visa granskningslogg" text links at the bottom carry the KPI dashboard + audit-log entry points without crowding the menu.

Clinic Owner home — Swedish, light

Step 8.2 — Arabic, right-to-left layout

Switching to العربية mirrors the entire interface. Logo moves to the right, theme toggle and language switcher to the left, every section heading and card label translated. Proper-noun preservation: Latin names (Anna Lindqvist, Stockholm Skin Studio) stay in Latin script as expected; the Clinic ID badge remains alphanumeric.

Clinic Owner home — Arabic, RTL

Step 8.3 — Dark theme parity

Dark theme uses a dark purple surface with magenta accent. Contrast meets WCAG AA implicitly because all colour decisions go through design tokens — no per-page colour invention. "Coming soon" badges remain legible.

Clinic Owner home — Swedish, dark

9. Clinic Owner KPI dashboard

✓ Delivered

The Week 4 communication-and-dashboards milestone deliverable. Five-card overview with a 7/30/90-day period selector. Each KPI card is independent — one slow source doesn't sink the grid.

Promised

"Clinic statistics module (30-day rolling treatments, new customers, revenue estimate, device usage, upcoming functional checks)."

Source: Weekly Timeline, W4 Communication & Dashboards

Delivered

All five cards live with URL-driven period selector (7/30/90 days), parallel-fetched server actions, and per-card error envelopes so one failing KPI doesn't blank the grid. Revenue card renders a Phase-2 placeholder note (billing model deferred). The same five endpoints are exposed under /api/v1/clinic/dashboard/* for the Clinic Owner mobile app — already consumed there.

Walkthrough

Step 9.1 — Swedish, 30-day window

"Behandlingar" shows zero completed treatments in the last 30 days — correct for this seed where Sofia's hair-removal session is 42 days old (would appear in the 90-day window). "Nya kunder" = 2 reflects Sofia + Karl seeded for the demo. "Beräknad omsättning" carries the explicit Phase-2 deferral note so the client isn't surprised by an empty figure.

Clinic Owner KPI dashboard — Swedish, light

Step 9.2 — English, dark theme

All KPI labels and copy translate cleanly to English. Dark theme uses the same design-token palette as the home landing — no per-page colour drift.

Clinic Owner KPI dashboard — English, dark

10. Client Register — search + GDPR-safe patient ID

✓ Delivered

The clinic's patient list, with name + 8-character public patient ID search. Personnummer is encrypted at rest and never displayed in the UI or returned by any API — the public ID is the patient-facing identifier across every module, per GDPR.

Promised

"Client register with 4 add methods (public ID, personal number, name+contact, walk-in) … client detail page with treatment history, linked forms, photos."

Source: Weekly Timeline, W3 Clinical Core

Delivered

Searchable list with debounced name and exact-public-ID match, cursor pagination ready for clinics with thousands of patients, per-row treatment count and last-treatment date aggregations. Per spec §5.2, three of the four add methods (manual entry, QR check-in, app invite) are scoped for the next CLT-2 slice; the personnummer-lookup method is on hold pending a compliance review of searchable-encryption tradeoffs. Same list surface available to both Clinic Owner and permission-scoped Practitioner roles.

Walkthrough

Step 10.1 — Clinic Owner view (Swedish)

Anna sees both seeded clients with their public IDs (KRL2N4P7, SF3K9X8M). Sofia's "Senaste behandling" column shows 2026-04-15 — the seeded laser hair removal session. The "+ Lägg till klient" button is visible because Anna has clinic-owner privileges; this CTA will open the four-add-methods modal in the next CLT slice.

Client Register — Clinic Owner, Swedish

Step 10.2 — Practitioner view (English)

Erik (practitioner) sees the same list scoped to the same clinic — no cross-clinic data exposed by Row-Level Security. The add-client button is intentionally hidden because the Staff & Permissions module gates "Add new patient" behind a per-practitioner flag toggle.

Client Register — Practitioner, English

11. Treatment Wizard — Step 1 of 8

✓ Delivered

The heart of the clinical workflow. Eight steps from client selection through device choice, treatment-type, consent capture, energy parameters, photo documentation, aftercare confirmation, and a final reviewable summary that triggers the Swedish-locale PDF and an audit-log trail.

Promised

"8-step treatment wizard — client selection → type & skin → assessment → consent → parameters → photo → aftercare → confirm & save. Draft auto-save every 1 second, resumable sessions, back-navigation to completed steps."

Source: Weekly Timeline, W3 Clinical Core

Delivered

All eight steps live end-to-end. Auto-save with one-second debouncing on every step. Consent capture writes an immutable join row to the Form Builder's frozen template version with the practitioner's IP + user agent. Photo upload to encrypted object storage. Step-8 completion generates a watermarked Swedish-locale PDF/A-2b archival document with a cryptographic signature. Permission-flag gates (TRT-6) and post-completion broadcast triggers (TRT-5) remain on the polish track for Week 5/6.

Walkthrough

Step 11.1 — Client picker (Swedish)

The wizard opens with an 8-step stepper (the active step glows magenta, completed steps would show a checkmark, future steps are grey). Step 1 is "Välj klient" — a search box accepts either a name or the 8-character public ID. Each result card shows the patient's name, public ID, and email. "Avbryt och gå tillbaka" provides a top-right escape hatch that preserves the draft.

Treatment Wizard — Step 1, Swedish

Step 11.2 — Arabic right-to-left

In العربية, the stepper itself flips: steps progress 1 → 8 from right to left. All copy, button labels, and helper text translate; patient names (Karl Andersson, Sofia Bergman) and IDs stay in their original Latin form so a non-Arabic-reading clinic admin can still identify the patient. The Cancel-and-return link moves to the top-left edge.

Treatment Wizard — Step 1, Arabic RTL

12. Form Builder — drag-and-drop with 12 field types

✓ Delivered

Clinics build their own consent forms, health questionnaires, and aftercare agreements. Each template is versioned: when a clinic updates a template, in-flight responses stay frozen at the version the patient accepted, preserving GDPR consent traceability.

Promised

"Form builder with drag-and-drop and 10+ field types (short text, long text, yes/no, checkbox, radio, select, signature, heading, info, section). Versioned form templates — patient responses frozen at version completed."

Source: Weekly Timeline, W3 Clinical Core

Delivered

Twelve field types live (the promised ten plus consent-block and file-upload). Drag-and-drop reordering with keyboard arrow-key fallback and screen-reader live-region announcements for accessibility. Immutability triggers at the database level prevent retroactive edits to submitted responses. The same renderer primitive is reused by the Treatment Wizard's consent step.

Walkthrough

Step 12.1 — Template list

The clinic's library of form templates with type (Consent / Aftercare / Health Declaration / Custom), audience (Patient / Staff), version number, and last-modified date. Status badges (v1 = published, Utkast = draft, Inaktiv = retired) make state visible at a glance. The seeded clinic has three templates ready to use.

Form Builder — template list

Step 12.2 — New template — initial metadata

Creating a template starts with the basics: a name, a type (Consent / Aftercare / Health Declaration), an audience, and an active toggle controlling visibility to practitioners. Once the draft is created the user lands on the drag-and-drop builder.

Form Builder — new template metadata form

Step 12.3 — Drag-and-drop builder with 12 field types

Twelve field-type "+ Add" buttons across the top (short text, long text, checkbox, single-choice, dropdown, multi-select, date, number, signature, consent block, file upload, section heading). The active draft below is the seeded "Consent — Laser Hair Removal v1" template with five fields already ordered. Click a field to open the right-side config panel; use the up/down arrows (or keyboard) to reorder. "Spara som ny version" freezes the snapshot and creates v2.

Form Builder — drag-drop with 12 field types

13. Functional check audit report

✓ Delivered

After a technician runs a functional check on a laser device (Demo 4 wizard), every result is permanently archived in the SSMFS §14 audit-format report below. Submitted reports are read-only and cannot be edited or deleted — only superseded by a newer check.

Promised

"Functional check wizard (SSMFS §14) — same engine, kind-flag toggle, cron-driven 7-day reminder … audit log captures every action." (Spec §5.7 + W2 milestone.)

Source: Weekly Timeline, W2 Compliance + Lumiis spec §5.7

Delivered

Permanent five-step archive with device identifier, submission timestamp, technician name, per-step Godkänd/Underkänd outcome with notes, photo evidence, free-text observations, and signature placeholder. Submitted reports are immutable at the database trigger layer. The cron job from Demo 4 + Demo 7 (notifications) automatically blocks devices whose next check is overdue.

Walkthrough

Step 13.1 — Detail report

The full report opens with a green "Godkänd" status, next-check date, technician name, then a card per step (Enhetsidentifiering, Utgångsmätning, Säkerhetssystem, Kalibreringsverifikation, Utfall + signatur). Step 2 attaches a measurement photo; Steps 3–4 record safety checks; Step 5 closes with the technician's signature image. "Tillbaka till enheten" returns to the device detail page.

Functional check audit report — detail

14. Treatment detail + Swedish PDF/A archival

✓ Delivered

The read-only summary of a completed treatment. Every clinical field captured by the 8-step wizard is laid out here, the Swedish PDF is one click away, and the record is immutable past completion. This is the legal document the clinic can hand to the patient or to Läkemedelsverket / Strålsäkerhetsmyndigheten on request.

Promised

"Swedish-locale PDF generation engine with watermarking (patient + timestamp + clinic). Audit anchors per treatment wizard step. PDF always in Swedish — SSMFS hard rule."

Source: Weekly Timeline W3 + Lumiis spec §5.4 Step 8

Delivered

Read-only summary card with client (public ID), device + serial, practitioner, treatment type, consent-signed marker, full energy parameter block (wavelength, fluence, pulse width, cooling, area), photo gallery, notes, session log. PDF generation is PDF/A-2b archival with a cryptographic signature via the Lumiis P12 certificate — verifiable through any PDF reader's signature panel. The PDF is auto-generated on Step-8 completion and re-downloadable on demand from the same page in either web or mobile.

Walkthrough

Step 14.1 — Swedish summary with full energy parameters

Sofia's first laser hair removal session (2026-04-15) on the Candela GentleLase Pro, performed by Erik Johansson. The Energiparametrar block shows every value Step 5 of the wizard captures: våglängd 755 nm, fluens 18 J/cm², pulsbredd 20 ms, cryogenic cooling, treated area "legs + bikini". Consent was signed at the wizard's Step 4 (timestamp recorded). The treatment is marked "Slutförd" — immutable past this point. "Ladda ner PDF" downloads the signed archival document.

Treatment detail — Swedish, light

Step 14.2 — Arabic right-to-left

Same record rendered in Arabic. All section headings translate (تفاصيل العلاج / العميل / الجهاز / الممارس / المعاملات الطاقية), value units stay Latin (J/cm², nm, ms), proper nouns and clinic-authored text stay in their original Latin script. RTL flip applies cleanly throughout.

Treatment detail — Arabic, RTL

Step 14.3 — English dark theme

Dark theme parity verified — same dark-purple surface, magenta CTA accent, all sections readable at WCAG AA contrast.

Treatment detail — English, dark

15. Functional check wizard — Step 1 entry

✓ Delivered

The entry point of the SSMFS §14 functional-check workflow. Demo 4 showed the completed audit report; this demo shows where the technician starts a new check. The wizard reuses the 5-step engine from the Delivery Inspection wizard (Demo 3) — same chrome, same Spara-utkast resume pattern, same signature canvas.

Promised

"Functional check wizard (SSMFS §14) — same engine, kind-flag toggle, cron-driven 7-day reminder." Wizard begins with device identification before measurement, safety, calibration, outcome steps.

Source: Weekly Timeline W2 + Lumiis spec §5.7

Delivered

Step 1 lands the technician on the device-identification card with the Candela's serial number pre-filled and the last-passed-check date shown for context. The 5-step indicator at the top is keyboard-navigable. The "Avbryt och gå tillbaka" link and "Spara utkast och fortsätt senare" mid-wizard save share the same engine as the Delivery Inspection wizard (Demo 3 of this doc), so the QA surface area is much smaller than two separate flows.

Walkthrough

Step 15.1 — Device identification (Swedish)

The technician opens the wizard from a device's detail page (the deviceId is implicit in the URL). Step 1 shows the device name + serial + last passed-check date — the technician confirms the serial matches what's stamped on the machine, then proceeds. The wizard validates and creates a draft on first interaction so accidental tab-close doesn't lose progress.

Functional check wizard — Step 1, Swedish

Step 15.2 — English locale

All wizard chrome strings translate cleanly: "Functional Check / Step 1 of 5 / Device identification / Verify the serial number matches the device + note last passed check. / Confirm serial number / Next / Save draft and continue later". Form labels are accessible to screen readers (every input has a programmatic label).

Functional check wizard — Step 1, English

16. Broadcast unsubscribe public landing

✓ Delivered

Swedish marketing law (Marknadsföringslagen) requires every broadcast email to carry a working unsubscribe link. The landing page recipients hit when they click that link lives outside the locale-prefixed route tree so it works whether the recipient still has a Lumiis session or not, and it derives the display language from the Accept-Language header.

Promised

"Unsubscribe link mandatory in every broadcast email — Marknadsföringslagen. Token storage in broadcast_recipient; landing page resolves token, records opt-out, shows confirmation." Three states: success / already / invalid.

Source: Lumiis spec §5.10 + Swedish marketing-law compliance

Delivered

Public landing at /unsubscribe/{token}. Three rendered states with Swedish + English + Arabic copy chosen via Accept-Language fallback (no locale prefix in the URL). Token resolution + opt-out write happen server-side with a SuperAdmin-bypass query so the unauthenticated recipient is never asked to log in. Theme cookie is read by the new root layout, so a recipient who set Dark Mode earlier in the Lumiis app gets dark-mode unsubscribe page too. Audit trail records the opt-out as a BroadcastRecipient resource type — only when the click is the first opt-out (idempotent against repeat clicks).

Walkthrough

Step 16.1 — Invalid-link state, light theme

When a token is expired, malformed, or simply not in the database (e.g., the recipient bookmarked the URL and clicked years later, or a bot fuzzing tokens), the landing shows a friendly "Invalid link / This unsubscribe link is invalid or has expired" card. Minimal chrome — just the Lumiis brand mark — so a recipient with no Lumiis context isn't confused by a full app shell.

Unsubscribe public landing — invalid token, light

Step 16.2 — Same state, dark theme

The new root layout reads the Lumiis theme cookie even on non-locale routes, so recipients who previously chose Dark Mode see a dark unsubscribe page when they click the link. Both themes use the same design-token palette as the rest of the app, so the brand remains consistent across the entire flow from clinic dashboard → broadcast send → patient inbox → unsubscribe.

Unsubscribe public landing — invalid token, dark

17. Clinic Settings

✓ Delivered

Clinic Owner settings for profile data, opening hours, consent disclaimer, default language, and notification preferences.

Promised

"Clinic Settings" per BN §5.11, scoped in DSH-3 to profile, hours, consent, and notifications. Master-data CRUDs are deferred to DSH-3b.

Delivered

Four settings sections render from clinic-scoped server actions. Seeded Stockholm Skin Studio hours show Monday-Friday 09:00-18:00, with Swedish consent text ready for new treatments.

Step 17.1 — Settings overview

Clinic settings in Swedish light theme

Step 17.2 — Arabic RTL + dark theme parity

Clinic settings in Arabic dark theme

18. Clinic Uploads

✓ Delivered

Private clinic file library with patient visibility toggles and short-lived signed share links.

Promised

Upload PDF, JPG, PNG, or MP4 files, keep them private by default, mark selected files visible to clients, and generate a 7-day signed URL when sharing externally.

Delivered

Two seeded files are visible in Stockholm Skin Studio: a visible Swedish PDF and a private JPG. Sharing expands the row with a signed URL, copy action, and expiry timestamp.

Step 18.1 — Share-expanded PDF row

Clinic uploads share-expanded Swedish light theme

Step 18.2 — Arabic RTL + dark theme parity

Clinic uploads share-expanded Arabic dark theme

19. Chat UI

✓ Delivered

Two-column clinical chat workspace for Clinic Owners and Practitioners, with seeded Anna/Sofia messages and read receipts.

Promised

CHT-3 web chat: thread list, message pane, composer, read receipts, treatment link when present, and file attachments deferred to CHT-3b.

Delivered

Clinic Owner and Practitioner routes share the same real-time-ready workspace. Screens show only Sofia's public ID, never personnummer. The attachment control is present but disabled for the deferred attachment slice.

Step 19.1 — Clinic Owner thread view

Clinic chat thread Swedish light theme

Step 19.2 — Practitioner thread view, Arabic RTL + dark theme

Practitioner chat thread Arabic dark theme

20. Staff list

✓ Delivered

Clinic Owner staff overview with searchable practitioners, public IDs, permission chips, and active status.

Promised

STF-2 staff list UI for Clinic Owners, with invite and flag-edit flows visually marked as the next slices.

Delivered

Erik and Maria appear with public IDs, email, specialty, active badge, and permission chips. Invite and edit actions are present as disabled placeholders until STF-3/STF-4.

Step 20.1 — Staff permissions table

Clinic staff list Swedish light theme

Step 20.2 — English dark theme parity

Clinic staff list English dark theme

21. Broadcast composer

✓ Delivered

Mass-broadcast compose surface for Clinic Owners — subject, message with personalisation variable chips ({firstname}, {lastname}, {clinic_name}, {last_treatment_date}), audience picker with live recipient count, send-now or schedule-for-later, save-as-draft and test-send. Unsubscribe link is auto-appended per Marknadsföringslagen.

Promised

BRD-2b broadcast composer with personalisation, audience filters with live preview, schedule-for-later, soft cap (10/day) + hard cap (50/day), and the legally required unsubscribe link.

Delivered

Subject + message + 4 personalisation chips + 3-tab audience picker (All / Selected / By treatment type) with "2 kommer att få meddelandet" live count, schedule controls, and a clean bottom action bar (Spara som utkast / Skicka testmeddelande / Skicka). Email transport hits SMTP via nodemailer (BRD-4) with the auto-appended unsubscribe footer in sv/en/ar.

Step 21.1 — Composer in Swedish light theme

Broadcast composer Swedish light theme

Step 21.2 — Arabic dark theme (RTL mirror)

Broadcast composer Arabic dark theme RTL