Lumiis — Swedish Aesthetic Clinic SaaS
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.
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.
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).
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.
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.
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.
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.
Step 1.1 — Open the app
Navigating to http://lumiis.se redirects to the Swedish login screen (default locale).
Step 1.2 — Switch language to English
The language switcher (top-right) flips the entire UI. URL prefix changes from /sv/ to /en/.
Step 1.3 — SuperAdmin lands on /admin
Andreas Olsson (platform owner) signs in with [email protected]. Lands on the cross-clinic admin dashboard.
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.
Step 1.5 — Practitioner lands on /practitioner
Erik Johansson (laser therapist at Stockholm) lands on his role-specific shell.
Step 1.6 — Patient lands on /patient
Sofia Bergman (Stockholm patient) lands on her patient portal.
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.
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
Device list — dark
Audit log — dark
Arabic login — dark + RTL combined
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.
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.
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).
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.
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).
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
Every day at 09:00 Stockholm time, two cron jobs run automatically inside the production server:
next_check_due is in the past gets automatically Blocked. Clinic Owner receives an email and an in-app notification.No human intervention required — compliance violations are caught automatically and the clinic is notified through their normal alerts channel.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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).
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).
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Step 14.3 — English dark theme
Dark theme parity verified — same dark-purple surface, magenta CTA accent, all sections readable at WCAG AA contrast.
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.
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.
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).
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).
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.
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.
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
Step 17.2 — Arabic RTL + dark theme parity
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
Step 18.2 — Arabic RTL + dark theme parity
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
Step 19.2 — Practitioner thread view, Arabic RTL + dark theme
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
Step 20.2 — English dark theme parity
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
Step 21.2 — Arabic dark theme (RTL mirror)