National Strategy Delivery Dashboard
Execution monitoring for a national agriculture strategy - bilingual Arabic/English, tracking strategic objectives against 2030 and 2034 targets alongside ~38 delivery initiatives with budget, timeline, and RAG status.
1. The problem
A national ministry needed to monitor execution of its multi-year agriculture strategy. Progress data lived in a working spreadsheet across three sheets in mixed Arabic and English, and leadership had no way to see, at a glance, whether the strategy was actually being delivered.
Two structural problems in the source data had to be solved before any UI work:
The objective-to-initiative mapping was wide-encoded. The mapping sheet expressed relationships as up to five repeated objective-ID columns per initiative row - with the same header text duplicated across those columns. This is a spreadsheet-native way of representing a many-to-many relationship, and it has to be normalised in code to (initiative → objective[]) before anything downstream can reason about it. Read naively, you get one arbitrary objective per initiative and quietly lose the rest of the strategy map.
Bilingual throughout. Objectives, indicators, segments, and entity labels all carry Arabic and English variants. This is not a translation layer bolted on at the end - it is a property of the data model, and the UI has to render both without either language becoming second-class.
2. Data model
Strategic objectives (~22 indicator rows): objective ID, objective and indicator in both languages, unit, baseline, target 2030, target 2034, current level, last update. Two target horizons rather than one, so progress is measured against the correct milestone rather than a single blurred endpoint.
Initiatives (~38 rows, 17 columns): bilingual objective/segment/entity labels, timeline start and end, budget to 2030, dashboard status, overall progress percentage, RAG status, owner, next milestone, and dependency/escalation notes.
Mapping: normalised in code from the wide five-column encoding into a proper many-to-many relation.
I extracted an authoritative schema document from the live workbook before building, so the type layer was derived from verified structure rather than assumption - the same discipline applied on the preceding portfolio-monitoring build.
3. Build approach - deliberate reuse and deliberate rebuild
This project ran immediately after a portfolio-monitoring dashboard in a different domain, and I made an explicit decision about what to carry over:
| Layer | Decision | Reason |
|---|---|---|
| Frontend stack (React 19, Vite, Tailwind v4, component library) | Reuse fully | Proven, current, no reason to diverge |
| Cloud static hosting + enterprise single-tenant auth | Reuse fully | Identical deployment shape |
| Header / card / KPI tile primitives | Reuse fully | Rebrand palette only |
| Sparkline, delta pill, score-ring components | Reuse partially | Only where they genuinely fit |
| Domain types | Rebuild | Strategic objectives + initiatives ≠ assets + returns |
| Calculations | Rebuild | Target-progress percentage ≠ portfolio return |
| Visualisations | Rebuild | Progress bars + RAG status + objective mapping ≠ heatmaps + return timelines |
| Bilingual Arabic/English | New | Prior build was English-only |
The judgement here is the transferable part: infrastructure and design system transfer; domain semantics do not. Reusing calculations across genuinely different domains is how you end up with a dashboard that looks right and means nothing.
Palette and visual language were rebuilt for the ministry’s domain rather than carried over from a financial-portfolio product.
4. Two things stated precisely
The data is synthetic, and generated rather than hand-written. A Python script parses a synthetic workbook and emits typed TypeScript literals marked auto-generated and not to be hand-edited. That is the right call - figures are plausible placeholders, the client’s real workbook never enters the repo, and the data layer regenerates from source rather than drifting by hand. But nothing on screen is a real ministry number.
The “AI Assistant” screen is a scripted demo, not an LLM. Answers are canned Arabic strings supplied verbatim by the requesting stakeholder, with streaming and a “thinking” indicator simulated in the UI. The code says so explicitly, and I’d rather record it here than let the label imply otherwise.
Defensible as a v1 in a 1–2 day build for a stakeholder conversation about what to build - the scripted answers were the client’s own words, so the screen accurately previews intended behaviour. But it is a clickable prototype of a chatbot, not a chatbot, and describing it as the latter would be a misrepresentation. The genuine engineering on this project is the bilingual RTL data model and the many-to-many normalisation, not the assistant.
5. What I’d highlight
- Normalising a wide-encoded many-to-many relationship - the kind of quiet data-modelling trap that invalidates a whole strategy map if missed.
- Bilingual RTL as a data-model property, not a late-stage translation pass.
- Dual target horizons (2030 / 2034) modelled explicitly so progress measures against the right milestone.
- Schema extracted and verified before building, so types derive from reality.
- Explicit reuse-versus-rebuild reasoning, delivered as a documented decision table rather than an implicit assumption.
- Fast turnaround - scoped and delivered as a 1–2 day v1 build, which is what made the client conversation possible at all.
6. Skills demonstrated
government strategy monitoring · bilingual (Arabic/English) interface development · many-to-many data normalisation · schema extraction and verification · RAG status and progress visualisation · React 19 / TypeScript / Tailwind v4 · design-system adaptation · Azure Static Web Apps · rapid delivery under stakeholder timelines