Show HN:Certo——用于交付 Open Badges 的开源平台
英文标题:🔶 Show HN: Certo – An open source platform to deliver Open Badges
Certo 是一个开源数字凭证平台,可依据 Open Badges 3.0 规范和 W3C Verifiable Credentials 数据模型签发、管理与验证徽章及证书。平台支持徽章模板、单个或 CSV 批量签发、公开验证、凭证撤销、证据附件、第三方背书及 LinkedIn 分享。其技术栈包括 Strapi 5 后端、Nuxt 3 前端、PostgreSQL 或 SQLite,并提供 Docker Compose 部署方案及 OpenAPI 文档。对教育机构、培训组织、企业和开源社区而言,Certo 提供了一个可自托管、遵循开放标准的数字认证基础设施。
825.9 KB
19.4 KB
42.9 KB
130.2 KB
63.2 KB
中文
Certo 是一个综合性数字凭证平台,用于签发、管理和验证基于 Open Badges 3.0 规范及 W3C Verifiable Credentials 数据模型的徽章和证书。
Certo 是一个开源平台,使组织和个人能够按照全球标准签发可验证的数字凭证(徽章和证书)。无论是运营教育项目、工作坊、认证课程,还是需要表彰成就,Certo 都为创建、签发和验证数字凭证提供完整解决方案。
- 签发方创建徽章模板(Achievements),定义徽章所代表的内容、获取标准及关联技能
- 签发方可向接收者单独签发凭证,或通过 CSV 上传批量签发
- 接收者收到凭证后,可在其仪表板中查看
- 任何人均可通过公开验证页面核验凭证的真实性
- 接收者可以在 LinkedIn 及其他平台分享其已验证凭证
Certo 实现了:
-
Open Badges 3.0:IMS Global Learning Consortium 制定的数字凭证标准
-
W3C Verifiable Credentials:具备加密安全性和防篡改特征的凭证
-
去中心化标识符:用于稳健的身份管理
-
教育机构:签发课程结业证书和学术成就凭证
-
培训组织:为工作坊和培训项目提供可验证证书
-
活动组织者:为会议和聚会授予出席或参与徽章
-
企业:认可员工技能、认证资格及职业发展成果
-
开源社区:确认贡献和参与情况
-
专业协会:签发会员凭证和专业认证
🏆 徽章与证书管理
- 创建 Achievements:设计可自定义标准、技能和元数据的徽章模板
- 签发凭证:为工作坊、课程、活动和项目签发数字证书
- 批量签发:上传 CSV 文件,同时向多名接收者签发凭证
- 基于角色的访问控制:区分签发方和接收者角色,并设置相应权限
🔐 验证与安全
-
加密验证:使用加密证明和 Verifiable Credentials 模型验证徽章真实性
-
撤销支持:维护已失效凭证的撤销列表
-
防篡改:所有凭证均经过加密签名,并具备防篡改特性
-
LinkedIn 集成:可直接在 LinkedIn 上分享证书
-
多种导出格式:支持以多种格式导出凭证
-
公开验证:任何人均可通过验证页面核验凭证真实性
-
证据附件:可为凭证附加支持性证据和说明
-
背书:支持第三方对凭证进行背书
-
仪表板:查看和管理所有已签发及已接收的凭证
-
开放标准:完全符合 Open Badges 3.0 规范
certo/ ├── src/ │ ├── backend/ # Strapi 5.x backend (TypeScript) │ │ ├── src/ │ │ │ ├── api/ # API endpoints │ │ │ │ ├── achievement/ # Badge templates/definitions (Open Badges 3.0) │ │ │ │ ├── credential/ # Issued credentials/badges │ │ │ │ ├── profile/ # User profiles (issuers & recipients) │ │ │ │ ├── evidence/ # Evidence attachments │ │ │ │ ├── endorsement/ # Third-party endorsements │ │ │ │ └── revocation-list/# Credential revocation lists │ │ │ ├── admin/ # Strapi admin customizations │ │ │ ├── components/ # Reusable content components │ │ │ ├── middlewares/ # Custom middlewares │ │ │ └── utils/ # Utility functions │ │ ├── config/ # Strapi configuration │ │ ├── database/ # Database migrations │ │ ├── public/ # Static files & uploads │ │ ├── scripts/ # Utility scripts │ │ ├── types/ # TypeScript type definitions │ │ ├── Dockerfile # Backend Docker configuration │ │ └── package.json # Backend dependencies │ │ │ └── frontend/ # Nuxt 3 frontend (Vue 3 + TypeScript + Una UI) │ ├── pages/ # Application pages │ │ ├── index.vue # Home page │ │ ├── issue.vue # Badge issuance (CSV upload support) │ │ ├── verify.vue # Credential verification │ │ ├── dashboard.vue # User dashboard │ │ └── ... # Other pages │ ├── components/ # Vue components │ ├── composables/ # Vue composables │ ├── stores/ # Pinia state management │ ├── middleware/ # Route middleware (auth, etc.) │ ├── api/ # API client libraries │ ├── types/ # TypeScript types │ ├── plugins/ # Nuxt plugins │ ├── assets/ # CSS, images, SVG components │ ├── public/ # Static public files │ ├── e2e/ # Playwright E2E tests │ ├── Dockerfile # Frontend Docker configuration │ └── package.json # Frontend dependencies │ ├── netlify/ # Netlify serverless functions │ └── functions/ │ └── og-credential/ # Open Graph image generation ├── docker-compose.yml # Docker Compose configuration ├── README.md # This file ├── LICENSE # AGPL-3.0 License ├── CONTRIBUTING.md # Contribution guidelines └── CODE_OF_CONDUCT.md # Code of conduct
Docker 部署设置(推荐)
-
Docker 和 Docker Compose
-
Node.js 18-22.x(用于本地开发)
-
Node.js 18.x - 22.x
-
npm 6.0.0 或更高版本
-
PostgreSQL 13+(开发环境也可使用 SQLite)
-
后端:Strapi 5.15.0、TypeScript 5.x、Node.js 18-22.x
-
前端:Nuxt 3.10+、Vue 3.4+、TypeScript 5.x、Una UI
-
数据库:PostgreSQL(生产环境)或 SQLite(开发环境)
-
认证:使用 jose 库的 JWT
-
测试:Vitest(单元测试)、Playwright(E2E)
- 克隆仓库:
git clone https://github.com/schrodinger-hat/certo.git
cd certo
- 创建环境变量:
在 src/backend 目录中创建 .env 文件,并设置以下变量:
# Required Strapi Secrets
ADMIN_JWT_SECRET=your-admin-jwt-secret
JWT_SECRET=your-jwt-secret
APP_KEYS=your-app-keys
# Database Configuration (PostgreSQL)
DATABASE_CLIENT=postgres
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=certo
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strapi
# Server Configuration
HOST=0.0.0.0
PORT=1337
# Frontend URL (for CORS)
FRONTEND_URL=http://localhost:3000
在 src/frontend 目录中创建 .env 文件:
# API Configuration
NUXT_PUBLIC_API_URL=http://localhost:1337
NUXT_PUBLIC_WEBSITE_URL=http://localhost:3000
# Optional: Google Analytics
NUXT_PUBLIC_GTAG=your-gtag-id
- 启动 Docker 容器:
这将启动后端(Strapi)、前端(Nuxt 3)和 PostgreSQL 数据库。
- 等待容器完成初始化。首次运行时,后端将自动:
- 创建用于测试的示例数据
- 配置所有必要的 API 权限
默认登录凭证(管理面板和前端相同):
- 电子邮箱:
admin@certo.com - 密码:
certo
示例数据包括:
- 一个 Strapi 管理员用户(用于
/admin管理面板) - 一个 API 用户(用于前端认证)
- 一个 Profile(同时配置为签发方和接收者)
- 一个示例 Achievement(“Welcome to Certo”)
- 一项授予管理员用户的示例凭证/徽章
自动配置的权限:
- 已认证用户可访问所有 API 端点(profiles、achievements、credentials 等)
- 公开用户可以读取和验证徽章
注意:种子数据仅在首次运行时创建。如需重置数据库,请运行
docker-compose down -v删除卷,然后重新启动。
- 访问应用:
本地运行(不使用 Docker)
如果希望在本地不使用 Docker 运行应用程序,则需要单独设置 PostgreSQL,或在开发环境中使用 SQLite。
- 设置数据库(PostgreSQL 或 SQLite)
- 按上述说明创建
.env文件 - 安装并运行:
cd src/backend
npm install
npm run develop # Development mode with auto-reload
# or
npm run dev # Alternative dev command
Strapi 管理面板将位于 http://localhost:1337/admin
首次设置:首次启动时,请在提示出现后创建管理员账户。
- 按上述说明创建
.env文件 - 安装并运行:
cd src/frontend
npm install
npm run dev
前端将位于 http://localhost:3000
- 先启动后端(运行在 1337 端口)
- 启动前端(将连接至后端 API)
- 在 Strapi 中创建管理员账户
- 在前端注册用户账户
- 在 Strapi 管理后台将用户角色设为“issuer”,即可签发徽章
API 遵循 Open Badges 3.0 规范。Swagger UI(OpenAPI)位于 http://localhost:1337/documentation。
公开端点:
GET /api/credentials/:id- 获取公开凭证数据(Open Badges 3.0 格式)POST /api/credentials/verify- 验证凭证真实性GET /api/revocation-list/check/:id- 检查凭证是否已被撤销
需认证的端点:
-
POST /api/achievements- 创建徽章模板(仅限签发方) -
POST /api/credentials/batch-issue- 向多名接收者签发凭证 -
GET /api/profiles/me- 获取当前用户 Profile -
GET /api/profiles/:id/credentials- 获取用户的凭证 -
POST /api/endorsements- 创建凭证背书 -
POST /api/evidence- 为凭证附加证据 -
Achievement:徽章模板/定义(Open Badges 3.0 中的 Badge Class)
-
Credential:已签发的徽章/证书(Open Badges 3.0 中的 Badge Assertion)
-
Profile:用户 Profile(签发方或接收者)
-
Evidence:凭证的支持性文档
-
Endorsement:对凭证的第三方验证
-
Revocation List:已撤销凭证列表
如需完整 API 文档,请在完成设置后访问位于 http://localhost:1337/admin 的 Strapi 管理面板。
单元测试(Vitest):
cd src/frontend
npm run test:unit # Run once
npm run test:unit:watch # Run in watch mode
端到端测试(Playwright):
cd src/frontend
npm run test:e2e
E2E 测试涵盖:
- 用户注册和登录流程
- 徽章签发工作流
- 凭证验证
- 仪表板功能
- 导航和路由
后端使用 Strapi 的测试框架。可在后端目录中运行测试:
部署 Certo 最简单的方式是使用 Docker Compose:
这将以生产模式启动全部所需服务(后端、前端和数据库)。
cd src/backend
npm install
npm run build
npm start
cd src/frontend
npm install
npm run build
npm start
生产环境变量
请务必为以下变量设置安全的值:
ADMIN_JWT_SECRET- 用于管理员认证的高强度随机字符串JWT_SECRET- 用于用户认证的高强度随机字符串APP_KEYS- 以逗号分隔的随机字符串列表DATABASE_PASSWORD- 安全的数据库密码- 使用生产环境 URL 更新
FRONTEND_URL和NUXT_PUBLIC_API_URL
欢迎贡献!请随时提交 Pull Request。
- Fork 该仓库
- 创建功能分支(
git checkout -b feature/amazing-feature) - 提交你的更改(
git commit -m 'Add some amazing feature') - 推送至分支(
git push origin feature/amazing-feature) - 创建 Pull Request
本项目采用 GNU Affero General Public License v3.0 许可——详情请参阅 LICENSE 文件。
English / 原文
Certo is a comprehensive digital credentials platform for issuing, managing, and verifying badges and certificates based on the Open Badges 3.0 specification and the W3C Verifiable Credentials data model.
Certo is an open-source platform that enables organizations and individuals to issue verifiable digital credentials (badges and certificates) following global standards. Whether you're running educational programs, workshops, certification courses, or need to recognize achievements, Certo provides a complete solution for creating, issuing, and verifying digital credentials.
- Issuers create badge templates (Achievements) defining what the badge represents, criteria for earning it, and associated skills
- Issuers issue credentials to recipients either individually or in bulk via CSV upload
- Recipients receive their credentials and can view them in their dashboard
- Anyone can verify the authenticity of a credential using the public verification page
- Recipients can share their verified credentials on LinkedIn and other platforms
Certo implements:
-
Open Badges 3.0 : IMS Global Learning Consortium standard for digital credentials
-
W3C Verifiable Credentials : Cryptographically secure and tamper-evident credentials
-
Decentralized Identifiers : For robust identity management
-
Educational Institutions : Issue course completion certificates and academic achievements
-
Training Organizations : Provide verifiable certificates for workshops and training programs
-
Event Organizers : Award attendance or participation badges for conferences and meetups
-
Companies : Recognize employee skills, certifications, and professional development
-
Open Source Communities : Acknowledge contributions and participation
-
Professional Associations : Issue membership credentials and professional certifications
🏆 Badge & Certificate Management
- Create Achievements : Design badge templates with customizable criteria, skills, and metadata
- Issue Credentials : Issue digital certificates for workshops, courses, events, and projects
- Batch Issuance : Upload CSV files to issue credentials to multiple recipients simultaneously
- Role-Based Access : Separate issuer and recipient roles with appropriate permissions
🔐 Verification & Security
-
Cryptographic Verification : Verify badge authenticity using cryptographic proofs and the Verifiable Credentials model
-
Revocation Support : Maintain revocation lists for invalidated credentials
-
Tamper-Evident : All credentials are cryptographically signed and tamper-evident
-
LinkedIn Integration : Share certificates directly on LinkedIn
-
Multiple Export Formats : Export credentials in various formats
-
Public Verification : Anyone can verify credential authenticity via the verification page
-
Evidence Attachments : Attach supporting evidence and narratives to credentials
-
Endorsements : Third-party endorsement support for credentials
-
Dashboard : View and manage all issued and received credentials
-
Open Standards : Full compliance with Open Badges 3.0 specification
certo/ ├── src/ │ ├── backend/ # Strapi 5.x backend (TypeScript) │ │ ├── src/ │ │ │ ├── api/ # API endpoints │ │ │ │ ├── achievement/ # Badge templates/definitions (Open Badges 3.0) │ │ │ │ ├── credential/ # Issued credentials/badges │ │ │ │ ├── profile/ # User profiles (issuers & recipients) │ │ │ │ ├── evidence/ # Evidence attachments │ │ │ │ ├── endorsement/ # Third-party endorsements │ │ │ │ └── revocation-list/# Credential revocation lists │ │ │ ├── admin/ # Strapi admin customizations │ │ │ ├── components/ # Reusable content components │ │ │ ├── middlewares/ # Custom middlewares │ │ │ └── utils/ # Utility functions │ │ ├── config/ # Strapi configuration │ │ ├── database/ # Database migrations │ │ ├── public/ # Static files & uploads │ │ ├── scripts/ # Utility scripts │ │ ├── types/ # TypeScript type definitions │ │ ├── Dockerfile # Backend Docker configuration │ │ └── package.json # Backend dependencies │ │ │ └── frontend/ # Nuxt 3 frontend (Vue 3 + TypeScript + Una UI) │ ├── pages/ # Application pages │ │ ├── index.vue # Home page │ │ ├── issue.vue # Badge issuance (CSV upload support) │ │ ├── verify.vue # Credential verification │ │ ├── dashboard.vue # User dashboard │ │ └── ... # Other pages │ ├── components/ # Vue components │ ├── composables/ # Vue composables │ ├── stores/ # Pinia state management │ ├── middleware/ # Route middleware (auth, etc.) │ ├── api/ # API client libraries │ ├── types/ # TypeScript types │ ├── plugins/ # Nuxt plugins │ ├── assets/ # CSS, images, SVG components │ ├── public/ # Static public files │ ├── e2e/ # Playwright E2E tests │ ├── Dockerfile # Frontend Docker configuration │ └── package.json # Frontend dependencies │ ├── netlify/ # Netlify serverless functions │ └── functions/ │ └── og-credential/ # Open Graph image generation ├── docker-compose.yml # Docker Compose configuration ├── README.md # This file ├── LICENSE # AGPL-3.0 License ├── CONTRIBUTING.md # Contribution guidelines └── CODE_OF_CONDUCT.md # Code of conduct
For Docker Setup (Recommended)
-
Docker and Docker Compose
-
Node.js 18-22.x (for local development)
-
Node.js 18.x - 22.x
-
npm 6.0.0 or higher
-
PostgreSQL 13+ (or use SQLite for development)
-
Backend : Strapi 5.15.0, TypeScript 5.x, Node.js 18-22.x
-
Frontend : Nuxt 3.10+, Vue 3.4+, TypeScript 5.x, Una UI
-
Database : PostgreSQL (production) or SQLite (development)
-
Authentication : JWT with jose library
-
Testing : Vitest (unit), Playwright (E2E)
- Clone the repository:
git clone https://github.com/schrodinger-hat/certo.git
cd certo
- Create environment variables:
Create a .env file in the src/backend directory with the following variables:
# Required Strapi Secrets
ADMIN_JWT_SECRET=your-admin-jwt-secret
JWT_SECRET=your-jwt-secret
APP_KEYS=your-app-keys
# Database Configuration (PostgreSQL)
DATABASE_CLIENT=postgres
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=certo
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strapi
# Server Configuration
HOST=0.0.0.0
PORT=1337
# Frontend URL (for CORS)
FRONTEND_URL=http://localhost:3000
Create a .env file in the src/frontend directory:
# API Configuration
NUXT_PUBLIC_API_URL=http://localhost:1337
NUXT_PUBLIC_WEBSITE_URL=http://localhost:3000
# Optional: Google Analytics
NUXT_PUBLIC_GTAG=your-gtag-id
- Start the Docker containers:
This will start the backend (Strapi), frontend (Nuxt 3), and PostgreSQL database.
- Wait for the containers to initialize. On first run, the backend will automatically:
- Create sample data for testing
- Configure all necessary API permissions
Default login credentials (same for admin panel and frontend):
- Email:
admin@certo.com - Password:
certo
Sample data includes:
- A Strapi admin user (for the admin panel at
/admin) - An API user (for frontend authentication)
- A profile (configured as both Issuer and Recipient)
- A sample achievement ("Welcome to Certo")
- A sample credential/badge awarded to the admin user
Permissions automatically configured:
- Authenticated users can access all API endpoints (profiles, achievements, credentials, etc.)
- Public users can read and verify badges
Note: Seed data is only created on the first run. If you need to reset the database, run
docker-compose down -vto remove volumes, then start again.
- Access the applications:
Running Locally (Without Docker)
If you prefer to run the applications locally without Docker, you'll need to set up PostgreSQL separately or use SQLite for development.
- Set up your database (PostgreSQL or SQLite)
- Create the
.envfile as described above - Install and run:
cd src/backend
npm install
npm run develop # Development mode with auto-reload
# or
npm run dev # Alternative dev command
The Strapi admin panel will be available at http://localhost:1337/admin
First-time setup : Create an admin account when prompted on first launch.
- Create the
.envfile as described above - Install and run:
cd src/frontend
npm install
npm run dev
The frontend will be available at http://localhost:3000
- Start the backend first (it runs on port 1337)
- Start the frontend (it connects to the backend API)
- Create an admin account in Strapi
- Register a user account in the frontend
- Set user role to "issuer" in Strapi admin to issue badges
The API follows the Open Badges 3.0 specification. Swagger UI (OpenAPI) is available at http://localhost:1337/documentation.
Public Endpoints:
GET /api/credentials/:id- Retrieve public credential data (Open Badges 3.0 format)POST /api/credentials/verify- Verify credential authenticityGET /api/revocation-list/check/:id- Check if a credential is revoked
Authenticated Endpoints:
-
POST /api/achievements- Create badge templates (issuer only) -
POST /api/credentials/batch-issue- Issue credentials to multiple recipients -
GET /api/profiles/me- Get current user profile -
GET /api/profiles/:id/credentials- Get user's credentials -
POST /api/endorsements- Create credential endorsements -
POST /api/evidence- Attach evidence to credentials -
Achievement : Badge template/definition (Badge Class in Open Badges 3.0)
-
Credential : Issued badge/certificate (Badge Assertion in Open Badges 3.0)
-
Profile : User profile (issuer or recipient)
-
Evidence : Supporting documentation for credentials
-
Endorsement : Third-party validation of credentials
-
Revocation List : List of revoked credentials
For complete API documentation, access the Strapi admin panel at http://localhost:1337/admin after setup.
Unit Tests (Vitest):
cd src/frontend
npm run test:unit # Run once
npm run test:unit:watch # Run in watch mode
End-to-End Tests (Playwright):
cd src/frontend
npm run test:e2e
E2E tests cover:
- User registration and login flows
- Badge issuance workflow
- Credential verification
- Dashboard functionality
- Navigation and routing
The backend uses Strapi's testing framework. Tests can be run from the backend directory:
The easiest way to deploy Certo is using Docker Compose:
This will start all required services (backend, frontend, and database) in production mode.
cd src/backend
npm install
npm run build
npm start
cd src/frontend
npm install
npm run build
npm start
Environment Variables for Production
Make sure to set secure values for:
ADMIN_JWT_SECRET- Strong random string for admin authenticationJWT_SECRET- Strong random string for user authenticationAPP_KEYS- Comma-separated list of random stringsDATABASE_PASSWORD- Secure database password- Update
FRONTEND_URLandNUXT_PUBLIC_API_URLwith your production URLs
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the GNU Affero General Public License v3.0 - see the LICENSE file for details.
