Initial MobilityOps build pack (docs, contracts, scaffold)

This commit is contained in:
NuklearRabbit
2026-08-01 20:34:43 +02:00
commit 24188d9b10
71 changed files with 3412 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
import { useEffect, useState } from "react";
const API = import.meta.env.VITE_API_BASE_URL ?? "";
type Status = {
service: string;
environment: string;
demo_mode: boolean;
knowledge_provider: string;
scaffold: boolean;
};
export function App() {
const [status, setStatus] = useState<Status | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
fetch(`${API}/api/v1/system/status`)
.then((response) => {
if (!response.ok) throw new Error(`API returned ${response.status}`);
return response.json();
})
.then(setStatus)
.catch((reason: unknown) => setError(reason instanceof Error ? reason.message : "Unknown error"));
}, []);
return (
<main className="shell">
<section className="hero">
<p className="eyebrow">Synthetic proof of concept</p>
<h1>MobilityOps</h1>
<p>Connected operations for vehicle rental and service teams.</p>
</section>
<section className="panel" aria-live="polite">
<h2>Scaffold status</h2>
{error && <p className="error">API unavailable: {error}</p>}
{!error && !status && <p>Connecting to the MobilityOps API</p>}
{status && (
<dl>
<div><dt>Service</dt><dd>{status.service}</dd></div>
<div><dt>Environment</dt><dd>{status.environment}</dd></div>
<div><dt>Knowledge provider</dt><dd>{status.knowledge_provider}</dd></div>
</dl>
)}
<p className="note">This is the bootable project scaffold. Claude must replace it with the complete scoped application described in the build pack.</p>
</section>
</main>
);
}
+10
View File
@@ -0,0 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
+19
View File
@@ -0,0 +1,19 @@
:root {
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
color: #172033;
background: #f3f6fa;
font-synthesis: none;
}
* { box-sizing: border-box; }
body { margin: 0; min-width: 320px; }
.shell { width: min(920px, calc(100% - 32px)); margin: 0 auto; padding: 64px 0; }
.hero { margin-bottom: 28px; }
.eyebrow { color: #315d73; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; font-size: .8rem; }
h1 { margin: 6px 0; font-size: clamp(2.4rem, 7vw, 4.8rem); line-height: 1; }
.hero > p:last-child { color: #526173; font-size: 1.2rem; }
.panel { background: white; border: 1px solid #dce3eb; border-radius: 18px; padding: 24px; box-shadow: 0 10px 30px rgba(24,40,64,.06); }
dl { display: grid; gap: 12px; }
dl div { display: flex; justify-content: space-between; gap: 24px; border-bottom: 1px solid #edf1f5; padding-bottom: 10px; }
dt { color: #607084; } dd { margin: 0; font-weight: 700; }
.note { margin-top: 24px; color: #607084; }
.error { color: #9a2530; }