// Use cases + AI onboarding — translating "build anything" into buyer language const { useState: useStateU, useEffect: useEffectU, useRef: useRefU } = React; /* ============================================================================= USE CASES — buyers don't search for "low-code platform", they search for the specific thing that's broken. Lead with their words. ============================================================================= */ const USE_CASES = [ { id: "spreadsheet", said: "Replace our spreadsheet-based approval process.", tag: "Operations", pain: "A shared workbook nobody trusts, an approval chain that lives in email, and no way to prove who signed off what.", build: "A multi-stage approval workflow with electronic authorisation, conditional routing and a full audit trail. Approvers act from an email link; the record updates itself.", parts: ["Workflows", "Electronic authorisation", "Auditing", "E-mail templates"], proof: ["Every decision timestamped and attributable", "Rollback to any previous version", "No more 'which copy is current?'"], weeks: "2–4", }, { id: "portal", said: "Launch a secure customer portal.", tag: "Customer-facing", pain: "Customers phone and email for information you already hold. Staff re-key it. Nobody has a self-service option.", build: "A branded portal where customers log in to see only their own records — documents, orders, cases, invoices — with row-level permissions enforced by the platform, not by hope.", parts: ["Security groups", "Row-level permissions", "2FA", "Document management"], proof: ["Default-deny access model", "SSO or platform accounts", "Custom domain and theme"], weeks: "3–6", }, { id: "access", said: "Modernise our Access database.", tag: "Migration", pain: "A business-critical Access or Excel system built by someone who left. It only runs on one machine, has no backups, and breaks when Windows updates.", build: "Drop the spreadsheet in and easy-create mode detects field types and builds a proper datastore. You get web access, real permissions, backups, audit and an API — same data, no rewrite.", parts: ["Easy-create mode", "Data Import System", "Datastores", "Deployments"], proof: ["5 import methods incl. update-existing", "Multi-user from day one", "Accessible anywhere, backed up nightly"], weeks: "1–3", }, { id: "supplier", said: "Build a supplier onboarding system.", tag: "Procurement", pain: "Onboarding runs on PDFs and chasing. Compliance documents expire without anyone noticing.", build: "A self-service onboarding flow with staged forms, document upload with expiry tracking, automated chase emails and an approval dashboard for your team.", parts: ["Multi-stage forms", "File uploads", "Automated tasks", "Reports"], proof: ["Suppliers complete their own data", "Expiry reminders sent automatically", "Approve or reject with reasons logged"], weeks: "3–5", }, { id: "booking", said: "Create a regulated booking and reporting platform.", tag: "Regulated", pain: "Bookings across multiple sites, capacity rules, attendance evidence — and an auditor who wants a report you can't produce.", build: "Unlimited calendars with per-location availability, slot or range booking, attendance recording, automated confirmations, and a report builder that auto-joins the underlying tables.", parts: ["Booking calendars", "Attendance recording", "Reports", "Auditing"], proof: ["Recurring availability with overrides", "E-mail and SMS confirmations", "Evidence trail for inspection"], weeks: "4–8", }, { id: "casework", said: "Track cases from referral to outcome.", tag: "Casework", pain: "Cases tracked across a mailbox, a spreadsheet and someone's memory. Reporting to funders takes days.", build: "A case management system with stages, assignment, SLA timers, document attachment and outcome recording — plus scheduled reports that email themselves to stakeholders.", parts: ["Datastores", "Workflows", "Scheduled tasks", "Summary reports"], proof: ["Full history per case", "Caseload dashboards per worker", "Funder reports generated, not assembled"], weeks: "3–6", }, { id: "saas", said: "Turn our service into a SaaS product.", tag: "Commercial", pain: "You have a process clients pay for, but no product to sell them — and building tenancy and billing from scratch is a year of work.", build: "Hard-isolated tenants with per-tenant configuration, a subscription engine with tiers and free trials, and Stripe recurring billing that pauses access on failed payment.", parts: ["Multitenancy", "Subscription engine", "Stripe", "Admin panel"], proof: ["Tenants manage their own users", "Tiered feature access", "Onboarding and billing included"], weeks: "6–10", }, { id: "integrate", said: "Get our systems talking to each other.", tag: "Integration", pain: "Finance, operations and the website all hold a version of the truth. Someone re-keys between them every week.", build: "Link external databases directly, sync datastores between instances, and expose a permission-aware REST API — with custom functions where an off-the-shelf connector won't do.", parts: ["API engine", "External databases", "Datastore sync", "Custom functions"], proof: ["Same permission rules as the UI", "Token-based clients with call logging", "No more re-keying"], weeks: "2–5", }, ]; // Track a media query (default: the ≤900px "mobile" breakpoint used for the // use-cases layout). Initialised synchronously so the very first render already // picks the right layout — no flash of the wrong variant. function useMediaQueryU(query) { const [matches, setMatches] = useStateU( () => (typeof window !== "undefined" && window.matchMedia) ? window.matchMedia(query).matches : false ); useEffectU(() => { if (typeof window === "undefined" || !window.matchMedia) return; const mq = window.matchMedia(query); const sync = () => setMatches(mq.matches); sync(); // Primary: the media-query change event (efficient, fires on breakpoint cross). if (mq.addEventListener) mq.addEventListener("change", sync); else mq.addListener(sync); // Safari < 14 // Fallback: some environments don't dispatch MQL change on resize — re-check // on window resize too. setState bails out when the value is unchanged, so // this stays cheap. window.addEventListener("resize", sync); return () => { if (mq.removeEventListener) mq.removeEventListener("change", sync); else mq.removeListener(sync); window.removeEventListener("resize", sync); }; }, [query]); return matches; } // Shared detail body for a use case. `compact` drops the tag pill + repeated // quote heading (the accordion trigger already shows those), keeping the panel // tight when it expands inline on mobile. function UseCaseDetail({ uc, onNavigate, compact }) { return (
{!compact && (
{uc.tag} {uc.weeks} weeks typical
{uc.said}
)}

What's actually going wrong

{uc.pain}

What we build

{uc.build}

Built from
{uc.parts.map(p => {p})}
); } function UseCasesSection({ onNavigate }) { const [active, setActive] = useStateU(0); const isMobile = useMediaQueryU("(max-width: 900px)"); const uc = USE_CASES[active] || USE_CASES[0]; return (
Where it fits

You're not shopping for a platform.
You're trying to fix something.

"Build almost any application" is true, and useless. Here's what people actually ask us for — pick the one that sounds like your week.

{isMobile ? ( /* Mobile: an accordion so every scenario title is visible at once — tap one to expand its detail inline (no horizontal swiping). */
{USE_CASES.map((u, i) => { const open = active === i; return (
{open && }
); })}
) : (
{USE_CASES.map((u, i) => ( ))}
)}
); } /* ============================================================================= AI ONBOARDING — answer a few questions, the platform builds v1 ============================================================================= */ const AI_SCRIPT = [ { q: "What do you want to build?", a: "A supplier onboarding system for our procurement team.", think: "Understanding the domain" }, { q: "Who will use it?", a: "Around 200 suppliers self-serving, plus 12 internal reviewers.", think: "Sizing users and roles" }, { q: "What information do you need to collect?", a: "Company details, insurance certificates, bank details and H&S policies.", think: "Deriving your data model" }, { q: "Does anything need approving?", a: "Yes — a reviewer signs off before a supplier goes active.", think: "Designing the workflow" }, { q: "Anything that expires?", a: "Insurance and H&S documents, annually.", think: "Adding expiry tracking" }, ]; const AI_OUTPUT = [ { icon: "▦", name: "4 datastores", detail: "Supplier, Document, Review, Category — with relationships" }, { icon: "▤", name: "3-stage onboarding form", detail: "Conditional fields, file upload, save-and-resume" }, { icon: "◉", name: "3 security groups", detail: "Supplier · Reviewer · Procurement Admin, row-level scoped" }, { icon: "⇄", name: "Approval workflow", detail: "Electronic authorisation with reject-and-return" }, { icon: "↻", name: "2 scheduled tasks", detail: "Expiry chase at 60 and 30 days" }, { icon: "▥", name: "Reviewer dashboard", detail: "Pending queue, ageing chart, exception list" }, ]; function AiOnboardingSection() { const [step, setStep] = useStateU(-1); // -1 idle, 0..n-1 questions, n thinking, n+1 done const [typed, setTyped] = useStateU(""); const ref = useRefU(null); const started = useRefU(false); const total = AI_SCRIPT.length; const phase = step < 0 ? "idle" : step < total ? "asking" : step === total ? "building" : "done"; // Auto-start when scrolled into view useEffectU(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver(([e]) => { if (e.isIntersecting && !started.current) { started.current = true; setStep(0); } }, { threshold: 0.3 }); io.observe(el); return () => io.disconnect(); }, []); // Type out the current answer, then advance useEffectU(() => { if (phase !== "asking") return; const answer = AI_SCRIPT[step].a; setTyped(""); let i = 0; const typer = setInterval(() => { i += 2; setTyped(answer.slice(0, i)); if (i >= answer.length) { clearInterval(typer); setTimeout(() => setStep(s => s + 1), 850); } }, 22); return () => clearInterval(typer); }, [step, phase]); // Building pause useEffectU(() => { if (phase !== "building") return; const t = setTimeout(() => setStep(s => s + 1), 2200); return () => clearTimeout(t); }, [phase]); const replay = () => { setStep(0); setTyped(""); }; return (
New · AI onboarding

Answer five questions.
Get version one.

Describing what you need is the hard part. Our AI onboarding asks about your process in plain English, then builds the datastores, forms, permissions and workflow for you — a working first version you can open, use and change.

{/* Conversation */}
Onboarding assistant {phase !== "idle" && ( )}
{AI_SCRIPT.map((s, i) => { if (step < i) return null; const answered = step > i; return (
{s.q}
{answered ? s.a : typed} {!answered && }
); })} {phase === "building" && (
Designing your application…
)} {phase === "done" && (
Version one is ready — open it and start editing.
)}
{/* Output */}
What it built {phase === "done" && Ready}
{phase !== "done" ? (
{AI_OUTPUT.map((o, i) => (
))}

{phase === "building" ? "Assembling your application…" : "Answer the questions to see the output."}

) : (
{AI_OUTPUT.map((o, i) => (
{o.icon}
{o.name} {o.detail}
))}
)}

The AI writes the first draft — not the last word. Everything it produces is ordinary platform configuration you can open in the visual builder and change, exactly as if you'd built it by hand.

); } Object.assign(window, { UseCasesSection, AiOnboardingSection, USE_CASES });