feat: Passwordless cross-device authentication

- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
This commit is contained in:
Bernt
2026-07-07 07:11:50 +00:00
parent 4aa984ad74
commit 6989a98d75
61843 changed files with 5491611 additions and 872231 deletions
@@ -136,7 +136,7 @@
font-size: 14px; color: var(--text-body); padding: 6px 0;
display: flex; align-items: center; gap: 8px;
}
.feature-list li::before { content: ''; color: #00C853; font-weight: 700; }
.feature-list li::before { content: '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'; color: #00C853; font-weight: 700; }
footer { border-top: 1px solid var(--border); padding: 32px 20px; text-align: center; }
footer p { font-size: 12px; color: var(--text-muted); }
@@ -267,74 +267,74 @@
<tbody>
<tr class="highlight-row">
<td>Landvex RIOS</td>
<td class="check"> Full</td>
<td class="check"> Advanced (AMOS)</td>
<td class="check"> Integrated</td>
<td class="check"> Full offline</td>
<td class="check"> First-class</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Advanced (AMOS)</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Integrated</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full offline</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> First-class</td>
<td>Data-volume</td>
</tr>
<tr>
<td>AASHTOWare BrDR</td>
<td class="check"> Standard</td>
<td class="cross"> None</td>
<td class="cross"> None</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Standard</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="partial">~ Limited</td>
<td class="partial">~ Limited</td>
<td>Annual license</td>
</tr>
<tr>
<td>InspectTech</td>
<td class="check"> Full</td>
<td class="cross"> None</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="partial">~ 3rd party</td>
<td class="check"> Full</td>
<td class="check"> Available</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Available</td>
<td>Per-bridge</td>
</tr>
<tr>
<td>AssetWise (Bentley)</td>
<td class="check"> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="partial">~ Basic</td>
<td class="partial">~ 3rd party</td>
<td class="check"> Full</td>
<td class="check"> Available</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Available</td>
<td>Enterprise</td>
</tr>
<tr>
<td>Fulcrum</td>
<td class="partial">~ Configurable</td>
<td class="cross"> None</td>
<td class="cross"> None</td>
<td class="check"> Full</td>
<td class="check"> Available</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Available</td>
<td>Per-user</td>
</tr>
<tr>
<td>Cartegraph</td>
<td class="partial">~ Via module</td>
<td class="cross"> None</td>
<td class="cross"> None</td>
<td class="check"> Full</td>
<td class="check"> Available</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Available</td>
<td>Per-asset</td>
</tr>
<tr>
<td>Trimble Connect</td>
<td class="cross"> No</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> No</td>
<td class="partial">~ Basic</td>
<td class="check"> Integrated</td>
<td class="check"> Full</td>
<td class="check"> Available</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Integrated</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Full</td>
<td class="check"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Available</td>
<td>Enterprise</td>
</tr>
<tr>
<td>SPIDASoftware</td>
<td class="partial">~ Limited</td>
<td class="cross"> None</td>
<td class="cross"> None</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> None</td>
<td class="partial">~ Limited</td>
<td class="cross"> Limited</td>
<td class="cross"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 4L12 12M12 4L4 12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg> Limited</td>
<td>Per-structure</td>
</tr>
</tbody>
@@ -350,7 +350,7 @@
<h2 class="section-title">What to look for in bridge inspection software</h2>
<div class="feature-list">
<h4>🔍 AI Defect Detection</h4>
<h4><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="7" cy="7" r="5" stroke="#666" stroke-width="2"/><path d="M11 11L14 14" stroke="#666" stroke-width="2" stroke-linecap="round"/></svg> AI Defect Detection</h4>
<ul>
<li>Automatic crack detection on concrete and steel surfaces</li>
<li>Corrosion identification and severity scoring</li>
@@ -359,7 +359,7 @@
</ul>
</div>
<div class="feature-list">
<h4>📋 NBIS Compliance</h4>
<h4><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="3" y="2" width="10" height="12" rx="1" stroke="#666" stroke-width="1.5"/><path d="M6 5H10M6 8H10M6 11H8" stroke="#666" stroke-width="1.5" stroke-linecap="round"/></svg> NBIS Compliance</h4>
<ul>
<li>Element Level inspection ratings (NBI coding)</li>
<li>Condition state assessment per AASHTO guidelines</li>
@@ -368,7 +368,7 @@
</ul>
</div>
<div class="feature-list">
<h4>🚁 Drone Integration</h4>
<h4><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 2V6M4 4H12" stroke="#666" stroke-width="1.5" stroke-linecap="round"/><path d="M2 8H6L8 6L10 8H14" stroke="#666" stroke-width="1.5" stroke-linejoin="round"/><path d="M6 8V12H10V8" stroke="#666" stroke-width="1.5"/></svg> Drone Integration</h4>
<ul>
<li>Automated flight planning for bridge geometry</li>
<li>4K/8K imagery with GPS and timestamp metadata</li>