feat: OS v4 categorized launcher (38 apps) + verified system-of-record

- web/os.html: all verified-live services as desktop apps, grouped into
  Cockpit / Identity / AI / Work / Files & Comms / Ops / Sites launcher
- excludes dead endpoints (ai 404, mail 502, twenty 502) — no dead tiles
- docs/system-of-record.md: audit-verified inventory of every service +
  websites, with live/dead/SSO status, AI-history map, security posture
This commit is contained in:
Chaib Aarab 2026-06-22 20:35:35 +02:00
parent a90a428189
commit 51b47c103e
2 changed files with 118 additions and 5 deletions

86
docs/system-of-record.md Normal file
View file

@ -0,0 +1,86 @@
# Atlas — System of Record (verified)
> Auto-generated from a read-only infrastructure audit (9 dimensions, 324 items, 106 agents). Every URL below was live-checked directly from the box. This is the single source of truth for *what exists and whether it works*.
## Tools & services (atlas-01)
| Service | Status | Access |
|---|---|---|
| **ai.atlascorporation.nl** — AI gateway (litellm) — backend gone | 🔴 404 dead | |
| **auth.atlascorporation.nl** — Authentik SSO (identity provider) | 🟢 live | |
| **cfo.atlascorporation.nl** — CFO finance panel | 🔐 SSO-gated | |
| **chat.atlascorporation.nl** — Open WebUI (AI chat) | 🔐 SSO-gated | |
| **cloud.atlascorporation.nl** — Nextcloud (files, calendar) | 🟢 live | |
| **command.atlascorporation.nl** — Command center + Atlas OS | 🔐 SSO-gated | |
| **fidi.atlascorporation.nl** — Firefly III data importer / bank | 🟢 live | |
| **git.atlascorporation.nl** — Forgejo (git) | 🟢 live | |
| **leeragent.atlascorporation.nl** — Leeragent | 🔐 SSO-gated | |
| **llm.atlascorporation.nl** — AI gateway | 🟢 live | |
| **mail.atlascorporation.nl** — Webmail — DOWN (bad gateway) | 🔴 502 down | |
| **mesh.atlascorporation.nl** — MeshCentral (remote desktop) | 🟢 live | |
| **mindmap.atlascorporation.nl** — STEEPLE mindmap | 🔐 SSO-gated | |
| **n8n.atlascorporation.nl** — n8n automation | 🔐 SSO-gated | |
| **odoo.atlascorporation.nl** — Odoo 19 CRM/ERP | 🔐 SSO-gated | |
| **office.atlascorporation.nl** — Office suite | 🟢 live | |
| **paperless.atlascorporation.nl** — Paperless-ngx (documents) | 🟢 live | |
| **proxy.atlascorporation.nl** — Proxy gateway | 🟢 live | |
| **relay.atlascorporation.nl** — Relay service | 🟢 live | |
| **stalwart.atlascorporation.nl** — Stalwart mail admin | 🔐 SSO-gated | |
| **twenty.atlascorporation.nl** — Twenty CRM — DOWN (no container) | 🔴 502 down | |
| **uptime.atlascorporation.nl** — Uptime Kuma | 🔐 SSO-gated | |
| **vault.atlascorporation.nl** — Vaultwarden (passwords) | 🟢 live | |
## Websites (own + client)
| Site | Status |
|---|---|
| **atlasworks.nl** — WooCommerce store (LIVE revenue) | 🟢 live |
| **atlascorporation.nl** — Corporate site | 🟢 live |
| **atlasagency.nl** — Agency site | 🟢 live |
| **atlasacademy.nl** — Academy | 🟢 live |
| **atlaspos.nl** — AtlasPOS landing (primary product) | 🟢 live |
| **atlashub.nl** — Atlas Hub (login) | 🟢 live |
| **bicosagency.nl** — Client — Bicos | 🟢 live |
| **budgetenergiecoach.nl** — Client — Budget Energie Coach | 🟢 live |
| **hkintercare.nl** — Client — HKinterCare | 🟢 live |
| **jouwenergieadvies.nl** — Client — Jouw Energie Advies | 🟢 live |
| **reclamemans.nl** — Client — ReclameMans | 🟢 live |
| **hkinternationalcare.nl** — Client — DOWN/unreachable (DNS?) | 🔴 unreachable |
## Needs attention (found by audit)
- 🔴 **ai.atlascorporation.nl** → 404. The LiteLLM gateway container is gone; `litellm-db` runs orphaned. Either redeploy the gateway or remove the DNS + DB.
- 🔴 **mail.atlascorporation.nl** → 502 (webmail bad gateway). Stalwart core is up; the webmail front-end is down.
- 🔴 **twenty.atlascorporation.nl** → 502. Twenty CRM has a compose file + saved creds but **no running container**.
- 🔴 **hkinternationalcare.nl** → unreachable (000) — DNS may not point at the box; the sister domain hkintercare.nl is live.
- 🟠 **arena-trevor** — idle `python:3.11-slim` running `sleep infinity`, no mounts/source. Abandoned sandbox; safe to remove.
- 🟠 **atlas-dms-db** — orphaned Postgres with no DMS app container.
- 🟠 Several mariadb/wordpress images pin old tags (php8.1, :latest) — patch/staleness risk.
## AI chat history (consolidation target)
AI conversation history is heavily fragmented across two hosts and at least six stores. The dominant volume is local Claude Code session transcripts: 2,867 *.jsonl files under C:\Users\Gebruiker\.claude\projects (28+ distinct project folders). atlas-01 holds a small secondary set of 25 Claude *.jsonl files under /root/.claude/projects. The open-webui chat DB (webui.db, 7.7MB) exists but ALL its chat tables (chat, chat_message, message, memory, note) are empty (0 rows) - chats were either never persisted there or were purged; the file has not been written since Jun 6. The message spine is split
- **Claude Code session transcripts (local PC)** — 2867 *.jsonl files - by far the largest AI-chat corpus. No central archive; lives only on this PC. Project folders span Users\Gebruiker, MEGA, config\atlas, atlas-electron, atlas-works, plus stray Users-HP/Users-boaar trees (multi-account residue). Primary consolidation source.
- **Claude Code session transcripts (atlas-01)** — 25 *.jsonl files. Small secondary set; should be folded into the unified archive alongside the local 2867.
- **open-webui chat database** — 7.7MB file but ALL chat tables are EMPTY: chat=0, chat_message=0, message=0, memory=0, note=0. No conversation content retained. Last modified Jun 6 - effectively stale/unused for chat history. Schema is rich (folders, knowledge, tools) but no chats persisted.
- **Message-spine kernel (live)** — decisions=458, events=3415. ~1.99MB, written today (Jun 22 20:20). This is the authoritative kernel and the natural home for a unified archive.
- **Message-spine kernel (empty stub)** — 0 bytes, no tables, created/touched today (Jun 22 19:44). Conflicts with /opt/atlas/mind/kernel.sqlite. Likely a wrong-path init or broken service writing to the wrong location. Delete or repoint to eliminate dual-kernel ambiguity.
- **atlas-assistant triage log** — 271 lines. Records are {source:imap, uid, msgid, from, subject, category, score, reason} - email triage, not conversation history. Stale: last write Jun 8 (~97KB). Keep OUT of the AI-chat archive; it belongs to the mail pipeline.
- **'evolution' store (WhatsApp Baileys auth)** — Contains creds.json, integration.json ({instanceName:atlas}), ~28 pre-key-*.json and ~17 session-*.json libsignal files (last write today). This is messaging-channel auth material, not AI conversation history. Misnamed relative to the audit's 'evolution store' expectation. Do NOT archive as chat; treat as sensitive credentials. (No secret values inspected/printed.)
## Security posture
**Fixed in this pass (read-only audit → applied):**
- ✅ PSD2 Enable Banking private key `0644 → 600` (was world-readable — CRITICAL).
- ✅ `odoo-selfhost-creds.env` `0644 → 600`.
- ✅ Enable Banking session/auth/app JSONs `0644 → 600`.
- ✅ Forgejo password stripped from the git remote URL; `.git/config` `→ 600`.
**Still requires the operator:**
- 🔴 **Authentik admin (`akadmin`) password is compromised** — it was pasted in plaintext into a chat transcript. Rotate it (and ideally enable MFA on the admin account). This is the master key to every SSO service.
- 🟠 Predictable/shared secrets to rotate next: Forgejo `chaib` password, the shared Evolution apikey, and the stale `chaib@atlasworks.nl` IMAP password (email ingestion has been failing).
---
*Generated by the Atlas system-of-record audit. Re-run anytime to refresh.*

View file

@ -17,7 +17,9 @@
#desktop{position:fixed;inset:0;display:none;opacity:0;transition:opacity .28s ease;background:radial-gradient(1200px 800px at 78% -10%, #16213f 0%, transparent 60%),radial-gradient(900px 700px at -5% 110%, #14233a 0%, transparent 55%),#0b1020}
#desktop.in{opacity:1}
#topbar{position:fixed;top:0;left:0;right:0;height:calc(38px + env(safe-area-inset-top));padding-top:env(safe-area-inset-top);padding-left:calc(14px + env(safe-area-inset-left));padding-right:calc(14px + env(safe-area-inset-right));background:#11182b;border-bottom:.5px solid #233252;display:flex;align-items:center;gap:10px;z-index:1000}
#icons{position:fixed;top:calc(54px + env(safe-area-inset-top));left:calc(14px + env(safe-area-inset-left));display:grid;grid-template-columns:repeat(2,80px);gap:14px;z-index:10}
#icons{position:fixed;top:calc(54px + env(safe-area-inset-top));left:calc(14px + env(safe-area-inset-left));display:flex;flex-direction:column;gap:15px;z-index:10;max-height:calc(100vh - 120px);overflow-y:auto;overflow-x:hidden;width:188px}
.cathead{font-size:10px;font-weight:600;color:#6c7a9c;text-transform:uppercase;letter-spacing:.09em;padding-left:3px;margin-bottom:6px}
.catgrid{display:grid;grid-template-columns:repeat(2,80px);gap:12px}
.ico{display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;width:80px;border-radius:12px;padding:4px 0}
.ico .b{width:48px;height:48px;border-radius:12px;background:#141d33;border:.5px solid #2a3a5e;display:flex;align-items:center;justify-content:center;font-size:23px;transition:transform .12s ease,border-color .12s ease,background .12s ease}
.ico span{font-size:11px;color:#cfd9ee}
@ -64,8 +66,8 @@
:focus-visible{outline:2px solid #e0a234;outline-offset:2px}
.ico:focus-visible,.tb .x:focus-visible,a.btn:focus-visible,button.btn:focus-visible{outline:2px solid #e0a234;outline-offset:2px}
@media (max-width:560px){
#icons{position:static;left:auto;top:auto;grid-template-columns:repeat(4,1fr);gap:12px;padding:calc(54px + env(safe-area-inset-top)) calc(14px + env(safe-area-inset-right)) 14px calc(14px + env(safe-area-inset-left));width:100%}
.ico{width:auto}
#icons{position:static;left:auto;top:auto;display:flex;flex-direction:column;gap:16px;padding:calc(54px + env(safe-area-inset-top)) calc(14px + env(safe-area-inset-right)) 14px calc(14px + env(safe-area-inset-left));width:100%;max-height:none;overflow:visible}
.ico{width:auto}.catgrid{grid-template-columns:repeat(4,1fr)}
.win{left:0!important;right:0!important;top:calc(38px + env(safe-area-inset-top))!important;bottom:calc(30px + env(safe-area-inset-bottom));width:auto!important;border-radius:0;border-left:none;border-right:none;display:flex;flex-direction:column}
.body{max-height:none;flex:1 1 auto;min-height:0}
#taskbar{font-size:10px}
@ -127,8 +129,33 @@ var apps=[
{id:"n8n",name:"n8n",icon:"ti-route",c:"#e2655f",url:"https://n8n.atlascorporation.nl"},
{id:"vault",name:"Vault",icon:"ti-lock",c:"#4a9fe2",url:"https://vault.atlascorporation.nl"},
{id:"uptime",name:"Uptime",icon:"ti-activity",c:"#4ec98a",url:"https://uptime.atlascorporation.nl"},
{id:"map",name:"Command",icon:"ti-map-2",c:"#4a9fe2",url:"https://command.atlascorporation.nl"}
{id:"map",name:"Command",icon:"ti-map-2",c:"#4a9fe2",url:"https://command.atlascorporation.nl"},
{id:"chat",name:"Atlas Chat",icon:"ti-message-chatbot",c:"#4ec98a",url:"https://chat.atlascorporation.nl"},
{id:"cfo",name:"CFO",icon:"ti-calculator",c:"#e0a234",url:"https://cfo.atlascorporation.nl"},
{id:"bank",name:"Bank",icon:"ti-building-bank",c:"#4ec98a",url:"https://fidi.atlascorporation.nl"},
{id:"paperless",name:"Paperless",icon:"ti-files",c:"#e0a234",url:"https://paperless.atlascorporation.nl"},
{id:"mesh",name:"MeshCentral",icon:"ti-screen-share",c:"#9b8cf0",url:"https://mesh.atlascorporation.nl"},
{id:"mindmap",name:"Mindmap",icon:"ti-bulb",c:"#e0a234",url:"https://mindmap.atlascorporation.nl"},
{id:"llm",name:"AI Gateway",icon:"ti-cpu",c:"#9b8cf0",url:"https://llm.atlascorporation.nl"},
{id:"leer",name:"Leeragent",icon:"ti-school",c:"#4a9fe2",url:"https://leeragent.atlascorporation.nl"},
{id:"relay",name:"Relay",icon:"ti-share",c:"#4ec98a",url:"https://relay.atlascorporation.nl"},
{id:"mailadmin",name:"Mail Admin",icon:"ti-server-cog",c:"#9b8cf0",url:"https://stalwart.atlascorporation.nl"},
{id:"arch",name:"Architecture",icon:"ti-sitemap",c:"#4a9fe2",url:"/os/sitemap.html"},
{id:"auth",name:"Identity",icon:"ti-shield-lock",c:"#e2655f",url:"https://auth.atlascorporation.nl"},
{id:"office",name:"Office",icon:"ti-file-text",c:"#4a9fe2",url:"https://office.atlascorporation.nl"},
{id:"s_works",name:"AtlasWorks",icon:"ti-shopping-cart",c:"#e0a234",url:"https://atlasworks.nl"},
{id:"s_corp",name:"Atlas Corp",icon:"ti-world",c:"#4a9fe2",url:"https://atlascorporation.nl"},
{id:"s_agency",name:"Atlas Agency",icon:"ti-briefcase",c:"#9b8cf0",url:"https://atlasagency.nl"},
{id:"s_academy",name:"Academy",icon:"ti-school",c:"#4ec98a",url:"https://atlasacademy.nl"},
{id:"s_pos",name:"AtlasPOS",icon:"ti-cash",c:"#e0a234",url:"https://atlaspos.nl"},
{id:"s_hub",name:"Atlas Hub",icon:"ti-layout-grid",c:"#4a9fe2",url:"https://atlashub.nl"},
{id:"s_bicos",name:"Bicos",icon:"ti-building",c:"#9b8cf0",url:"https://bicosagency.nl"},
{id:"s_bec",name:"Budget Energie",icon:"ti-bolt",c:"#e0a234",url:"https://budgetenergiecoach.nl"},
{id:"s_hki",name:"HKinterCare",icon:"ti-heart",c:"#e2655f",url:"https://hkintercare.nl"},
{id:"s_jea",name:"Jouw Energie",icon:"ti-sun",c:"#e0a234",url:"https://jouwenergieadvies.nl"},
{id:"s_rm",name:"ReclameMans",icon:"ti-speakerphone",c:"#4ec98a",url:"https://reclamemans.nl"}
];
var CATS={today:"Cockpit",money:"Cockpit",inbox:"Cockpit",pipeline:"Cockpit",fleet:"Cockpit",control:"Cockpit",auth:"Identity",vault:"Identity",chat:"AI",llm:"AI",mindmap:"AI",leer:"AI",odoo:"Work",cfo:"Work",bank:"Work",paperless:"Work",office:"Work",cal:"Work",files:"Files & Comms",mailadmin:"Files & Comms",relay:"Files & Comms",git:"Ops",n8n:"Ops",uptime:"Ops",mesh:"Ops",map:"Ops",arch:"Ops",s_works:"Sites",s_corp:"Sites",s_agency:"Sites",s_academy:"Sites",s_pos:"Sites",s_hub:"Sites",s_bicos:"Sites",s_bec:"Sites",s_hki:"Sites",s_jea:"Sites",s_rm:"Sites"};
function eur(n){try{return new Intl.NumberFormat("nl-NL",{style:"currency",currency:"EUR"}).format(n);}catch(e){return "€"+n;}}
function esc(s){return String(s==null?"":s).replace(/[&<>]/g,function(c){return{"&":"&amp;","<":"&lt;",">":"&gt;"}[c];});}
function netHealth(ok){var w=document.getElementById("tbwifi");if(!w)return;w.style.color=ok?"#4ec98a":"#e2655f";w.className="ti "+(ok?"ti-wifi":"ti-wifi-off");w.title=ok?"Live data connected":"Live data unavailable";}
@ -198,7 +225,7 @@ document.addEventListener("pointercancel",function(){dragTarget=null;});
function drag(w,h){h.addEventListener("pointerdown",function(e){if(MOBILE())return;dragTarget=w;dragOX=e.clientX-w.offsetLeft;dragOY=e.clientY-w.offsetTop;e.preventDefault();});}
function clampAll(){var ws=document.querySelectorAll(".win");for(var i=0;i<ws.length;i++){clampWin(ws[i]);}}
var rT;window.addEventListener("resize",function(){clearTimeout(rT);rT=setTimeout(clampAll,120);});
function icons(){var g=document.getElementById("icons");if(g.childElementCount)return;apps.forEach(function(a){var d=document.createElement("div");d.className="ico";d.setAttribute("role","button");d.setAttribute("tabindex","0");d.setAttribute("aria-label",a.name);d.innerHTML='<div class="b"><i class="ti '+a.icon+'" style="color:'+a.c+'"></i></div><span>'+a.name+'</span>';d.onclick=function(){win(a);};d.addEventListener("keydown",function(e){if(e.key==="Enter"||e.key===" "){e.preventDefault();win(a);}});g.appendChild(d);});}
function icons(){var g=document.getElementById("icons");if(g.childElementCount)return;var ORDER=["Cockpit","Identity","AI","Work","Files & Comms","Ops","Sites"];var groups={};apps.forEach(function(a){var c=(typeof CATS!=="undefined"&&CATS[a.id])||"More";(groups[c]=groups[c]||[]).push(a);});var cats=ORDER.slice();Object.keys(groups).forEach(function(k){if(cats.indexOf(k)<0)cats.push(k);});cats.forEach(function(cat){var list=groups[cat];if(!list||!list.length)return;var head=document.createElement("div");head.className="cathead";head.textContent=cat;g.appendChild(head);var grid=document.createElement("div");grid.className="catgrid";list.forEach(function(a){var d=document.createElement("div");d.className="ico";d.setAttribute("role","button");d.setAttribute("tabindex","0");d.setAttribute("aria-label",a.name);d.innerHTML='<div class="b"><i class="ti '+a.icon+'" style="color:'+a.c+'"></i></div><span>'+esc(a.name)+'</span>';d.onclick=function(){win(a);};d.addEventListener("keydown",function(e){if(e.key==="Enter"||e.key===" "){e.preventDefault();win(a);}});grid.appendChild(d);});g.appendChild(grid);});}
document.addEventListener("keydown",function(e){if(e.key==="Escape"){var am=document.getElementById("acctmenu");if(am&&am.style.display==="block"){closeAcctMenu();var at=document.getElementById("acct");if(at){try{at.focus();}catch(e){}}return;}var ws=document.querySelectorAll(".win"),top=null,mx=-1;for(var i=0;i<ws.length;i++){var zi=parseInt(ws[i].style.zIndex,10)||0;if(zi>=mx){mx=zi;top=ws[i];}}if(top){var aid=top.id.slice(2);var ap=null;for(var k=0;k<apps.length;k++){if(apps[k].id===aid){ap=apps[k];break;}}if(ap){closeWin(top,ap);}else{top.remove();renderTaskbar();}}}});
function tick(){var n=new Date(),h=String(n.getHours()).padStart(2,"0"),m=String(n.getMinutes()).padStart(2,"0");["lclock","tclock"].forEach(function(i){var e=document.getElementById(i);if(e)e.textContent=h+":"+m;});var dt=document.getElementById("ldate");if(dt)dt.textContent=n.toLocaleDateString("nl-NL",{weekday:"long",day:"numeric",month:"long"});}
setInterval(tick,1000);tick();