A modern web dApp to issue, manage, share, and authorize verifiable credentials. Built with Next.js 16, React 19, TypeScript, Tailwind CSS, and the ACTA SDK.
- Issue credentials to users and manage issuer authorization
- Maintain a vault of credentials with search, share, and revoke actions
- Guided onboarding via tutorials and quick start flows
- Responsive UI with accessible components and consistent design
- Framework: Next.js 16 (App Router, Turbopack)
- UI: React 19, TypeScript, Tailwind CSS v4, Radix UI
- Icons:
lucide-react - State & Data: TanStack Query
- SDKs:
@acta-team/acta-sdk, Stellar Wallets Kit
- Node.js 18 or newer
- npm (or your preferred package manager)
-
Install dependencies:
npm install
-
Run in development:
npm run dev
The app runs at
http://localhost:3000/.
npm run dev— start the dev servernpm run build— create a production buildnpm run start— run the production servernpm run lint— run ESLintnpm run format— format with Prettier
-
Build the app:
npm run build
-
Start the server:
npm run start
Deploy to any Node-compatible environment. Static and dynamic routes are handled by Next.js.
src/app— App Router pages and layoutsdashboard/— home, authorize, credentials, issue, tutorialscredential/[id]— dynamic credential page
src/components/modules— domain componentsdashboard/— quick start and dashboard UIcredentials/— credential list, card, share modalvault/— vault dashboard and issuer management
src/components/ui— shared UI (buttons, cards, effects)src/layouts— application layout and sidebarsrc/providers— app-wide context providers (network, wallet, ACTA SDK)
- The app supports sharing credentials with an attached zero-knowledge proof (ZK) that validates a predicate without revealing private data.
- ZK proofs are generated client-side and verified client-side using Noir and bb.js backends.
- Age ≥ 18 (
isAdult) - Not expired (
notExpired) - Status is valid (
isValid)
- Select the fields to reveal, pick a ZK predicate, and click
Generate ZK Proof. - The share link payload includes:
revealedFields: only the selected public fieldsstatement: the selected predicate and public parameterspublicSignalsandproof: proof artifacts required for verification
- Encoding of the payload occurs in the share hook:
src/components/modules/credentials/hooks/useShareCredential.ts:62–77.
- The credential page decodes the
sharepayload and shows revealed fields. - The ZK section ("ZK Proof", "Test", and privacy message) is hidden until the user clicks
Verify Proof. - On click, the app verifies the proof using the appropriate circuit and updates the UI:
- Verification trigger and state:
src/components/modules/credentials/hooks/useCredentialVerify.ts:125–144 - ZK section gating in the card:
src/components/modules/credentials/ui/CredentialVerifyCard.tsx:120–149
- Verification trigger and state:
- ACIR JSON files are served under
public/zk/:noir_workshop.json— Age ≥ 18noir_not_expired.json— Not expirednoir_valid_status.json— Status is valid
- Circuit loading and proof generation happen in
src/lib/zk.ts.
- Verification relies on
backend.verifyProof— not on NoirreturnValue. - Only selected fields are revealed; no private inputs are shared.
- The ZK section remains hidden until explicit user verification to improve transparency.
- All public-facing texts in the ZK flow are in English.
- Icons are provided by
lucide-reactfor consistency and clarity - Tailwind CSS v4 is used for styling with utility classes
- The ACTA SDK is configured via
ActaProvider; no environment setup is required for local development
- Do not commit secrets to the repository
- Keep
.env*files local and out of version control
Issues and PRs are welcome. Keep changes focused and follow the existing code style. Run npm run lint and npm run build before submitting.