Clio/Stripe competitive benchmark, moslem03/04 backend reality check, and the moslem04 sync API spec, plus the resolved schema-per-tenant isolation decision that unblocks Phase 2 of the sync spec.
260 lines
10 KiB
HTML
260 lines
10 KiB
HTML
<title>Falah OS — Backend Integration Reality Check</title>
|
|
<style>
|
|
:root {
|
|
--bg: #f6f5ef;
|
|
--bg-panel: #ffffff;
|
|
--ink: #1b2420;
|
|
--ink-soft: #4d5951;
|
|
--line: #dbd9cd;
|
|
--line-strong: #b9b6a6;
|
|
--accent: #2f6e52;
|
|
--accent-soft: #e3ede7;
|
|
--warn: #a6432e;
|
|
--warn-bg: #f6e6e1;
|
|
--future: #9a7327;
|
|
--future-bg: #f2e9d4;
|
|
--node-bg: #ffffff;
|
|
}
|
|
:root[data-theme="dark"] {
|
|
--bg: #141815;
|
|
--bg-panel: #1b201c;
|
|
--ink: #e9e7dd;
|
|
--ink-soft: #a9b0a7;
|
|
--line: #333a34;
|
|
--line-strong: #48524a;
|
|
--accent: #6bbf94;
|
|
--accent-soft: #212b24;
|
|
--warn: #e08268;
|
|
--warn-bg: #2c1e1a;
|
|
--future: #e3bd6a;
|
|
--future-bg: #2b2416;
|
|
--node-bg: #1f2420;
|
|
}
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not([data-theme="light"]) {
|
|
--bg: #141815;
|
|
--bg-panel: #1b201c;
|
|
--ink: #e9e7dd;
|
|
--ink-soft: #a9b0a7;
|
|
--line: #333a34;
|
|
--line-strong: #48524a;
|
|
--accent: #6bbf94;
|
|
--accent-soft: #212b24;
|
|
--warn: #e08268;
|
|
--warn-bg: #2c1e1a;
|
|
--future: #e3bd6a;
|
|
--future-bg: #2b2416;
|
|
--node-bg: #1f2420;
|
|
}
|
|
}
|
|
* { box-sizing: border-box; }
|
|
html, body { margin: 0; background: var(--bg); color: var(--ink); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; }
|
|
body { padding: clamp(1.25rem, 4vw, 3rem); display: flex; justify-content: center; }
|
|
main { width: 100%; max-width: 900px; display: flex; flex-direction: column; gap: 2.5rem; }
|
|
|
|
.masthead { display: flex; flex-direction: column; gap: 0.5rem; padding-bottom: 1.25rem; border-bottom: 2px solid var(--ink); }
|
|
.eyebrow { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
|
|
h1 { margin: 0; font-size: clamp(1.5rem, 3.4vw, 2rem); font-weight: 700; letter-spacing: -0.01em; text-wrap: balance; }
|
|
.dek { margin: 0; max-width: 60ch; font-size: 0.98rem; line-height: 1.5; color: var(--ink-soft); }
|
|
|
|
h2.section-title {
|
|
display: flex; align-items: center; gap: 0.6rem;
|
|
font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase;
|
|
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
color: var(--ink-soft); margin: 0 0 1.1rem 0;
|
|
}
|
|
h2.section-title .n { color: var(--ink); font-weight: 700; }
|
|
|
|
/* ---- Diagram 1: today ---- */
|
|
.diagram {
|
|
border: 1px solid var(--line-strong);
|
|
border-radius: 6px;
|
|
background: var(--bg-panel);
|
|
padding: clamp(1.25rem, 3vw, 2rem);
|
|
overflow-x: auto;
|
|
}
|
|
.row { display: flex; align-items: center; gap: 0; min-width: 640px; }
|
|
.node {
|
|
flex: 1;
|
|
border: 1.5px solid var(--line-strong);
|
|
border-radius: 6px;
|
|
background: var(--node-bg);
|
|
padding: 0.9rem 1rem;
|
|
text-align: center;
|
|
display: flex; flex-direction: column; gap: 0.25rem;
|
|
}
|
|
.node .label { font-weight: 700; font-size: 0.92rem; }
|
|
.node .sub { font-size: 0.74rem; color: var(--ink-soft); }
|
|
.arrow {
|
|
flex: 0 0 60px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-family: ui-monospace, monospace;
|
|
color: var(--ink-soft);
|
|
font-size: 1.1rem;
|
|
}
|
|
.node.app { border-color: var(--accent); background: var(--accent-soft); }
|
|
.node.api { border-style: dashed; }
|
|
.node.void { border-color: var(--warn); background: var(--warn-bg); border-style: dashed; color: var(--warn); }
|
|
.node.void .label { color: var(--warn); }
|
|
|
|
.three-up { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.9rem; margin-top: 1rem; min-width: 640px; }
|
|
.three-up .node .sub { line-height: 1.35; }
|
|
|
|
.badge-row { display: flex; gap: 0.6rem; margin-top: 1.1rem; flex-wrap: wrap; }
|
|
.badge {
|
|
font-family: ui-monospace, monospace; font-size: 0.68rem; font-weight: 700;
|
|
letter-spacing: 0.04em; text-transform: uppercase;
|
|
padding: 0.25rem 0.6rem; border-radius: 3px;
|
|
}
|
|
.badge.no { color: var(--warn); background: var(--warn-bg); }
|
|
|
|
/* ---- Diagram 2: what needs building ---- */
|
|
.stack { display: flex; flex-direction: column; gap: 0; min-width: 560px; }
|
|
.layer {
|
|
display: grid;
|
|
grid-template-columns: 30px 1fr;
|
|
border: 1.5px solid var(--line-strong);
|
|
border-top: none;
|
|
background: var(--node-bg);
|
|
}
|
|
.layer:first-child { border-top: 1.5px solid var(--line-strong); border-radius: 6px 6px 0 0; overflow: hidden; }
|
|
.layer:last-child { border-radius: 0 0 6px 6px; overflow: hidden; }
|
|
.layer-num {
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-family: ui-monospace, monospace; font-size: 0.78rem; font-weight: 700;
|
|
color: var(--ink-soft); background: color-mix(in srgb, var(--ink) 4%, transparent);
|
|
border-right: 1px solid var(--line);
|
|
}
|
|
.layer-body { padding: 0.85rem 1.1rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
|
|
.layer-body .title { font-weight: 700; font-size: 0.92rem; }
|
|
.layer-body .desc { font-size: 0.8rem; color: var(--ink-soft); }
|
|
.layer.exists { }
|
|
.layer.exists .layer-num { color: var(--accent); }
|
|
.layer.missing .layer-num { color: var(--future); }
|
|
.status {
|
|
font-family: ui-monospace, monospace; font-size: 0.66rem; font-weight: 700;
|
|
letter-spacing: 0.05em; text-transform: uppercase; padding: 0.18rem 0.5rem; border-radius: 3px;
|
|
white-space: nowrap;
|
|
}
|
|
.status.exists { color: var(--accent); background: var(--accent-soft); }
|
|
.status.missing { color: var(--future); background: var(--future-bg); }
|
|
|
|
.legend { display: flex; gap: 1.3rem; flex-wrap: wrap; font-size: 0.78rem; color: var(--ink-soft); margin-top: 1rem; }
|
|
.legend span { display: inline-flex; align-items: center; gap: 0.4rem; }
|
|
.dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
|
|
.dot.exists { background: var(--accent); }
|
|
.dot.missing { background: var(--future); }
|
|
|
|
footer { padding-top: 1.25rem; border-top: 1px solid var(--line); font-size: 0.78rem; color: var(--ink-soft); }
|
|
footer strong { color: var(--ink); }
|
|
</style>
|
|
|
|
<main>
|
|
<div class="masthead">
|
|
<span class="eyebrow">Falah OS — checked against the actual repos</span>
|
|
<h1>moslem03 has no backend either — same gap as moslem04</h1>
|
|
<p class="dek">Verified against <code>nur-muslim-companion-v2</code> and <code>nur-falah-prevention</code> source. Neither app talks to a Falah OS server. There is no existing pattern to copy — the admin console link has to be built from zero.</p>
|
|
</div>
|
|
|
|
<section>
|
|
<h2 class="section-title"><span class="n">01</span> · What moslem03 actually does today</h2>
|
|
<div class="diagram">
|
|
<div class="row">
|
|
<div class="node app">
|
|
<span class="label">moslem03.falahos.my</span>
|
|
<span class="sub">Svelte 5 PWA · static build</span>
|
|
</div>
|
|
<div class="arrow">→</div>
|
|
<div class="node api">
|
|
<span class="label">Public third-party APIs</span>
|
|
<span class="sub">Al Quran Cloud · Aladhan · Overpass</span>
|
|
</div>
|
|
</div>
|
|
<div class="three-up">
|
|
<div class="node void">
|
|
<span class="label">✕ No auth</span>
|
|
<span class="sub">Anyone opens the app, no login</span>
|
|
</div>
|
|
<div class="node void">
|
|
<span class="label">✕ No Falah OS server</span>
|
|
<span class="sub">Never calls anything on the Contabo VPS</span>
|
|
</div>
|
|
<div class="node void">
|
|
<span class="label">✕ No admin console link</span>
|
|
<span class="sub">Nothing to sync — data never leaves the browser</span>
|
|
</div>
|
|
</div>
|
|
<div class="badge-row">
|
|
<span class="badge no">Same for moslem04</span>
|
|
<span class="badge no">Same localStorage-only pattern</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<h2 class="section-title"><span class="n">02</span> · What has to be built — bottom up</h2>
|
|
<div class="diagram">
|
|
<div class="stack">
|
|
<div class="layer exists">
|
|
<div class="layer-num">✓</div>
|
|
<div class="layer-body">
|
|
<div>
|
|
<div class="title">casdoor (ummahid) identity service</div>
|
|
<div class="desc">Already running on the Contabo VPS :8000 — reuse it, don't rebuild login</div>
|
|
</div>
|
|
<span class="status exists">Already exists</span>
|
|
</div>
|
|
</div>
|
|
<div class="layer missing">
|
|
<div class="layer-num">1</div>
|
|
<div class="layer-body">
|
|
<div>
|
|
<div class="title">Login screen in moslem04</div>
|
|
<div class="desc">App currently has zero auth UI — needs a casdoor sign-in flow bolted on</div>
|
|
</div>
|
|
<span class="status missing">To build</span>
|
|
</div>
|
|
</div>
|
|
<div class="layer missing">
|
|
<div class="layer-num">2</div>
|
|
<div class="layer-body">
|
|
<div>
|
|
<div class="title">Sync API (new)</div>
|
|
<div class="desc">Push Faraid / Assets / Wassiyah / Hibah / Waqf drafts from localStorage to a server, encrypted</div>
|
|
</div>
|
|
<span class="status missing">To build</span>
|
|
</div>
|
|
</div>
|
|
<div class="layer missing">
|
|
<div class="layer-num">3</div>
|
|
<div class="layer-body">
|
|
<div>
|
|
<div class="title">RAMZ tenant tagging</div>
|
|
<div class="desc">Every synced record gets stamped with which tenant/firm it belongs to</div>
|
|
</div>
|
|
<span class="status missing">To build</span>
|
|
</div>
|
|
</div>
|
|
<div class="layer missing">
|
|
<div class="layer-num">4</div>
|
|
<div class="layer-body">
|
|
<div>
|
|
<div class="title">Admin console read view</div>
|
|
<div class="desc">Nur Falah Admin Console reads synced cases — view only, not edit</div>
|
|
</div>
|
|
<span class="status missing">To build</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="legend">
|
|
<span><span class="dot exists"></span> exists on the VPS today</span>
|
|
<span><span class="dot missing"></span> needs to be built — nothing to copy from moslem03</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<footer>
|
|
<strong>Bottom line:</strong> moslem03 gave us one reusable piece — casdoor login. Everything else (sync, tenant tagging, admin visibility) starts from scratch.
|
|
</footer>
|
|
</main>
|