Skip to content

feat: Add Carbon Atlas - business-friendly multi-policy indexer frontend#5834

Open
gautamp8 wants to merge 3 commits intohashgraph:developfrom
gautamp8:carbon-atlas
Open

feat: Add Carbon Atlas - business-friendly multi-policy indexer frontend#5834
gautamp8 wants to merge 3 commits intohashgraph:developfrom
gautamp8:carbon-atlas

Conversation

@gautamp8
Copy link
Contributor

Supports and resolves #5833

What

Carbon Atlas is a business-friendly multi-policy indexer frontend that translates Guardian's on-chain Verifiable Credentials into dashboards meaningful to carbon market stakeholders — project developers, buyers, auditors, registry operators, and sustainability officers.

It connects to the existing Guardian Indexer API with no backend changes required.

Screenshots

Dashboard

Dashboard

Trust Chain Explorer

Trust Chain

Monitoring Report (VC Renderer)

Monitoring Report

Device Data Search

Device Search

Document Verification

Verify

Current Features

  • Per-policy dashboards — summary cards (verified issuances, tCO₂e reductions, active projects, monitored devices), emission timeline chart, device distribution map
  • Trust Chain Explorer — trace any issuance through the full VC relationship graph: Approved Report → Verification Report → Monitoring Report → Daily MRV → Project → VVB
  • VC-type renderers — dedicated business-friendly views for monitoring reports (emission breakdown), verification reports (findings, GHG data), projects, device MRV data (3,254 devices with search/sort/pagination), and VVB registrations
  • Hedera proof links — every document links to its HCS message on HashScan
  • Document verification — look up any VC by consensus timestamp
  • Auth proxy — server-side JWT injection, API tokens never exposed to client
  • Caching — TanStack Query with 15 min stale, 1 hr GC

Policy Support

Policy Standard Network Status
MECD 431 Gold Standard Testnet ✅ Live
VM0033 Verra (VCS + CCB) Mainnet 🔜 Next phase

Multi-policy architecture (policy registry, URL-routed dashboards, per-policy renderers) is designed and planned as the next development phase.

Tech Stack

Next.js 16 (App Router) · React 19 · TanStack Query · shadcn/ui · Tailwind CSS 4 · Vitest

Structure

carbon-atlas/
  app/                 # Next.js App Router pages
    api/proxy/         # Auth proxy to Guardian Indexer API
    dashboard/         # Dashboard with stats, charts, recent issuances
    issuances/         # Issuance list + trust chain detail view
    projects/          # Project list + detail view
    documents/         # Generic VC document viewer
    verify/            # Document verification by consensus timestamp
  components/
    vc-views/          # Entity-type-specific VC renderers
    trust-chain/       # Trust chain visualization
    shared/            # Reusable (DeviceDataTable, HederaProofBadge)
  lib/
    api/               # API client and data fetching
    types/             # TypeScript types
    utils/             # Formatting, Hedera URLs, trust chain logic
  hooks/               # TanStack Query hooks
  __tests__/           # Vitest tests

How to Run

cd carbon-atlas
npm install
cp .env.example .env.local   # Add Guardian Indexer API token
npm run dev                   # http://localhost:3000
npm test                      # Run tests

Documentation Included

  • README.md — project overview, features, setup
  • CONTRIBUTING.md — architecture, development guidelines, how to add VC renderers
  • DEPLOYMENT.md — Vercel, Docker, Node.js/PM2, Cloudflare Pages, AWS deployment guides

@gautamp8 gautamp8 requested review from a team as code owners March 11, 2026 16:58
@Neurone
Copy link
Contributor

Neurone commented Mar 12, 2026

Hi @gautamp8, thanks for the PR, this is a great addition to the Guardian. Below there is a list of things that I would like to fix before merging the PR.

  1. all commits should be signed with a GPG key (you can add the -S flag to the commit command to sign the commit, e.g. git commit -S -m "my commit message"), in addition to have the signed-off-by line in the commit message (which is currently correctly present).

  2. any telemetry associated with the tools used by the project should be disabled by default (at the moment at least Netx.js automatically collects telemetry data when started).

  3. configure the scripts to be aware of the correct package-lock.json file in the carbon-atlas subfolder, and not to use the Guardian root one.

  4. by default, start services only on localhost, not on public interfaces (i.e. my 10.200/24 network below).

carbon-atlas git:(carbon-atlas) ✗ npm run dev

> mecd-dashboard@0.1.0 dev
> next dev

⚠ Warning: Next.js inferred your workspace root, but it may not be correct.
 We detected multiple lockfiles and selected the directory of /Users/giuseppe/workspace/guardian/yarn.lock as the root directory.
 To silence this warning, set `turbopack.root` in your Next.js config, or consider removing one of the lockfiles if it's not needed.
   See https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopack#root-directory for more information.
 Detected additional lockfiles:
   * /Users/giuseppe/workspace/guardian/carbon-atlas/package-lock.json

▲ Next.js 16.1.6 (Turbopack)
- Local:         http://localhost:3000
- Network:       http://10.200.12.221:3000
- Environments: .env

✓ Starting...
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

✓ Ready in 1058ms
  1. see comment below for updates on this point. Former requirement: add a script to generate the indexer bearer token starting from the username and password. At the moment I'm using a token derived by the browser development console after logging in to the indexer web interface, but it would be nice to have a script to generate it automatically.

  2. when started for the first time in dev mode, I get the following error: "A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:[...]."

Screenshot 2026-03-12 at 21 51 11
  1. the top-right GitHub button leads to the original repository, it should bring to the Guardian one instead.

  2. In the "View monitoring report", "Monitoring Report (Auto)", "Calculated Project", and "Project Design Document" sections, the content of the view Raw VC field should be formatted as JSON. This would make it easier to read and it should also solve the issue on the UI creating a long string that breaks the layout.

Screenshot 2026-03-12 at 21 57 19
  1. The ATEC logo in the top-right near the "Project Developer" label is super tiny. Please make it bigger and more visible.

  2. In general for the use of other companies logos, please include in the README of the repo a section dedicated to the permissions, something that states that we asked and obtained the permission to use the logo, and that we are using it in a respectful way, etc. Also, clarify that we don't own any rights on those logos, they are the property of the respective companies, and we will remove them from the repository in case requested by the respective companies.

  3. In the "Device MRV Data" section, the formatting is also not present, but on the contrary the size of the text field. It does not break the layout in this case, but always applying a JSON formatting for all these "view raw" fields is probably still the best option.

  4. in the "Issuances" page I can see "page 1 of 1" and the buttons to go back and forth, but I cannot see how many items I'm going to see per page. Probably we can remove these controls and information when there's only a single page of results.

Screenshot 2026-03-12 at 22 07 19
  1. in the "Projects" page I don't see the page controls I see in the "Issuances" page. If they are there and hidden because of the number of results, fine. Otherwise, please add the pagination features also to the "Projects" page, and any other page that lists of an undefined number of items.

  2. the "View" and "Trust Chain" actions use an icon that is normally associated with an external website. That works fine for the links to Hashscan, but please use another icon (or no icon at all) for the actions brining the user to another page of the same application, to avoid confusion.

  3. in the "Issuances" page, the transaction ID of the issuance is called "Document ID". Is that expected/correct?

  4. in the "Projects" page I can see two rows with two states, the first one Validated the second one NEW.

    • I suggest to use "New" for the status, not "NEW", or use "VALIDATED" instead of "Validated", to be consistent in the use of uppercase/lowercase.
    • When I check the details of the New project, the "status" in the detailed page is "Draft" instead of "New".
  5. In the "Issuances" and "Projects" pages, I cannot read or copy the entire issuer ID. The information seems truncated server side, so regardless of the width I have available on the screen I still can see only strings like this "
    did:hedera:testn….5922842".

  6. If I enter the details from the pages above, I cannot see the details of the issuer.

  7. In the "verify document" page, it's not clear if I need to use a VC ID or the "MongoDB document ID" to verify things.

  8. I tried the "Verify Document" feature with what I assumed was a valid VC ID (ee67dd49-e60c-4388-b49f-39336a576b6c), but I got a blank page with an application error message: "Application error: a client-side exception has occurred while loading localhost (see the browser console for more information).". Below the error when run in dev mode:

## Error Type
Runtime TypeError

## Error Message
Cannot read properties of undefined (reading 'options')
    at DocumentDetailPage (app/documents/[messageId]/page.tsx:22:32)

## Code Frame
  20 |   const { data: vcDetail, isLoading, error } = useVcDocument(vcId)
  21 |
> 22 |   const entityType = vcDetail?.item.options?.entityType as EntityType | undefined
     |                                ^
  23 |   const config = entityType ? ENTITY_TYPE_CONFIG[entityType] : null
  24 |
  25 |   return (

Next.js version: 16.1.6 (Turbopack)
  1. in the "Verify Document" page, if I use the transaction ID (i.e. 1767600748.312578844) I get some results, although the interface states I need to use a VC ID or a MongoDB document ID in the format of something like "64a1f8c9e4b0f5d2c1234567". So, it's not clear to me what is the correct format of the ID I need to use in this page, and it seems that the transaction ID works, but it's not clear if that's the intended behavior or if it's a bug that it works.

  2. in the bottom left part, the Guardian icon should be the one used for external links.

  3. in the bottom left part, the "Hedera Methodology" icon bring me to the MGS indexer page https://indexer.guardianservice.app/policies/1767599197.624837133. I suggest to link the policy in the methodology library instead.

  4. in the bottom left part, please remove the "contact" icon.

  5. in the top left, unless there are specific reasons to use that specific logo, replace the logo before the MECD Indexer with the Hedera logo.

  6. a nice to have feature would be to have a button in the top-right part, near the light/dark theme, to switch between US and non-US number format (i.e. emissions reduction: 1,667.83 vs 1.667,83).

  7. In the "Trust chain" page, please use human readable format for the date/time, and if possible try to make evident the events are ordered from the newest to the oldest. It felt more natural to me considering the first item "Verified monitoring report" as the first event, while it's actually the last. Having a human readable time format would alleviate that also.

Screenshot 2026-03-13 at 01 40 38
  1. In the "Trust chain" page, the issuance step "Verified monitoring report" is missing a reference to the actual minted tokens. That can be a link on Hashscan to the token page, or to the mint operation if available (probably not easy to recover the exact transaction ID, but in case a link to the token page is good enough)
Screenshot 2026-03-13 at 01 47 55

@Neurone
Copy link
Contributor

Neurone commented Mar 13, 2026

Hi @gautamp8 , I noticed another issue.

Currently there's no mechanism to refresh the indexer token, that is fixed in the .env file. That means that, after the token expires (14 days in case of MGS indexer for example), you start receiving error messages in the UI until you change that token and restart the server.

Instead of the point 5 above, probably we need to restructure the auth process so that users can setup user and password in the env file, and the token generation and refresh will be managed autonomously by the explorer.

  1. add a script to generate the indexer bearer token starting from the username and password. At the moment I'm using a token derived by the browser development console after logging in to the indexer web interface, but it would be nice to have a script to generate it automatically.
Screenshot 2026-03-13 at 14 08 16

Carbon Atlas is a Next.js dashboard that translates Guardian's on-chain
Verifiable Credentials into business-friendly views for carbon market
stakeholders.

Currently supports the Gold Standard MECD 431 policy (testnet) with:
- Per-policy dashboards with emission reduction stats, charts, and tables
- Trust chain explorer tracing issuances through the full VC relationship graph
- Dedicated VC-type renderers for monitoring reports, verification reports,
  projects, device MRV data, and VVB registrations
- Searchable device data table (3,254 metered cooking devices)
- Server-side auth proxy (API tokens never exposed to client)
- Hedera proof links to HashScan for every document
- Document verification by consensus timestamp

Tech stack: Next.js 16 (App Router), React 19, TanStack Query, shadcn/ui,
Tailwind CSS 4, Vitest

Multi-policy support (VM0033/Verra mainnet) planned as next phase.

Signed-off-by: Gautam Prajapati <gautamprajapati06@gmail.com>
@gautamp8 gautamp8 changed the base branch from main to develop March 16, 2026 14:50
…opy UX, auth restructure

- Trust chain follows standard carbon credit lifecycle (PDD → Calculated Project → Validation → Validated Project → dMRV → MR → Verification → MR Approved)
- VVB registration/approval excluded from chain; shown as inline assignment chips
- Ghost "Token Minting" pending node; removed broken minted token link
- Projects page deduplicates PDD + Validated Project into one row per project
- ATEC badge removed from projects list (policy-level page, multiple developers possible)
- ATEC logo increased to h-20 for visibility (source images are 2000x2000 squares)
- CopyableId component with visible copy icon replaces hover-to-copy
- Auth restructured: 3-step MGS SSO chain with auto-refresh, static token fallback
- All 28 review checklist items addressed; 38 tests passing

Signed-off-by: Gautam Prajapati <gautamprajapati06@gmail.com>
… emission reductions

- Sidebar title: MECD Indexer → Carbon Atlas
- Page title: MECD Indexer → Carbon Atlas
- Hedera Policy URL updated to guardian.hedera.com
- Emission reductions card/chart renamed to "Projected Emission Reductions"
- Footer text clarifies partial issuances to date

Signed-off-by: Gautam Prajapati <gautamprajapati06@gmail.com>
@gautamp8
Copy link
Contributor Author

gautamp8 commented Mar 16, 2026

@Neurone I've addressed all of the comments. Described below.

Everything is live at - https://atlas.carbonmarketshq.com to review

Review Checklist (28 items)

Configuration & Build

# Requirement File(s) Status
1 Turbopack root set to current directory (not monorepo root) next.config.ts DONE
2 postinstall script runs next telemetry disable package.json DONE
3 dev script binds to --hostname localhost (not 0.0.0.0) package.json DONE
4 .env.example contains NEXT_TELEMETRY_DISABLED=1 and NEXT_PUBLIC_TOKEN_ID .env.example DONE

Documentation

# Requirement File(s) Status
5 README documents authentication setup (auto-auth + static token fallback) README.md DONE
10 "Third-Party Logos & Trademarks" section covering Hedera, ATEC, Gold Standard README.md DONE

Layout & Navigation

# Requirement File(s) Status
6 "use client" directive to prevent hydration mismatch dashboard-layout.tsx DONE
7 GitHub link points to https://github.com/hashgraph/guardian site-header.tsx DONE
22 Guardian link uses IconExternalLink icon app-sidebar.tsx DONE
23 Hedera Policy URL points to MECD methodology docs page app-sidebar.tsx DONE
24 No "Contact" navigation item app-sidebar.tsx DONE
25 Sidebar logo is static /hedera-logo.png, favicon uses it app-sidebar.tsx DONE

VC Views & Formatting

# Requirement File(s) Status
8 All 5 VC view components use formatRawVc() for Raw VC tab MonitoringReportView, ProjectView, GenericVCView, VerificationReportView, ValidationReportView DONE
11 DeviceDataView uses formatRawVc() for full formatted JSON DeviceDataView.tsx DONE
27 formatRawVc() exists with tests (valid JSON, invalid JSON, JSON array) lib/utils/format.ts, __tests__/format.test.ts DONE

List Pages (Issuances & Projects)

# Requirement File(s) Status
12 Pagination controls hidden when totalPages <= 1 issuances/page.tsx, projects/page.tsx DONE
13 Projects page has client-side pagination with PAGE_SIZE = 25 projects/page.tsx DONE
14 Action links use IconArrowRight (not IconExternalLink) issuances/page.tsx, projects/page.tsx DONE
15 Issuances column header says "Consensus Timestamp" issuances/page.tsx DONE
16 Status badges use normalized casing (title case, not raw uppercase) issuances/page.tsx, projects/page.tsx DONE
17 Full issuer DID shown with truncate, tooltip, click-to-copy issuances/page.tsx, projects/page.tsx DONE

Detail Pages

# Requirement File(s) Status
18 All three detail pages show issuer DID with click-to-copy issuances/[messageId], projects/[messageId], documents/[messageId] DONE
20 Null guards on entityType, consensusTimestamp, and before VCRenderer documents/[messageId]/page.tsx DONE

Verify Page

# Requirement File(s) Status
19 Description says "Look up any VC document by its Hedera consensus timestamp" verify/page.tsx DONE
21 Placeholder shows consensus timestamp example (1767600748.312578844) verify/page.tsx DONE

Branding

# Requirement File(s) Status
9 ATEC logo sized appropriately (updated to h-20 for visibility — see follow-up below) ProjectDeveloperBadge.tsx DONE

Trust Chain

# Requirement File(s) Status
26 Human-readable dates, numbered step circles, "Newest first" label, token link handling ChainStep.tsx, TrustChainView.tsx DONE

Auth Restructure

# Requirement File(s) Status
28 3-step MGS SSO chain, proxy uses getIndexerToken() with 401 retry, backwards-compat with static INDEXER_API_TOKEN lib/api/auth.ts, app/api/proxy/[...path]/route.ts DONE

Some more changes

Trust Chain Redesign

Changes:

  • Redesigned buildChain() to use forward + reverse-link augmentation, discovering all related VCs then filtering to lifecycle-relevant types only
  • Added VVB assignment annotations as inline chips between steps ("VVB Assigned for Validation" between Calculated Project and Validation Report, "VVB Assigned for Verification" between Monitoring Report and Verification Report)
  • Added ghost "Token Minting" node at top with dashed/pending styling — minting hasn't happened yet
  • Renamed labels: "Verified Monitoring Report" → "Monitoring Report (Approved)", "Monitoring Report (Auto)" → "Monitoring Report", "VVB Verification Report" → "Verification Report", "Device MRV Data" → "Device dMRV Data"
  • Chain now shows 9 steps: Token Minting (pending) → MR Approved → Verification Report → Monitoring Report → Device dMRV Data → Validated Project → Validation Report → Calculated Project → PDD

Files: lib/utils/trust-chain.ts, components/trust-chain/TrustChainView.tsx, components/trust-chain/ChainStep.tsx

Copy UX with Visible Icon

Changes:

  • Reusable CopyableId component with truncated text + visible clipboard icon (shows checkmark on success)

Files: components/shared/CopyableId.tsx, app/issuances/page.tsx, app/projects/page.tsx, app/issuances/[messageId]/page.tsx, app/projects/[messageId]/page.tsx, app/documents/[messageId]/page.tsx

Issuances Page Wording

Problem: Description said "Verified monitoring reports" which was misleading.

Changes:

  • Updated to "Approved monitoring reports — each represents a carbon credit issuance"

Files: app/issuances/page.tsx

Document Not Found UI

Problem: Generic "Failed to load VC detail." text when a chain step's VC couldn't be loaded.

Changes:

  • Styled card with "Document not found" heading, explanation text, and consensus timestamp

Files: components/trust-chain/ChainStep.tsx

Tests

  • Updated trust chain tests for lifecycle-based chain (8 lifecycle nodes, VVB excluded)
  • Added deduplicateProjects() tests (merging, developer DID extraction, uncovered forms)
  • 38 tests passing, clean production build

Files: __tests__/trust-chain.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Carbon Atlas: A business-friendly multi-policy indexer frontend

2 participants