A decentralized credential platform built on XRPL that allows anyone to create schemas and issue verifiable credentials. Credentials can be stored privately (on our service) or publicly (on IPFS), following W3C Verifiable Credentials standards.
- Framework: Nuxt 4 (Full SSR)
- Runtime: Node.js 20+
- Language: TypeScript
- Database: PostgreSQL 16+ with Drizzle ORM
- XRPL: xrpl.js v4+, Testnet (wss://s.altnet.rippletest.net:51233)
- IPFS: ipfs-http-client (configurable provider)
- UI: Vue 3 (Composition API) + TailwindCSS + Nuxt UI
- Validation: Zod
- β
Database schema defined (
server/db/schema.ts)- Schemas table with versioning support
- Credentials table with W3C VC format
- Proper indexes for performance
- β
Database connection setup (
server/db/index.ts) - β
Type definitions (
lib/types/schema.ts)- SchemaField, SchemaFields, Schema interfaces
- Credential and W3CVerifiableCredential interfaces
- β
XRPL client (
server/utils/xrpl.ts)- Connection management
- Credential creation on-chain (CredentialCreate)
- Credential acceptance (CredentialAccept)
- Credential deletion (CredentialDelete)
- Ripple time conversion
- β
IPFS client (
server/utils/ipfs.ts)- Publish to IPFS
- Get from IPFS
- Unpin functionality
- Gateway URL builder
- β
W3C VC utilities (
server/utils/w3c-vs.ts)- W3C VC document generation
- Schema validation
- β
Validation schemas (
server/utils/validation.ts)
- β
Schema Management
POST /api/schema/create- Create new schemaPOST /api/schema/list- List/search schemasGET /api/schema- Get schema by IDPOST /api/schema/update-version- Update schema version
- β
Credential Management
POST /api/credential/issue- Issue credentialPOST /api/credential/list- List/query credentialsGET /api/credential- Get credential by IDPOST /api/credential/revoke- Revoke credentialPOST /api/credential/accept- Accept credential (subject)
- β
SchemaForm.vue- Full schema creation form with dynamic fields - β
CredentialForm.vue- Credential issuance form - β
CredentialAcceptance.vue- Subject acceptance view
- β Nuxt config with runtime config
- β Drizzle config
- β Environment variables template
- β Package.json with all dependencies
-
Database Setup
- Generate initial Drizzle migration from schema
- Run migration to create tables
- Add seed data script (optional, for testing)
-
Missing Server Utilities
- Error handling utilities (
server/utils/errors.ts)- Custom error classes
- Error response formatting
- Complete W3C VC utilities (
server/utils/w3c-vc.ts)- Ensure
validateDataAgainstSchemafunction exists - Ensure
generateW3CVCfunction exists - Add proof generation (signature support)
- Ensure
- Error handling utilities (
-
API Endpoint Fixes
- Review and fix missing imports (e.g.,
eqfrom drizzle-orm in some files) - Add health check endpoint (
/api/health.get.ts) - Add proper error middleware (
server/middleware/error-handler.ts)
- Review and fix missing imports (e.g.,
-
Database Connection
- Verify
server/db/index.tsexports working db instance - Test connection with PostgreSQL
- Verify
-
Project Structure Fix
- Move components from
app/components/pages/to properapp/pages/structure - Create proper page files:
app/pages/index.vue- Landing pageapp/pages/schemas/index.vue- Browse schemasapp/pages/schemas/create.vue- Create schemaapp/pages/schemas/[id].vue- Schema detailapp/pages/credentials/index.vue- Browse credentialsapp/pages/credentials/issue.vue- Issue credentialapp/pages/credentials/[id].vue- Credential detailapp/pages/credentials/accept.vue- Accept credentialsapp/pages/docs/index.vue- Documentationapp/pages/docs/w3c-guide.vue- W3C VC guide
- Move components from
-
Missing Components
- Schema Components
SchemaCard.vue- Display schema summarySchemaList.vue- List of schemas with search/filterSchemaVersionHistory.vue- Show version history
- Credential Components
CredentialCard.vue- Display credential summaryCredentialList.vue- List of credentials with filters
- Layout Components
AppHeader.vue- Navigation headerAppFooter.vue- Footer
- UI Components (if not using Nuxt UI for all)
- Verify Nuxt UI provides: Button, Input, Select, Card, Badge, Modal
- Create custom components only if needed
- Schema Components
-
Layouts
- Create
app/layouts/default.vuewith header/footer - Update
app/app.vueto use NuxtLayout and NuxtPage
- Create
-
Page Integrations
- Wire up components to API endpoints using
useFetchor$fetch - Add loading states and error handling
- Add success notifications
- Implement pagination for lists
- Wire up components to API endpoints using
-
Code Quality
- Review all TypeScript errors
- Add missing type imports
- Fix any linting issues
-
Error Handling
- Add comprehensive error handling to all API endpoints
- Display user-friendly error messages in UI
- Add validation error display in forms
-
Testing
- Manual testing of all flows:
- Create schema (private and public)
- Issue credential (private and public)
- Accept credential
- Revoke credential
- View schemas and credentials
- Test XRPL integration on testnet
- Test IPFS publishing and retrieval
- Manual testing of all flows:
-
UX Improvements
- Add loading spinners
- Add confirmation modals for destructive actions
- Add form validation feedback
- Improve mobile responsiveness
-
Authentication System: Add user wallet connection (XUMM or similar)
- Currently using env-based issuer wallet
- Future: Allow users to connect their own wallets
- Need wallet signature verification
- Session management
-
IPFS Refactoring: Review and potentially refactor IPFS implementation
- Current implementation uses
ipfs-http-client - May want to switch to Helia (already installed)
- Consider using Pinata SDK directly
- Improve error handling and retry logic
- Current implementation uses
-
Advanced search and filtering
-
Credential verification endpoint
-
Webhook support for credential events
-
Export credentials in various formats
-
Schema marketplace/discovery
-
Analytics dashboard
- Node.js 20+
- PostgreSQL 16+
- XRPL Testnet account with funded wallet
- (Optional) IPFS provider credentials (Pinata, Web3.Storage, etc.)
-
Clone and Install Dependencies
npm install
-
Database Setup
# Create database createdb xcs # Or using psql psql -U postgres CREATE DATABASE xcs;
-
Environment Variables
cp .env.example .env
Edit
.env:# Database DATABASE_URL=postgresql://user:12345678@localhost:5432/xcs # XRPL Configuration XRPL_SERVER=wss://s.altnet.rippletest.net:51233 ISSUER_SEED=sXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Your testnet wallet seed # IPFS Configuration (if using public storage) IPFS_PROVIDER=pinata PINATA_JWT=your_pinata_jwt_here IPFS_GATEWAY=https://gateway.pinata.cloud # Application BASE_URL=http://localhost:3000 PORT=3000
-
Generate and Run Database Migrations
# Generate migration from schema npm run db:generate # Push to database npm run db:push # Or use Drizzle Studio to inspect npm run db:studio
-
Start Development Server
npm run dev
If you don't have a testnet wallet:
// Run this script once to generate a wallet
import { Client, Wallet } from 'xrpl'
const client = new Client('wss://s.altnet.rippletest.net:51233')
await client.connect()
// Generate new wallet
const wallet = Wallet.generate()
console.log('Address:', wallet.address)
console.log('Seed:', wallet.seed) // Save this securely!
// Fund it from testnet faucet
const response = await client.fundWallet(wallet)
console.log('Funded:', response)
await client.disconnect()Or use the XRPL Testnet Faucet: https://xrpl.org/xrp-testnet-faucet.html
- Navigate to
/schemas/create - Fill in schema details:
- Name (required)
- Description
- Version (semantic versioning)
- Public/Private toggle
- Add fields with types and validation rules
- Submit - schema will be created in DB and optionally on IPFS
- Navigate to
/credentials/issue - Select a schema
- Enter subject XRPL address
- Fill in credential data according to schema
- Choose public (IPFS) or private storage
- Submit - credential will be:
- Validated against schema
- Stored in DB and optionally IPFS
- Created on-chain via XRPL CredentialCreate transaction
- Subject can then accept it
- Subject navigates to
/credentials/accept - Views pending credentials
- Clicks accept
- Provides their wallet seed (for MVP)
- XRPL CredentialAccept transaction is submitted
Create Schema
POST /api/schema/create
Body: {
name: string
description?: string
version: string
fields: SchemaField[]
isPublic: boolean
parentSchemaId?: string
}
List Schemas
POST /api/schema/list
Body: {
creator?: string
isPublic?: boolean
search?: string
limit?: number
offset?: number
}
Get Schema
GET /api/schema?id={schemaId}
Issue Credential
POST /api/credential/issue
Body: {
schemaId: string
subject: string (XRPL address)
data: object
isPublic: boolean
expiresAt?: string (ISO date)
}
List Credentials
POST /api/credential/list
Body: {
issuer?: string
subject?: string
schemaId?: string
accepted?: boolean
revoked?: boolean
limit?: number
offset?: number
}
Accept Credential
POST /api/credential/accept
Body: {
credentialId: string
subjectSeed: string
}
Revoke Credential
POST /api/credential/revoke
Body: {
credentialId: string
}
xrpl-credential-platform/
βββ app/
β βββ components/
β β βββ schema/
β β β βββ SchemaForm.vue β
β β β βββ SchemaCard.vue β
β β β βββ SchemaList.vue β
β β β βββ SchemaVersionHistory.vue β
β β βββ credential/
β β β βββ CredentialForm.vue β
β β β βββ CredentialCard.vue β
β β β βββ CredentialList.vue β
β β β βββ CredentialAcceptance.vue β
β β βββ layout/
β β βββ AppHeader.vue β
β β βββ AppFooter.vue β
β βββ pages/ β (needs to be created)
β βββ layouts/
β β βββ default.vue β
β βββ app.vue β οΈ (needs update)
βββ server/
β βββ api/ β
β βββ utils/ β οΈ (mostly complete, some functions need implementation)
β βββ db/
β β βββ schema.ts β
β β βββ index.ts β οΈ (needs verification)
β β βββ migrations/ β (needs generation)
β βββ middleware/
β βββ error-handler.ts β
βββ lib/
β βββ types/
β β βββ schema.ts β
β βββ constants.ts β
βββ .env.example β
βββ nuxt.config.ts β
βββ drizzle.config.ts β
βββ package.json β
βββ README.md β
Legend:
β
Complete
β οΈ Partial/Needs Review
β Not Started
The system follows W3C VC 1.1 specification:
@context: Standard W3C contextstype: VerifiableCredential + custom typesissuer: XRPL address of issuercredentialSubject: Data validated against schemacredentialSchema: Reference to schema (IPFS CID or internal ID)
Uses XRPL Credentials Amendment (XRPL v2.0):
CredentialCreate: Creates on-chain credential attestationCredentialAccept: Subject accepts credentialCredentialDelete: Issuer revokes/deletes credential- Credentials stored as hex-encoded types with URIs
-
Schema Creation: Schema β Validate β Store DB β (If public) β Publish IPFS β Return
-
Credential Issuance: Data β Validate against Schema β Generate W3C VC β (If public) β Publish IPFS β Create XRPL Credential β Store DB β Return
-
Credential Acceptance: Request β Load Credential β Verify Subject β XRPL CredentialAccept β Update DB β Return
- Ensure PostgreSQL is running:
pg_isready - Check credentials in
.env - Verify database exists:
psql -U user -l
- Test network connectivity to testnet
- Verify issuer seed is valid
- Check wallet is funded (minimum 10 XRP)
- Verify provider credentials (Pinata JWT)
- Check network connectivity
- Test with public gateway first
- Clear
.nuxtdirectory:rm -rf .nuxt - Clear node_modules:
rm -rf node_modules && npm install - Check TypeScript errors:
npx nuxi typecheck
When working on this project:
- Backend first - ensure all APIs work
- UI second - build components and pages
- Bug fixes and polish last
- Test each feature thoroughly
- Follow the spec.md for requirements