AI verifies industrial work. Blockchain proves it. Smart contracts settle it.
ProofOps turns industrial maintenance into a shared, verifiable workflow: a manager defines the outcome and protects payment, a technician submits private evidence, Gemini analyzes that evidence, a qualified supervisor decides, and Base Sepolia releases pUSDC while recording a tamper-evident equipment service proof.
The repository is deployment-ready without external credentials: public demo screens render from clearly labelled seed data, while authentication, evidence mutation, AI, and blockchain actions fail closed until configured. Demo mode never fabricates AI results or transaction receipts.
Factories still reconcile photos, PDFs, readings, invoices, chats, and spreadsheets manually. The result is slow approvals, payment disputes, mismatched evidence, and maintenance histories that do not travel between companies. ProofOps gives every party one lifecycle and assigns each technology a narrow job:
- Gemini: multimodal evidence comparison, extraction, contradiction detection, and decision support.
- Human supervisor: final accountability and approval.
- Base Sepolia contracts: shared state, escrow, one-time settlement, and minimal tamper-evident proof.
- Supabase: identity, organization data, RLS-protected records, and private evidence.
flowchart LR
B[Browser\nNext.js + Wagmi] -->|session + typed requests| N[Next.js route handlers\nVercel]
B -->|wallet signature| E[WorkOrderEscrow\nBase Sepolia]
N -->|user-scoped reads| A[Supabase Auth + RLS]
N -->|authorized service operation| P[(PostgreSQL)]
N -->|private object access| S[Private Storage]
N -->|authorized multimodal evidence\nstore: false| G[Gemini Interactions API]
E --> T[pUSDC]
E --> X[EquipmentPassport]
N -->|receipt + contract-state reconciliation| E
S -. raw evidence never on-chain .-> N
The chain is the payment source of truth. Supabase is updated only after a successful receipt and contract-state read. Evidence bytes, filenames, private URLs, and personal information never go on-chain.
- Next.js App Router, React, strict TypeScript, Tailwind CSS v4
- React Hook Form, Zod, Recharts, Framer Motion, Sonner, next-themes
- Supabase PostgreSQL, Auth, Storage,
@supabase/ssr - Gemini
@google/genaiInteractions API; defaultgemini-2.5-flash - Solidity 0.8.28, Hardhat 3 (Foundry optional), OpenZeppelin, Base Sepolia
- Wagmi, Viem, injected browser wallets
- Vitest, Testing Library, Hardhat Node tests, optional Playwright/Foundry tests
app/ Public, auth, application, and API routes
components/ UI, shell, dashboard, evidence, verification, blockchain
lib/ AI, auth, contracts, hashing, scoring, state, validation
types/ Shared domain types and enums
supabase/migrations/ Schema, constraints, RLS, storage, protected functions
supabase/seed.sql Secure seed entrypoint note
contracts/ Solidity sources, scripts, and Foundry tests
scripts/ Demo seeding and ABI synchronization
tests/ Unit, component, API, and Playwright tests
docs/ Architecture, security, demo, pitch, judging
Prerequisites: Node.js 20+, npm, and a free Supabase project. Hardhat is installed with the project; Foundry is optional.
git clone <your-repository-url> ProofOps
Set-Location ProofOps
Copy-Item .env.example .env.local
npm.cmd install
npm.cmd run devOpen http://localhost:3000. With empty external values, /app is a read-only seeded exploration. Mutations explain exactly which configuration is missing.
- Create a free Supabase project.
- Copy the project URL and publishable key into
.env.local. - Put the service-role key in
SUPABASE_SERVICE_ROLE_KEY(server only). - Install and authenticate the Supabase CLI.
- Link and apply the migration:
supabase login
supabase link --project-ref <project-ref>
supabase db pushThe migration creates the private work-order-evidence bucket, constraints, indexes, RLS, and service-only atomic functions. Confirm the bucket remains private in the dashboard.
- Set
DEMO_USER_PASSWORDlocally to a strong demo-only password, then seed:
node --env-file=.env.local scripts/seed-demo.mjs- Add these Auth redirect URLs:
http://localhost:3000/auth/callbackandhttps://<vercel-domain>/auth/callback. - Inspect RLS policies before using a production organization.
Demo accounts:
manager@proofops.demo— Maya Chentechnician@proofops.demo— Amir Rahmansupervisor@proofops.demo— Sarah Lim
The password comes only from local DEMO_USER_PASSWORD; it is not committed or exposed through NEXT_PUBLIC_.
Create a Gemini API key and add only this server-side value:
GEMINI_API_KEY=<key>
GEMINI_MODEL=gemini-2.5-flash
AI_DAILY_USER_LIMIT=10
Restart Next.js. The verification route authenticates and authorizes the requester, loads only assigned private evidence, rate-limits attempts, calls the Interactions API with store: false, validates strict structured JSON, recomputes the score, hashes the canonical report, and then persists it. There is no fallback provider and no mock-on-error path.
ProofOps includes a tested Hardhat Ignition deployment that deploys all three contracts and authorizes the escrow automatically.
Copy-Item contracts/.env.example contracts/.env
Get-Content contracts/.env | ForEach-Object { if ($_ -match '^([^#=]+)=(.*)$') { [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') } }
npm.cmd run contracts:compile:hardhat
npm.cmd run contracts:deploy:hardhatUse a Base Sepolia-only deployer key with faucet ETH. The deployment prints the MockUSDC, EquipmentPassport, and WorkOrderEscrow addresses. Hardhat stores resumable deployment state under the ignored ignition/deployments/ directory.
Copy those three public addresses into .env.local, then verify the live deployment:
npm.cmd run contracts:verify:deploymentSign in as each demo user and open Settings to save a distinct Base Sepolia public address. The manager address must be the EquipmentPassport owner printed by verification. The manager wizard then registers equipment, faucets demo pUSDC, approves the exact amount, creates/funds escrow, verifies receipts, and synchronizes Supabase. The technician submits the finalized evidence hash on-chain; the supervisor records verification and releases payment or raises a dispute.
Install Foundry, then install pinned libraries from the repository root:
forge install foundry-rs/forge-std --no-commit
forge install OpenZeppelin/openzeppelin-contracts --no-commit
Copy-Item contracts/.env.example contracts/.envEdit contracts/.env locally. Use only Base Sepolia faucet ETH; never use mainnet funds. Load the variables and run tests:
Get-Content contracts/.env | ForEach-Object { if ($_ -match '^([^#=]+)=(.*)$') { [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') } }
forge test -vvv --root contractsDeploy all three contracts and authorize the escrow in the passport:
forge script script/Deploy.s.sol:Deploy --root contracts --rpc-url base_sepolia --broadcast --verifyIf no explorer key is available, omit --verify. Copy the printed public addresses into .env.local:
NEXT_PUBLIC_MOCK_USDC_ADDRESS=0x...
NEXT_PUBLIC_PASSPORT_CONTRACT_ADDRESS=0x...
NEXT_PUBLIC_ESCROW_CONTRACT_ADDRESS=0x...
Synchronize generated ABIs after a contract change:
forge build --root contracts
npm.cmd run abi:syncDEPLOYER_PRIVATE_KEY belongs only in ignored contracts/.env. It is never needed by the browser, Next.js, or Vercel.
npm.cmd run lint
npm.cmd run typecheck
npm.cmd run test
npm.cmd run test:e2e
npm.cmd run build
npm.cmd run check
npm.cmd run contracts:test:hardhat
forge test -vvv --root contractsThe Playwright test intentionally checks that, without Gemini/contracts, the UI explains the missing configuration and keeps approval disabled instead of faking success.
- Push this repository to GitHub.
- In Vercel, choose Add New → Project, import the repository, and keep the root directory as
.. - Framework preset: Next.js. Build command:
npm run build. Output: Next.js default. - Add every value from
.env.exampleexceptDEMO_USER_PASSWORD; addSUPABASE_SERVICE_ROLE_KEYandGEMINI_API_KEYas encrypted server variables. - Never add
DEPLOYER_PRIVATE_KEYorcontracts/.envto Vercel. - Deploy, then add
https://<deployment>/auth/callbackto Supabase Auth redirect URLs. - Redeploy after environment changes.
- Sign in through each role, test one private signed evidence URL, run Gemini, connect an injected wallet on chain 84532, and execute one full funded flow.
- Confirm explorer links point to
https://sepolia.basescan.organd that database payment state changes only after receipt confirmation.
See docs/SECURITY.md. Hackathon limitations: public Base RPC rate limits may apply; dispute resolution uses factory + supervisor consensus rather than an external arbitrator; the app is not a regulatory certification system; demo pUSDC has no value; and chain event indexing is reconciled on demand rather than through a dedicated indexer.