Case study · 2026
Nordic Sustainability Index
A sustainability intelligence platform that transforms unstructured Nordic food company reports into structured, comparable ESG data — backed by evidence and source references.
Data product · Next.js 15 · Supabase · TypeScript · PostgreSQL

The problem
Sustainability reporting is built for compliance, not comparison.
Companies like Carlsberg, Danish Crown and Lantmännen publish annual sustainability reports running hundreds of pages. They use different frameworks — GRI, ESRS, SASB — different baseline years, and different definitions of the same metric. Comparing disclosure quality across Nordic food companies requires months of manual work. No centralised, evidence-backed layer exists.
This matters now. The EU's CSRD and ESRS directives are rolling out mandatory structured disclosure requirements from 2024 onwards, with supply chain obligations following. Retailers, investors and procurement teams need structured data — not PDFs.
What I built
From unstructured PDFs to a structured intelligence layer.
Data extraction
Read and manually extracted indicators from 40+ company reports — annual reports, sustainability reports, and integrated disclosures. Every extracted value is linked to a page reference and the original company quote, creating a fully auditable chain from raw PDF to structured data.
Relational schema
Designed a 4-table PostgreSQL schema in Supabase: companies → sustainability reports → KPI values → KPI definitions. Normalised so adding a new KPI requires one row in kpi_definitions — not a schema migration. Adding a new company requires inserting its data without touching the structure.
KPI comparison table
A searchable comparison table showing 8 indicators across Climate, Circularity, and People for all tracked companies.
Technical approach
Architecture decisions that matter.
Data fetching runs entirely on the server via Next.js 15 App Router. The Supabase service role key is scoped to API routes and never reaches the client — a deliberate security boundary, not a default.
The relational schema was designed for extensibility from the start. A normalised 4-table structure means adding a new KPI requires one row in a definitions table, not a schema migration. Adding a new company requires only inserting its data — the structure stays unchanged.
Search is decoupled from the render cycle. Queries are debounced so the database is only hit when input stabilises, and the company record and its KPI values are fetched concurrently rather than in sequence — keeping the interaction responsive without overloading the backend.
Next.js 15 App Router · React 19 · TypeScript · Supabase PostgreSQL · Custom CSS
Outcomes
A production-ready data product.
40+
Nordic food companies mapped
350+
Sustainability indicators extracted
8
KPI categories across climate, circularity and people
Every indicator is linked to a report title, page number, and original company quote — making the data auditable rather than opaque. The index reveals patterns invisible from individual reports: which companies set near-term Scope 3 targets versus net-zero-only commitments, which disclose LTIFR versus which omit safety data entirely.
This is a disclosure index, not a performance index — transparency is what is measured, not actual environmental impact. That distinction is explicit in the framework.