NVTS™ Enterprise Certification Platform — Production Architecture & Implementation Blueprint

Organization: Kenya Coffee School Framework: Natural Value Traceability System (NVTS™) Founder: Alfred Gitau Mwaura Design System Standards: Modern, Enterprise-Grade, ISO/IEC 17065-Inspired, Material-Influenced, Fully Accessible (WCAG 2.1 AA)

1. Executive System Architecture

The Natural Value Traceability System (NVTS™) is engineered as a zero-trust, multi-tenant digital traceability, sustainability scoring, and certification platform. Designed primarily for agricultural value chains—starting with high-grade specialty coffee—it supports strict chain-of-custody tracking, multi-pillar audit workflows, and immutable product passport verifications.

+--------------------------------------------------------------------------------------------------+
|                                    CLIENT / UI LAYER (Vite + React 18)                           |
|  +---------------------+   +--------------------+   +-----------------------+   +-----------------+  |
|  |   Applicant Portal  |   |   Auditor Portal   |   | Council / Admin Panel |   | Public Passport |  |
|  +---------------------+   +--------------------+   +-----------------------+   +-----------------+  |
|            |                         |                          |                        |       |
|  +--------------------------------------------------------------------------------------------+  |
|  |                     React Router v6 + TanStack Query v5 + React Hook Form + Zod             |  |
|  +--------------------------------------------------------------------------------------------+  |
|                                              |                                                   |
|                                    REST / Realtime Engine                                        |
+----------------------------------------------|---------------------------------------------------+
                                               |
+----------------------------------------------v---------------------------------------------------+
|                                  SUPABASE BACKEND SERVICES                                       |
|  +-----------------------+     +-----------------------+     +--------------------------------+  |
|  |  Supabase Auth (JWT)  |     | PostgreSQL + PostGIS  |     |  Storage Buckets (Audit Docs)  |  |
|  +-----------------------+     +-----------------------+     +--------------------------------+  |
|              |                             |                                 |                   |
|              +--------------+--------------+---------------------------------+                   |
|                             |                                                                    |
|             +-------------------------------+                                                    |
|             |  Row-Level Security (RLS)     |                                                    |
|             |  Database Triggers & Webhooks |                                                    |
|             |  Edge Functions (Audit Calc)  |                                                    |
|             +-------------------------------+                                                    |
+--------------------------------------------------------------------------------------------------+

2. PostgreSQL Relational Schema & RLS Policies

Execute the following SQL script directly within the Supabase SQL Editor to establish the database structure, triggers, security policies, and standard seed data.

-- Enable necessary extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "postgis";

-- -----------------------------------------------------------------------------
-- ENUMS
-- -----------------------------------------------------------------------------
CREATE TYPE user_role AS ENUM (
  'super_admin',
  'certification_manager',
  'lead_auditor',
  'auditor',
  'technical_reviewer',
  'certification_council',
  'applicant',
  'producer',
  'public_user'
);

CREATE TYPE cert_level AS ENUM (
  'Diamond',
  'Platinum',
  'Gold',
  'Silver',
  'Bronze',
  'Improvement Required'
);

CREATE TYPE app_status AS ENUM (
  'Draft',
  'Submitted',
  'Under_Review',
  'Audit_Scheduled',
  'Audit_In_Progress',
  'Council_Review',
  'Approved',
  'Rejected',
  'Suspended'
);

CREATE TYPE pillar_category AS ENUM ('Nature', 'People', 'Culture', 'Quality', 'Trade');

-- -----------------------------------------------------------------------------
-- 1. USERS & PROFILES
-- -----------------------------------------------------------------------------
CREATE TABLE profiles (
  id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  email TEXT NOT NULL UNIQUE,
  full_name TEXT NOT NULL,
  phone TEXT,
  role user_role NOT NULL DEFAULT 'applicant',
  organization_id UUID,
  avatar_url TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- -----------------------------------------------------------------------------
-- 2. ORGANIZATIONS
-- -----------------------------------------------------------------------------
CREATE TABLE organizations (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  name TEXT NOT NULL,
  registration_number TEXT UNIQUE,
  tax_id TEXT,
  country TEXT NOT NULL DEFAULT 'Kenya',
  county_region TEXT NOT NULL,
  address TEXT,
  primary_contact_name TEXT NOT NULL,
  primary_contact_email TEXT NOT NULL,
  primary_contact_phone TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

ALTER TABLE profiles 
  ADD CONSTRAINT fk_profiles_organization 
  FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE SET NULL;

-- -----------------------------------------------------------------------------
-- 3. FARMS & LAND PARCELS
-- -----------------------------------------------------------------------------
CREATE TABLE farms (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
  name TEXT NOT NULL,
  location_name TEXT NOT NULL,
  gps_latitude NUMERIC(10,8) NOT NULL,
  gps_longitude NUMERIC(11,8) NOT NULL,
  total_area_hectares NUMERIC(8,2) NOT NULL,
  altitude_masl INT NOT NULL, -- Meters Above Sea Level
  soil_type TEXT,
  water_source TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- -----------------------------------------------------------------------------
-- 4. APPLICATIONS
-- -----------------------------------------------------------------------------
CREATE TABLE applications (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  application_number TEXT UNIQUE NOT NULL,
  organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
  farm_id UUID NOT NULL REFERENCES farms(id) ON DELETE CASCADE,
  status app_status NOT NULL DEFAULT 'Draft',
  target_scope TEXT NOT NULL DEFAULT 'Coffee Production & Processing',
  submitted_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- -----------------------------------------------------------------------------
-- 5. AUDITS & SCORING
-- -----------------------------------------------------------------------------
CREATE TABLE audits (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  application_id UUID NOT NULL REFERENCES applications(id) ON DELETE CASCADE,
  lead_auditor_id UUID REFERENCES profiles(id),
  scheduled_date DATE NOT NULL,
  completion_date DATE,
  score_nature NUMERIC(5,2) DEFAULT 0.00,
  score_people NUMERIC(5,2) DEFAULT 0.00,
  score_culture NUMERIC(5,2) DEFAULT 0.00,
  score_quality NUMERIC(5,2) DEFAULT 0.00,
  score_trade NUMERIC(5,2) DEFAULT 0.00,
  overall_score NUMERIC(5,2) DEFAULT 0.00,
  recommended_level cert_level,
  auditor_notes TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE audit_items (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  audit_id UUID NOT NULL REFERENCES audits(id) ON DELETE CASCADE,
  pillar pillar_category NOT NULL,
  indicator_code TEXT NOT NULL,
  indicator_title TEXT NOT NULL,
  max_score INT DEFAULT 5,
  score_given INT CHECK (score_given >= 0 AND score_given <= 5),
  evidence_summary TEXT,
  non_conformity_level TEXT CHECK (non_conformity_level IN ('None', 'Minor', 'Major', 'Critical')),
  corrective_action_required TEXT,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- -----------------------------------------------------------------------------
-- 6. CERTIFICATES
-- -----------------------------------------------------------------------------
CREATE TABLE certificates (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  certificate_number TEXT UNIQUE NOT NULL,
  application_id UUID NOT NULL REFERENCES applications(id),
  audit_id UUID NOT NULL REFERENCES audits(id),
  organization_id UUID NOT NULL REFERENCES organizations(id),
  certification_level cert_level NOT NULL,
  overall_score NUMERIC(5,2) NOT NULL,
  issue_date DATE NOT NULL,
  expiry_date DATE NOT NULL,
  is_active BOOLEAN DEFAULT TRUE,
  digital_signature_hash TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- -----------------------------------------------------------------------------
-- 7. PRODUCTS & LOT PASS PORTS
-- -----------------------------------------------------------------------------
CREATE TABLE product_passports (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  lot_number TEXT UNIQUE NOT NULL,
  certificate_id UUID NOT NULL REFERENCES certificates(id),
  farm_id UUID NOT NULL REFERENCES farms(id),
  crop_type TEXT NOT NULL DEFAULT 'Coffee',
  variety TEXT NOT NULL, -- e.g., SL28, SL34, Ruiru 11, Batian
  harvest_year INT NOT NULL,
  processing_method TEXT NOT NULL, -- Wash, Natural, Honey, Anaerobic
  quality_grade TEXT NOT NULL, -- AA, AB, PB, C
  cup_score NUMERIC(4,2), -- Specialty Coffee SCA Score
  moisture_content_pct NUMERIC(4,2),
  water_activity NUMERIC(4,3),
  density_g_l INT,
  initial_brix NUMERIC(4,1),
  dry_ferment_hours NUMERIC(4,1),
  soak_duration_hours NUMERIC(4,1),
  soak_water_temp_c NUMERIC(4,1),
  terminal_ph NUMERIC(3,2),
  qr_code_url TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- -----------------------------------------------------------------------------
-- 8. CHAIN OF CUSTODY (EVENT LOG)
-- -----------------------------------------------------------------------------
CREATE TABLE chain_of_custody_events (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  product_passport_id UUID NOT NULL REFERENCES product_passports(id) ON DELETE CASCADE,
  stage TEXT NOT NULL, -- Seed, Nursery, Farm, Harvest, Processing, Warehouse, Export, Roaster, Retail, Consumer
  actor_name TEXT NOT NULL,
  facility_location TEXT NOT NULL,
  timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  verification_hash TEXT NOT NULL,
  notes TEXT
);

-- -----------------------------------------------------------------------------
-- ROW-LEVEL SECURITY POLICIES (RLS)
-- -----------------------------------------------------------------------------
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
ALTER TABLE applications ENABLE ROW LEVEL SECURITY;
ALTER TABLE audits ENABLE ROW LEVEL SECURITY;
ALTER TABLE certificates ENABLE ROW LEVEL SECURITY;
ALTER TABLE product_passports ENABLE ROW LEVEL SECURITY;
ALTER TABLE chain_of_custody_events ENABLE ROW LEVEL SECURITY;

-- Profiles: Users can read their own profile; Admins read all.
CREATE POLICY "Users read own profile" ON profiles
  FOR SELECT USING (auth.uid() = id);

CREATE POLICY "Admins manage all profiles" ON profiles
  FOR ALL USING (
    EXISTS (SELECT 1 FROM profiles WHERE id = auth.uid() AND role IN ('super_admin', 'certification_manager'))
  );

-- Public Read Policies for Certificates & Passports
CREATE POLICY "Public certificate verification" ON certificates
  FOR SELECT USING (is_active = true);

CREATE POLICY "Public product passport view" ON product_passports
  FOR SELECT USING (true);

CREATE POLICY "Public chain of custody view" ON chain_of_custody_events
  FOR SELECT USING (true);

-- Applications: Applicants access their organization's data
CREATE POLICY "Applicants access own org applications" ON applications
  FOR ALL USING (
    organization_id IN (SELECT organization_id FROM profiles WHERE id = auth.uid())
    OR
    EXISTS (SELECT 1 FROM profiles WHERE id = auth.uid() AND role IN ('super_admin', 'certification_manager', 'lead_auditor', 'auditor', 'certification_council'))
  );

-- -----------------------------------------------------------------------------
-- AUTOMATIC SCORING & CERTIFICATION LEVEL TRIGGER
-- -----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION calculate_audit_scores()
RETURNS TRIGGER AS $$
DECLARE
  v_nat NUMERIC;
  v_peo NUMERIC;
  v_cul NUMERIC;
  v_qua NUMERIC;
  v_tra NUMERIC;
  v_tot NUMERIC;
  v_lvl cert_level;
BEGIN
  -- Compute averages per pillar normalized to percentage (0-100)
  SELECT 
    COALESCE(AVG(CASE WHEN pillar = 'Nature' THEN (score_given::numeric / max_score) * 100 END), 0),
    COALESCE(AVG(CASE WHEN pillar = 'People' THEN (score_given::numeric / max_score) * 100 END), 0),
    COALESCE(AVG(CASE WHEN pillar = 'Culture' THEN (score_given::numeric / max_score) * 100 END), 0),
    COALESCE(AVG(CASE WHEN pillar = 'Quality' THEN (score_given::numeric / max_score) * 100 END), 0),
    COALESCE(AVG(CASE WHEN pillar = 'Trade' THEN (score_given::numeric / max_score) * 100 END), 0)
  INTO v_nat, v_peo, v_cul, v_qua, v_tra
  FROM audit_items
  WHERE audit_id = NEW.audit_id;

  -- Weighted Total (Equal weighting across 5 pillars: 20% each)
  v_tot := (v_nat + v_peo + v_cul + v_qua + v_tra) / 5.0;

  -- Assign Tier Level based on standard benchmarks
  IF v_tot >= 95.0 THEN v_lvl := 'Diamond';
  ELSIF v_tot >= 90.0 THEN v_lvl := 'Platinum';
  ELSIF v_tot >= 85.0 THEN v_lvl := 'Gold';
  ELSIF v_tot >= 80.0 THEN v_lvl := 'Silver';
  ELSIF v_tot >= 70.0 THEN v_lvl := 'Bronze';
  ELSE v_lvl := 'Improvement Required';
  END IF;

  UPDATE audits
  SET 
    score_nature = ROUND(v_nat, 2),
    score_people = ROUND(v_peo, 2),
    score_culture = ROUND(v_cul, 2),
    score_quality = ROUND(v_qua, 2),
    score_trade = ROUND(v_tra, 2),
    overall_score = ROUND(v_tot, 2),
    recommended_level = v_lvl
  WHERE id = NEW.audit_id;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER trg_recalculate_audit_score
AFTER INSERT OR UPDATE ON audit_items
FOR EACH ROW EXECUTE FUNCTION calculate_audit_scores();

3. Five-Pillar Audit Engine Logic & Mathematical Model

The NVTS™ Standard evaluates producers across five core pillars. Every indicator within a pillar is scored from 0 to 5 based on objective verifiers.

Mathematical Formulation

  1. Indicator Score Normalization: \text{Score}_{i,p} = \frac{S_{i,p}}{S_{i,p}^{\max}} \times 100 Where S_{i,p} is the raw score given for indicator i in pillar p, and S_{i,p}^{\max} = 5.
  2. Pillar Score (\text{Pillar}_p): \text{Pillar}_p = \frac{1}{N_p} \sum_{i=1}^{N_p} \left( \frac{S_{i,p}}{5} \times 100 \right) Where N_p is the total number of evaluated indicators in pillar p.
  3. Composite NVTS™ Score (\text{Score}_{\text{NVTS}}): \text{Score}_{\text{NVTS}} = \sum_{p \in \{\text{Nature, People, Culture, Quality, Trade}\}} \left( w_p \times \text{Pillar}_p \right) With standard equal weighting w_p = 0.20 for each pillar.

Certification Tier Benchmarks

NVTS™ Score ThresholdTier LevelDesignatorAction Required / Status
95.00% – 100.00%Diamond★★★★★Full Certification (3-Year Validity, Annual Surveillance)
90.00% – 94.99%Platinum★★★★☆Full Certification (3-Year Validity, Annual Surveillance)
85.00% – 89.99%Gold★★★★Standard Certification (2-Year Validity)
80.00% – 84.99%Silver★★★Conditional Certification (1-Year Minor CAP Execution)
70.00% – 79.99%Bronze★★Provisional Certification (Mandatory Re-audit in 6 Months)
< 70.00%Improvement RequiredCertification Denied (Root-Cause Remediation Plan)

4. Frontend Implementation Architecture

TypeScript Types & Interfaces (src/types/nvts.ts)

export type UserRole = 
  | 'super_admin'
  | 'certification_manager'
  | 'lead_auditor'
  | 'auditor'
  | 'technical_reviewer'
  | 'certification_council'
  | 'applicant'
  | 'producer'
  | 'public_user';

export type CertificationLevel = 
  | 'Diamond'
  | 'Platinum'
  | 'Gold'
  | 'Silver'
  | 'Bronze'
  | 'Improvement Required';

export type PillarCategory = 'Nature' | 'People' | 'Culture' | 'Quality' | 'Trade';

export interface AuditIndicator {
  id: string;
  pillar: PillarCategory;
  indicatorCode: string;
  indicatorTitle: string;
  maxScore: number;
  scoreGiven: number;
  evidenceSummary: string;
  nonConformityLevel: 'None' | 'Minor' | 'Major' | 'Critical';
  correctiveActionRequired?: string;
}

export interface ProductPassport {
  lotNumber: string;
  organizationName: string;
  farmName: string;
  altitudeMasl: number;
  gpsCoordinates: { lat: number; lng: number };
  cropVariety: string;
  harvestYear: number;
  processingMethod: string;
  qualityGrade: string;
  cupScore: number;
  physicochemical: {
    initialBrix: number;
    dryFermentHours: number;
    terminalPh: number;
    soakDurationHours: number;
    soakWaterTempC: number;
    moistureContentPct: number;
    waterActivity: number;
    densityGL: number;
  };
  nvtsScore: number;
  certLevel: CertificationLevel;
  certificateNumber: string;
}

Key UI Component 1: Audit Engine Component (src/components/AuditEngine.tsx)

Below is the dynamic five-pillar audit scorecard with automated real-time calculation and validation.

import React, { useState } from 'react';
import { PillarCategory, AuditIndicator, CertificationLevel } from '../types/nvts';

const INITIAL_INDICATORS: AuditIndicator[] = [
  // Nature
  { id: '1', pillar: 'Nature', indicatorCode: 'NAT-01', indicatorTitle: 'Shade Tree Canopy Cover (>= 40%) & Biodiversity Protection', maxScore: 5, scoreGiven: 4, evidenceSummary: 'Native trees present, canopy density measured at 42%.', nonConformityLevel: 'None' },
  { id: '2', pillar: 'Nature', indicatorCode: 'NAT-02', indicatorTitle: 'Water Resource Management & Pulping Effluent Treatment', maxScore: 5, scoreGiven: 5, evidenceSummary: 'Recirculating eco-pulper used; eco-wetland filtration active.', nonConformityLevel: 'None' },
  // People
  { id: '3', pillar: 'People', indicatorCode: 'PEO-01', indicatorTitle: 'Fair Living Wage & Occupational Health and Safety Protocols', maxScore: 5, scoreGiven: 4, evidenceSummary: 'Workers paid 18% above minimum wage. PPE provided.', nonConformityLevel: 'None' },
  // Culture
  { id: '4', pillar: 'Culture', indicatorCode: 'CUL-01', indicatorTitle: 'Heritage Variety Conservation & Traditional Husbandry Knowledge', maxScore: 5, scoreGiven: 5, evidenceSummary: 'Preservation of legacy SL28/SL34 plots with organic composting.', nonConformityLevel: 'None' },
  // Quality
  { id: '5', pillar: 'Quality', indicatorCode: 'QUA-01', indicatorTitle: 'Fermentation Parameter Control (BRIX, Temp, pH)', maxScore: 5, scoreGiven: 4, evidenceSummary: 'Logbook verified: Dry ferment 16h, soak 33h at 17.5°C, pH 4.4.', nonConformityLevel: 'None' },
  // Trade
  { id: '6', pillar: 'Trade', indicatorCode: 'TRA-01', indicatorTitle: 'Traceable Payment Distribution & Transparent Cost-Breakdown', maxScore: 5, scoreGiven: 5, evidenceSummary: 'Direct mobile payment ledger verified against lot deliveries.', nonConformityLevel: 'None' }
];

export const AuditEngine: React.FC = () => {
  const [indicators, setIndicators] = useState<AuditIndicator[]>(INITIAL_INDICATORS);

  const updateScore = (id: string, score: number) => {
    setIndicators(prev => prev.map(ind => ind.id === id ? { ...ind, scoreGiven: score } : ind));
  };

  const calculatePillarScore = (pillar: PillarCategory): number => {
    const items = indicators.filter(i => i.pillar === pillar);
    if (items.length === 0) return 0;
    const sum = items.reduce((acc, i) => acc + (i.scoreGiven / i.maxScore) * 100, 0);
    return sum / items.length;
  };

  const scoreNature = calculatePillarScore('Nature');
  const scorePeople = calculatePillarScore('People');
  const scoreCulture = calculatePillarScore('Culture');
  const scoreQuality = calculatePillarScore('Quality');
  const scoreTrade = calculatePillarScore('Trade');

  const overallScore = (scoreNature + scorePeople + scoreCulture + scoreQuality + scoreTrade) / 5;

  const getTier = (score: number): { level: CertificationLevel; badgeStyle: string } => {
    if (score >= 95) return { level: 'Diamond', badgeStyle: 'bg-blue-100 text-blue-800 border-blue-400' };
    if (score >= 90) return { level: 'Platinum', badgeStyle: 'bg-purple-100 text-purple-800 border-purple-400' };
    if (score >= 85) return { level: 'Gold', badgeStyle: 'bg-yellow-100 text-yellow-800 border-yellow-500' };
    if (score >= 80) return { level: 'Silver', badgeStyle: 'bg-slate-200 text-slate-800 border-slate-400' };
    if (score >= 70) return { level: 'Bronze', badgeStyle: 'bg-amber-100 text-amber-800 border-amber-600' };
    return { level: 'Improvement Required', badgeStyle: 'bg-red-100 text-red-800 border-red-400' };
  };

  const currentTier = getTier(overallScore);

  return (
    <div className="max-w-6xl mx-auto p-6 bg-white shadow-xl rounded-2xl border border-gray-100">
      <div className="flex flex-col md:flex-row justify-between items-start md:items-center pb-6 border-b border-gray-200 gap-4">
        <div>
          <h2 className="text-2xl font-bold text-[#0B6B3A]">NVTS™ Digital Scorecard Engine</h2>
          <p className="text-sm text-gray-500">ISO/IEC 17065 Compliant Sustainability Assessment</p>
        </div>
        <div className="flex items-center gap-4 bg-gray-50 p-4 rounded-xl border border-gray-200">
          <div>
            <div className="text-xs text-gray-500 font-semibold uppercase">Composite Score</div>
            <div className="text-3xl font-extrabold text-[#333333]">{overallScore.toFixed(2)}%</div>
          </div>
          <div className={`px-4 py-2 rounded-lg border font-bold text-sm ${currentTier.badgeStyle}`}>
            {currentTier.level}
          </div>
        </div>
      </div>

      {/* Pillar Breakdown Grid */}
      <div className="grid grid-cols-2 md:grid-cols-5 gap-3 my-6">
        {[
          { name: 'Nature', score: scoreNature, color: 'bg-emerald-500' },
          { name: 'People', score: scorePeople, color: 'bg-blue-500' },
          { name: 'Culture', score: scoreCulture, color: 'bg-amber-500' },
          { name: 'Quality', score: scoreQuality, color: 'bg-[#6F4E37]' },
          { name: 'Trade', score: scoreTrade, color: 'bg-[#C9A227]' }
        ].map(p => (
          <div key={p.name} className="p-3 bg-gray-50 rounded-lg border border-gray-200">
            <span className="text-xs font-semibold text-gray-600 uppercase">{p.name}</span>
            <div className="text-xl font-bold text-gray-900 mt-1">{p.score.toFixed(1)}%</div>
            <div className="w-full bg-gray-200 h-1.5 rounded-full mt-2 overflow-hidden">
              <div className={`${p.color} h-1.5`} style={{ width: `${p.score}%` }}></div>
            </div>
          </div>
        ))}
      </div>

      {/* Indicator Assessment Table */}
      <div className="overflow-x-auto mt-6">
        <table className="w-full text-left border-collapse">
          <thead>
            <tr className="bg-[#0B6B3A] text-white text-xs uppercase tracking-wider">
              <th className="p-3 rounded-tl-lg">Code</th>
              <th className="p-3">Pillar</th>
              <th className="p-3">Indicator Title</th>
              <th className="p-3 text-center">Score (0-5)</th>
              <th className="p-3 rounded-tr-lg">Evidence / Auditor Summary</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-gray-200 text-sm">
            {indicators.map(item => (
              <tr key={item.id} className="hover:bg-gray-50">
                <td className="p-3 font-mono font-bold text-gray-700">{item.indicatorCode}</td>
                <td className="p-3">
                  <span className="px-2 py-1 text-xs rounded bg-gray-100 font-medium text-gray-700">
                    {item.pillar}
                  </span>
                </td>
                <td className="p-3 font-medium text-gray-900">{item.indicatorTitle}</td>
                <td className="p-3 text-center">
                  <select
                    value={item.scoreGiven}
                    onChange={(e) => updateScore(item.id, parseInt(e.target.value))}
                    className="p-1 border rounded bg-white font-bold text-[#0B6B3A] focus:ring-2 focus:ring-[#0B6B3A]"
                  >
                    {[0, 1, 2, 3, 4, 5].map(val => (
                      <option key={val} value={val}>{val}</option>
                    ))}
                  </select>
                </td>
                <td className="p-3 text-gray-600">{item.evidenceSummary}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

Key UI Component 2: Digital Product Passport & Chain of Custody (src/components/ProductPassportView.tsx)

This component displays the complete batch details, physical processing metrics, and chain of custody tracking.

import React from 'react';
import { ProductPassport } from '../types/nvts';

const SAMPLE_PASSPORT: ProductPassport = {
  lotNumber: 'NVTS-KE-2026-AA084',
  organizationName: 'Nyeri Farmers Co-operative Union',
  farmName: 'Kamunyaka Estate - Parcel B',
  altitudeMasl: 1820,
  gpsCoordinates: { lat: -0.4167, lng: 36.9500 },
  cropVariety: 'SL28 & Batian Blend',
  harvestYear: 2026,
  processingMethod: 'Double Fermented Washed',
  qualityGrade: 'AA (Screen 17/18)',
  cupScore: 89.25,
  physicochemical: {
    initialBrix: 21.5,
    dryFermentHours: 16.5,
    terminalPh: 4.38,
    soakDurationHours: 33.0,
    soakWaterTempC: 17.5,
    moistureContentPct: 11.3,
    waterActivity: 0.54,
    densityGL: 835
  },
  nvtsScore: 94.20,
  certLevel: 'Platinum',
  certificateNumber: 'CERT-NVTS-2026-8812'
};

const CHAIN_TIMELINE = [
  { stage: 'Seed & Nursery', date: '2021-04-12', actor: 'KCS Certified Seedbank', detail: 'SL28 Certified Seedling Planting' },
  { stage: 'Harvesting', date: '2025-12-10', actor: 'Kamunyaka Pickers Guild', detail: '100% Red Ripe Cherries (21.5° BRIX)' },
  { stage: 'Processing & Soak', date: '2025-12-12', actor: 'Kamunyaka Wet Mill', detail: 'Dry Ferment 16.5h -> 33h Cold Soak at 17.5°C' },
  { stage: 'Milling & Grading', date: '2026-01-20', actor: 'Central Kenya Dry Mill', detail: 'Graded Screen 17/18 (AA), Moisture 11.3%' },
  { stage: 'NVTS Audit & Verification', date: '2026-02-05', actor: 'Lead Auditor A. Gitau', detail: 'Platinum Rating Awarded (94.20%)' },
  { stage: 'Export Shipping', date: '2026-03-01', actor: 'Mombasa Logistics Hub', detail: 'Container Seal Verified - Hash #0x89f...a12' }
];

export const ProductPassportView: React.FC = () => {
  const p = SAMPLE_PASSPORT;

  return (
    <div className="max-w-5xl mx-auto p-8 bg-slate-50 min-h-screen">
      {/* Header Banner */}
      <div className="bg-[#0B6B3A] text-white p-6 rounded-t-2xl flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
        <div>
          <span className="text-xs uppercase tracking-widest text-[#C9A227] font-extrabold">NVTS™ Digital Product Passport</span>
          <h1 className="text-3xl font-black mt-1">Lot #{p.lotNumber}</h1>
          <p className="text-sm opacity-90">{p.organizationName} | {p.farmName}</p>
        </div>
        <div className="bg-white text-gray-900 px-6 py-3 rounded-xl border-2 border-[#C9A227] text-center">
          <div className="text-xs font-bold text-gray-500 uppercase">NVTS Tier</div>
          <div className="text-2xl font-black text-[#6F4E37]">{p.certLevel}</div>
          <div className="text-xs font-semibold text-emerald-700">{p.nvtsScore}% Score</div>
        </div>
      </div>

      {/* Main Grid */}
      <div className="bg-white p-6 rounded-b-2xl shadow-lg border border-gray-200 grid grid-cols-1 md:grid-cols-3 gap-6">
        
        {/* Physical & Origin Attributes */}
        <div className="space-y-4 border-r border-gray-100 pr-4">
          <h3 className="text-sm font-bold uppercase tracking-wider text-[#6F4E37] border-b pb-2">Origin & Terroir</h3>
          <ul className="text-sm space-y-2">
            <li><strong className="text-gray-600">Location:</strong> Nyeri, Kenya</li>
            <li><strong className="text-gray-600">GPS:</strong> {p.gpsCoordinates.lat}, {p.gpsCoordinates.lng}</li>
            <li><strong className="text-gray-600">Altitude:</strong> {p.altitudeMasl} MASL</li>
            <li><strong className="text-gray-600">Variety:</strong> {p.cropVariety}</li>
            <li><strong className="text-gray-600">Grade:</strong> {p.qualityGrade}</li>
            <li><strong className="text-gray-600">Cup Score:</strong> <span className="font-bold text-[#0B6B3A]">{p.cupScore} / 100 SCA</span></li>
          </ul>
        </div>

        {/* Harvest Processing Metrics */}
        <div className="space-y-4 border-r border-gray-100 pr-4">
          <h3 className="text-sm font-bold uppercase tracking-wider text-[#6F4E37] border-b pb-2">Physicochemical Profile</h3>
          <ul className="text-sm space-y-2 font-mono">
            <li><span className="text-gray-600">Initial BRIX:</span> <strong>{p.physicochemical.initialBrix}° Brix</strong></li>
            <li><span className="text-gray-600">Dry Ferment:</span> <strong>{p.physicochemical.dryFermentHours} Hours</strong></li>
            <li><span className="text-gray-600">Terminal pH:</span> <strong>{p.physicochemical.terminalPh}</strong></li>
            <li><span className="text-gray-600">Soak Duration:</span> <strong>{p.physicochemical.soakDurationHours} Hours</strong></li>
            <li><span className="text-gray-600">Soak Water Temp:</span> <strong>{p.physicochemical.soakWaterTempC}°C</strong></li>
            <li><span className="text-gray-600">Moisture Content:</span> <strong>{p.physicochemical.moistureContentPct}%</strong></li>
            <li><span className="text-gray-600">Water Activity ($a_w$):</span> <strong>{p.physicochemical.waterActivity}</strong></li>
            <li><span className="text-gray-600">Density:</span> <strong>{p.physicochemical.densityGL} g/L</strong></li>
          </ul>
        </div>

        {/* Certificate Reference & Verification */}
        <div className="space-y-4 flex flex-col justify-between">
          <div>
            <h3 className="text-sm font-bold uppercase tracking-wider text-[#6F4E37] border-b pb-2">Verification</h3>
            <div className="mt-3 p-3 bg-gray-50 rounded-lg border border-gray-200">
              <p className="text-xs text-gray-500">Certificate Reference</p>
              <p className="text-sm font-bold font-mono text-[#0B6B3A]">{p.certificateNumber}</p>
              <div className="mt-2 text-xs text-emerald-700 font-semibold flex items-center gap-1">
                <span className="w-2 h-2 rounded-full bg-emerald-500 inline-block"></span> Verified Authentic
              </div>
            </div>
          </div>
          <button className="w-full py-3 bg-[#0B6B3A] text-white font-bold rounded-xl hover:bg-emerald-800 transition-colors shadow-md">
            Download Official Certificate (PDF)
          </button>
        </div>
      </div>

      {/* Chain of Custody Timeline */}
      <div className="mt-8 bg-white p-6 rounded-2xl shadow-lg border border-gray-200">
        <h3 className="text-lg font-bold text-[#333333] mb-6">Chain of Custody Ledger</h3>
        <div className="relative border-l-2 border-[#0B6B3A] ml-4 space-y-6">
          {CHAIN_TIMELINE.map((evt, idx) => (
            <div key={idx} className="relative pl-6">
              <span className="absolute -left-[9px] top-1 w-4 h-4 rounded-full bg-[#C9A227] border-2 border-white"></span>
              <div className="flex justify-between items-baseline">
                <h4 className="text-sm font-bold text-gray-900">{evt.stage}</h4>
                <time className="text-xs font-mono text-gray-500">{evt.date}</time>
              </div>
              <p className="text-xs font-semibold text-[#0B6B3A]">{evt.actor}</p>
              <p className="text-xs text-gray-600 mt-0.5">{evt.detail}</p>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

5. Security Architecture (RLS Policy Enforcement)

Data protection and multi-tenant access controls are enforced at the PostgreSQL level using Supabase Row-Level Security (RLS).

                       +-----------------------------------+
                       |    INCOMING REST / GRAPHQL REQUEST|
                       +-----------------------------------+
                                         |
                                         v
                       +-----------------------------------+
                       |    SUPABASE AUTH JWT VALIDATION   |
                       |  (Extracts user_id & role claim)  |
                       +-----------------------------------+
                                         |
                                         v
                       +-----------------------------------+
                       |       POSTGRES RLS EVALUATION     |
                       +-----------------------------------+
                                font-mono / SQL
                                         |
             +---------------------------+---------------------------+
             |                                                       |
             v                                                       v
  +--------------------+                                  +--------------------+
  | ROLE = 'applicant' |                                  | ROLE = 'auditor'   |
  | Filter:            |                                  | Filter:            |
  | org_id =           |                                  | assigned_auditor = |
  | auth.jwt().org_id  |                                  | auth.jwt().user_id |
  +--------------------+                                  +--------------------+

Security Directives

  1. Auditor Field Isolation: Auditors can read and update only audits and audit_items assigned to them via lead_auditor_id.
  2. Public Scope: Public users can query certificates and product_passports where is_active = true. Access to internal audit evidence and score breakdown logs is restricted.
  3. Immutability of Issued Certificates: Database triggers prevent updating certificates records once issued. Revocations or updates require explicit administrative escalation.

6. Interactive Process Flow & Verification Engine

Below is the procedural lifecycle from initial registration to public QR certificate verification.

+---------------------------------------------------------------------------------------------------+
| APPLICATION PHASE                                                                                 |
|  [Producer / Applicant] ---> Fills Organization, Farm, and Crop Details ---> Submits Application |
+---------------------------------------------------------------------------------------------------+
                                                  |
                                                  v
+---------------------------------------------------------------------------------------------------+
| AUDIT & ASSESSMENT PHASE                                                                          |
|  [Certification Manager] ---> Assigns Lead Auditor                                               |
|  [Lead Auditor]         ---> On-site Inspection & Digital Audit Scoring (Nature, People, Culture, |
|                              Quality, Trade)                                                      |
|  [Database Engine]      ---> Trigger Executes: Calculates Pillar Averages & Recommends Level      |
+---------------------------------------------------------------------------------------------------+
                                                  |
                                                  v
+---------------------------------------------------------------------------------------------------+
| COUNCIL REVIEW & ISSUANCE PHASE                                                                   |
|  [Technical Reviewer]   ---> Conducts Compliance Check & Verifies Evidence                        |
|  [Certification Council]---> Formally Approves Certification                                       |
|  [System Generator]     ---> Generates Certificate, SHA-256 Hash, & Product Passport QR Code      |
+---------------------------------------------------------------------------------------------------+
                                                  |
                                                  v
+---------------------------------------------------------------------------------------------------+
| TRACEABILITY & VERIFICATION PHASE                                                                 |
|  [Consumer / Buyer]     ---> Scans QR Code on Coffee Packaging                                   |
|  [Public Portal]        ---> Displays Lot Origin, SCA Cup Score, Physicochemical Log, & CoC Ledger  |
+---------------------------------------------------------------------------------------------------+

7. Verification & Deployment Roadmap

To move this system to production, follow these key setup steps:

                  +------------------------------------------------+
                  |  STEP 1: DATABASE DEPLOYMENT                   |
                  |  Run SQL Schema & Triggers on Supabase Postgres|
                  +------------------------------------------------+
                                          |
                                          v
                  +------------------------------------------------+
                  |  STEP 2: ENVIRONMENT CONFIGURATION             |
                  |  Configure .env with Supabase API Keys         |
                  +------------------------------------------------+
                                          |
                                          v
                  +------------------------------------------------+
                  |  STEP 3: INTEGRATION TESTING                   |
                  |  Execute Test Suite (Audit Engine & Scoring)   |
                  +------------------------------------------------+
                                          |
                                          v
                  +------------------------------------------------+
                  |  STEP 4: PRODUCTION DEPLOYMENT                 |
                  |  Deploy Frontend on Vercel / Netlify           |
                  +------------------------------------------------+