feat(boc): Complete Business Operations Center v1.0

- Go backend API with full CRUD for all modules (CRM, Sales, Finance, HR, Legal, Marketing, Support, Purchase, Inventory, Projects, Automation, Analytics)
- Rust analytics service with parallel report generation
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables, full migrations
- Redis cache, sessions, pub/sub
- Kafka event streaming with Zookeeper
- WebSocket hub for real-time updates
- Automation engine with cron jobs, workflows, event triggers
- JWT authentication, multi-tenant from start
- Docker Compose with all services
- Nginx reverse proxy with rate limiting
- Integration tests passing
- Feature gap analysis against Fortnox/Odoo/Visma

Refs: BOC-001
This commit is contained in:
Bernt
2026-07-12 12:41:35 +00:00
parent 4789a7fb48
commit 58ca4e68db
26666 changed files with 575891 additions and 2074516 deletions
+32 -9
View File
@@ -786,8 +786,8 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
<p>Gå med i de hundratals kreativa proffs som redan är i kö. Launch-zoomers får prioritets-matching och exklusiv launch-badge.</p>
<form class="signup-form" id="waitlist-form" onsubmit="submitWaitlist(event)">
<input type="text" id="wl-name" placeholder="Ditt namn" required autocomplete="name" />
<input type="tel" id="wl-phone" placeholder="Telefonnummer" required autocomplete="phone" />
<button type="submit" class="btn-primary">Anmäl mig</button>
<input type="tel" id="wl-phone" placeholder="Telefonnummer" required autocomplete="phone" inputmode="tel" />
<button type="submit" class="btn-primary" id="wl-btn">Anmäl mig</button>
</form>
<div class="waitlist-count">
<strong id="waitlist-display">482</strong> zoomers i kö — bli nummer <strong id="waitlist-next">483</strong>
@@ -863,13 +863,29 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
}
loadWaitlist();
function submitWaitlist(e) {
// Load saved phone
document.addEventListener('DOMContentLoaded', function() {
const savedPhone = localStorage.getItem('qx_phone');
if (savedPhone) {
document.getElementById('wl-phone').value = savedPhone;
}
});
async function submitWaitlist(e) {
e.preventDefault();
const name = document.getElementById('wl-name').value.trim();
const phone = document.getElementById('wl-phone').value.trim();
const btn = document.getElementById('wl-btn');
if (!name || !phone) return;
// Save phone for next time
localStorage.setItem('qx_phone', phone);
localStorage.setItem('qx_name', name);
btn.disabled = true;
btn.textContent = 'Skickar...';
waitlistCount++;
document.getElementById('waitlist-stat').textContent = waitlistCount;
document.getElementById('waitlist-display').textContent = waitlistCount;
@@ -878,12 +894,19 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
document.getElementById('waitlist-form').style.display = 'none';
document.getElementById('success-msg').style.display = 'block';
// Skicka till backend (best-effort)
fetch('https://api.quixzoom.com/api/qz/waitlist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, phone, source: 'sweden-launch-page', city: 'SE' }),
}).catch(() => {});
// Send to backend + email
try {
await fetch('https://api.quixzoom.com/api/qz/waitlist', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, phone, source: 'sweden-launch-page', city: 'SE', timestamp: new Date().toISOString() }),
});
} catch(e) {
// Fallback: email
const subject = `Ny Zoomer-registrering: ${name}`;
const body = `Ny registrering från sweden-launch:\n\nNamn: ${name}\nTelefon: ${phone}\nKälla: sweden-launch.html\nTid: ${new Date().toLocaleString('sv-SE')}`;
fetch(`mailto:hello@quixzoom.com?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`).catch(()=>{});
}
}
</script>
</body>