在线编程平台 (Online Judge) · 一站式题库 · 竞赛 · 社区 · 成就系统
UltiCode 是一个面向开发者的全栈在线评测(Online Judge)平台。提供从练习、竞赛、社区交流到管理后台的完整闭环。
无论你是想刷题备战、举办算法竞赛、运营编程社区,还是搭建一个内部刷题系统,UltiCode 都提供开箱即用的能力。
想看更多视图、对比 light/dark 主题或下载原图:见 assets/screenshots/。
| 模块 | 能力 |
|---|---|
| 题库 | 标签、难度、搜索、题单、收藏夹、Markdown 题面、测试用例预览 |
| 在线评测 | 多语言(Python / C / C++ / Java …)沙箱执行,D-form 隔离运行,实时返回 Verdict |
| 题解 | Markdown + KaTeX 富文本、点赞、收藏、评论 |
| 社区论坛 | 帖子 / 评论 / 点赞 / 关注 / 通知、敏感词与内容审核 |
| 竞赛 | 个人赛 / 团队赛 / 公开赛 / 虚拟赛,榜单(ACM / OI / IOI 规则)、赛中聊天 |
| 成就系统 | 解题徽章、连击、排行榜 |
| 个人主页 | 提交记录、Rating、刷题进度、关注 / 粉丝 |
| 国际化 | 中英双语切换(vue-i18n),所有用户文案走翻译键 |
| 主题 | Light / Dark / System + Compact / Comfortable 密度档 |
| PWA | 离线缓存、桌面安装、推送通知 |
| 模块 | 能力 |
|---|---|
| 数据看板 | 注册趋势、提交分布、判题分布、收入与订阅概览 |
| 用户管理 | 角色 / 封禁 / 审计日志、批量操作 |
| 题库 / 竞赛管理 | 题目、测试用例、SPJ、特价比赛、滚动改题 |
| 提交审计 | 实时提交流、Replay、再判 |
| 社区治理 | 举报队列、申诉、敏感词、用户警告 |
| 通知 / 邮件 | 模板化系统通知、可定向推送 |
| 订阅 / 计费 | 会员档位、订单、收入仪表 |
| 系统设置 | Nacos 配置、Feature Flag、安全策略 |
视口 1496×933 桌面端。浅 / 深主题通过右上角用户菜单 → 主题 切换;以下所有截图源文件见 assets/screenshots/。
Light
Dark · 浏览与社区
| 论坛平台 | 帖子详情 | 比赛首页 | 比赛详情 |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Dark · 题库与题目
| 题库专题 | 题单详情 | 题目详情 |
|---|---|---|
![]() |
![]() |
![]() |
Dark · 个人中心
| 个人 Dashboard | 提交记录 | 成就徽章 |
|---|---|---|
![]() |
![]() |
![]() |
Dark · 概览
| 数据分析 | 仪表板 |
|---|---|
![]() |
![]() |
Dark · 治理与审计
| 用户管理 | 比赛管理 | 内容审核 | 提交审计 |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
┌────────────────────────────────────────────┐
│ Browser (PWA) │
│ Console 9002 · Management 9003 │
└────────────┬────────────────┬───────────────┘
│ Axios + CSRF │
▼ ▼
┌────────────────────────────────────────────┐
│ Spring Boot 3.2.5 · Java 17 (9001) │
│ 26 modules · MyBatis-Plus · MapStruct │
│ JWT + Redis Session · SpringDoc OpenAPI │
└──┬──────────────┬──────────────┬───────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌───────────────┐
│ MySQL │ │ Redis │ │ Nacos │
│ 9.1 │ │ 7 │ │ 2.3.2 │
│ (23306) │ │ (26379) │ │ (28848) │
└──────────┘ └──────────┘ └───────────────┘
▲
│
┌────────────┴─────────────┐
│ Sandbox Runner (D-form) │
│ Python · C · C++ · Java │
│ Hexagonal / Source-Stage-Image │
└────────────────────────────┘
UltiCode/
├── backend-spring/ # Spring Boot 3.2.5 后端 — 端口 9001
├── console/ # Vue 3 用户前端 — 端口 9002
├── management/ # Vue 3 管理后台 — 端口 9003
├── shared/ # 共享包 (auth-core · auth-ui · badge-config · design-system · sandbox-types · theme)
├── init-db/ # Flyway 数据库迁移
├── docker/ # Docker 初始化脚本 (Nacos SQL · Sandbox harness)
├── assets/ # README 截图等二进制资源
├── scripts/dev/ # 开发运维脚本 (init-env · up · migrate · test)
├── infrastructure/ # Arthas 项目级配置
└── ecosystem.config.cjs # PM2 进程编排
| 领域 | 技术 |
|---|---|
| 运行时 | Java 17 (vfox 管理) · Spring Boot 3.2.5 |
| 持久化 | MyBatis-Plus 3.5.16 · MySQL 9.1 · Flyway |
| 对象映射 | MapStruct 1.6.3 |
| 认证 | JWT (jjwt 0.13.0) · Redis (Redisson 4.3.1) · OAuth2 state in HttpOnly cookie |
| API 文档 | SpringDoc OpenAPI 2.6.0 |
| WebSocket | STOMP over SockJS · Cookie-only access token |
| 测试 | JUnit 5 · Testcontainers (MySQL + Redis) · JaCoCo |
| 领域 | 技术 |
|---|---|
| 框架 | Vue 3.5 + TypeScript (strict) + Composition API |
| 构建 | Vite 8 · pnpm 10 |
| 路由 / 状态 | Vue Router 5 · Pinia 3 |
| UI | Tailwind CSS v4 · shadcn-vue (reka-ui) · Radix Vue · Lucide / Tabler Icons |
| 国际化 | vue-i18n 11(中英双语) |
| HTTP | Axios(统一 request.ts · CSRF 自动注入 · 401 自动跳转) |
| PWA | vite-plugin-pwa + Workbox |
| 测试 | Vitest 4 · jsdom · Playwright (management) |
| 代码检查 | ESLint 9/10 (flat config) · Prettier(无分号 / 单引号 / 100 字符) |
| 领域 | 技术 |
|---|---|
| 容器 | Docker Compose v2 · 非 root 用户 (appuser:appgroup) · 多阶段构建 |
| 进程管理 | PM2(4 个长生命周期 + 1 个一次性 Flyway 任务) |
| 运行时诊断 | Arthas 4.2.2 · STATELESS MCP(端口 8563) |
| 服务发现 / 配置 | Nacos 2.3.2 |
| CI/CD | GitHub Actions(路径触发) · CD 滚动发布与回滚 |
每个模块遵循 controller → service → mapper (MyBatis-Plus) → entity 分层,DTO 转换由 MapStruct 完成。
| 模块 | 职责 |
|---|---|
auth |
登录 / 注册 / OAuth / 找回密码 / 刷新 token |
user |
用户资料 / 关注 / 实名 |
problem |
题目 / 测试用例 / SPJ |
problemlist |
题单 / 收藏夹 |
submission |
提交记录 / 判题 / Replay |
solution |
题解 / 评论 / 点赞 |
contest |
比赛 / 榜单 / 注册 |
forum |
帖子 / 评论 / 板块 |
vote |
点赞 / 点踩 |
notification |
站内通知 / 邮件 / 推送 |
achievement |
成就 / 徽章 / 解题连击 |
subscription |
订阅 / 支付 / 订单 |
moderation |
审核队列 / 举报 / 申诉 |
search |
全文 / 向量检索 |
i18n |
翻译键托管 |
bookmark · follow |
收藏 / 关注 |
email |
邮件模板 / 队列 |
admin · permission |
角色 / 权限 / 审计 |
monitoring · backup |
监控 / 备份 |
edgeoperations · queue |
边缘任务 / 异步队列 (Outbox + Fencing) |
websocket · refreshtoken |
WebSocket 鉴权 / Token 轮换 |
backup |
数据备份与恢复 |
- Console (用户端) — 题目 · 题单 · 提交 · 竞赛 · 论坛 · 成就 · 个人主页 · Dashboard
- Management (管理端) — Dashboard · 用户 · 题目 · 提交 · 竞赛 · 论坛 · 审核 · 通知 · 订阅 · 标签 · 系统 · 审计 · Help
| 包 | 说明 |
|---|---|
auth-core |
Vue composable 鉴权核心(Cookie / CSRF / Auth state / 权限) |
auth-ui |
登录 / 注册 / 找回密码 UI 组件(双端共享) |
badge-config |
成就徽章配置 |
design-system |
设计 token 与组件原语 |
sandbox-types |
OJ 沙箱契约类型(与 docker/sandbox/ 跨语言通信) |
theme |
主题系统:State / Tokens / Primitives / Bootstrap |
改动
shared/必须在shared/auth-core跑pnpm test+pnpm type-check,并在 console / management 双端验证。
| 工具 | 版本 | 用途 |
|---|---|---|
| Docker + Compose | v2 | MySQL / Redis / Nacos |
| Java | 17 (推荐 vfox 管理) | 后端构建与运行 |
| Node.js | ^20.19.0 || >=22.12.0 |
前端 / pnpm |
| pnpm | 10+ | 前端依赖 |
| PM2 | latest | 进程管理 |
# 1. 克隆
git clone <repo>
cd UltiCode
# 2. 首次:生成带随机凭据的私有 .env(已有则跳过)
./scripts/dev/init-env.sh
# 3. 启动基础设施 + Flyway 迁移 + 安装依赖 + 启动应用
./scripts/dev/up.shup.sh 是幂等的。再次启动且依赖未变时可跳过安装:
./scripts/dev/up.sh --skip-installdev 数据库会自动创建固定管理员账号:
用户名:admin
密码: admin123
⚠️ 该弱密码仅用于本机 dev 数据库。基础设施密码和 JWT / Nacos 密钥均由init-env.sh随机生成,写入 Git 忽略的.env。 生产环境必须改用强密码与外部密钥管理。
| 服务 | 地址 | 备注 |
|---|---|---|
| 用户前端 (Console) | http://localhost:9002 | PWA · 支持 light/dark/compact 切换 |
| 管理后台 (Management) | http://localhost:9003 | 需 admin 角色 |
| 后端 API | http://localhost:9001 | REST · Result<T> 封装 |
| Swagger UI | http://localhost:9001/swagger-ui.html | OpenAPI 3 |
| Nacos 控制台 | http://localhost:28848/nacos | 配置中心 / 服务发现 |
| Arthas MCP | http://localhost:8563/mcp | STATELESS · Claude Code / IDE 直连 |
端口暴露策略:
docker-compose.yml不发布基础设施端口;docker-compose.dev.yml仅绑定127.0.0.1。 生产 compose 进一步收紧,两个前端只绑 loopback,TLS 终止在外部网关。
# 通过 PM2
pm2 restart ulticode-9001
pm2 logs ulticode-9001
# 直接启动
./mvnw spring-boot:run -Dmaven.test.skip=true
# 编译 / 测试 / 集成
./mvnw compile -B
./mvnw test -B # 排除 *IT.java
./mvnw -Dtest='*IT' test -B # Testcontainers 集成
./mvnw verify -B # 含 JaCoCo 校验
./mvnw package -DskipTestspnpm install
pnpm dev # lint + type-check + format + test + Vite dev
pnpm build # type-check + Vite build
pnpm type-check # vue-tsc --build
pnpm lint # eslint . --fix --cache
pnpm format # prettier --write src/
pnpm test # vitest --run
pnpm test:coverage# 与 console 相同的命令
pnpm dev / pnpm build / pnpm test
# 额外:i18n key 完整性检查
pnpm validate:i18n-keyspnpm test
pnpm type-check修改
shared/auth-core必须在 console / management 双端验证。详见 docs/CONTRIBUTING.md §6。
./scripts/dev/migrate.sh migrate # 跑迁移
./scripts/dev/migrate.sh info # 状态
./scripts/dev/migrate.sh validate # 校验
./scripts/dev/migrate.sh repair # 修复 checksum mismatch迁移文件命名:V{N}__{description}.sql,唯一真源在 init-db/migrations/。
绝不再编辑已应用的迁移 —— 只能新增时间戳更大的迁移。
# 开发
docker compose --env-file .env \
-f docker-compose.yml -f docker-compose.dev.yml up -d
# 生产
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# 直接进 MySQL(容器默认 latin1,必须显式指定 utf8mb4)
set -a; source .env; set +a
docker exec -e MYSQL_PWD="$DB_PASSWORD" ulticode-mysql \
mysql --default-character-set=utf8mb4 -u "$DB_USER" "$DB_NAME" \
-e "SHOW TABLES;"字符集陷阱:不指定
--default-character-set=utf8mb4会导致中文被双重编码(æžå¨œ)。详见 CLAUDE.md §MySQL 容器化操作。
./scripts/dev/test.sh quick # 后端 / shared / console / management 单元测试 + 类型检查
./scripts/dev/test.sh full # quick + 前端构建 + i18n 检查 + 依赖审计
./scripts/dev/test.sh integration # quick + Testcontainers + Sandbox 集成测试| 触碰面 | 跑这套 |
|---|---|
| 后端 | ./mvnw compile test -B |
| 后端集成 | ./mvnw -Dtest='*IT' test -B |
| Console | pnpm lint && pnpm type-check && pnpm test && pnpm build |
| Management | pnpm lint && pnpm type-check && pnpm test && pnpm validate:i18n-keys && pnpm build |
| 共享包 | cd shared/auth-core && pnpm test && pnpm type-check |
| 迁移 / 配置 | docker compose ... config >/dev/null · git diff --check |
GitHub Actions 在 push / PR 到 main 时触发,基于路径变化检测仅运行相关任务。
| Job | 触发条件 | 内容 |
|---|---|---|
| Backend | backend-spring/** |
Maven 构建 + 单测 + Flyway 校验 |
| Console | console/** |
lint + type-check + test |
| Management | management/** |
lint + type-check + test + i18n 校验 |
| Docker | Dockerfile 变更 | 多阶段构建验证 |
| Integration | 定时 / 手动 | Testcontainers(MySQL 9.1 + Redis 7) |
| CD Deploy | workflow_dispatch |
滚动发布到指定环境 |
| CD Rollback | workflow_dispatch |
一键回滚到指定 image tag |
部署 Runbook 见 wiki/overview/dev-environment-overview.md § 启动 / 部署章节。
| 端口 | PM2 app | 进程类型 | 备注 |
|---|---|---|---|
| 9001 | ulticode-9001 |
Spring Boot 后端 | 长生命周期 |
| 9002 | ulticode-9002 |
Console (Vite) | dev: Vite · prod: 静态服务 |
| 9003 | ulticode-9003 |
Management (Vite) | dev: Vite · prod: 静态服务 |
| — | ulticode-init-db |
Flyway 一次性任务 | stopped 是预期终态 |
| 8563 | ulticode-arthas |
Arthas MCP wrapper | STATELESS 协议 |
pm2 start ecosystem.config.cjs # 首次启动(按序拉起 init-db → 9001 → 前端)
pm2 start all # 后续启动
pm2 restart all # 重启
pm2 stop all
pm2 status # 状态
pm2 logs # 实时日志
pm2 logs ulticode-9001 --nostream --lines 200 # 拉最近 200 行
pm2 save && pm2 resurrect # 持久化与恢复ulticode-mysql/ulticode-redis/ulticode-nacos必须 Up + Healthypm2 restart ulticode-init-db(跑 Flyway)pm2 restart ulticode-9001- 启动两个前端
一键修复:
./scripts/dev/up.sh --skip-install
.env 是唯一真实来源(gitignored),由 init-env.sh 生成。
完整字段与说明见 docs/ENV.md 与 .env.example。
| 变量 | 用途 | 备注 |
|---|---|---|
DB_HOST / DB_PORT |
MySQL 地址 | dev: localhost:23306 |
DB_USER / DB_PASSWORD / DB_NAME |
MySQL 凭据 | — |
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD |
Redis 配置 | dev: localhost:26379 |
JWT_SECRET |
JWT 签名密钥 | ≥ 32 字符,由 init-env 随机生成 |
CORS_ALLOWED_ORIGINS |
跨域白名单 | dev: http://localhost:9002,http://localhost:9003 |
NACOS_SERVER_ADDR |
Nacos 地址 | dev: localhost:28848 |
NACOS_USERNAME / NACOS_PASSWORD |
Nacos 鉴权 | dev profile 专用账号 |
FRONTEND_URL |
邮件 / 回调拼接 | dev: http://localhost:9002 |
SPRING_PROFILES_ACTIVE |
Spring Profile | dev / prod |
pm2 env 缓存陷阱:
pm2 restart --update-env不会重读.env。 改.env后若 9001 报RedisWrongPasswordException等认证错,请用:pm2 delete ulticode-9001 && pm2 start ecosystem.config.cjs --only ulticode-9001
| 主题 | 约定 |
|---|---|
| 提交格式 | <type>: <description> · 类型: feat fix refactor docs test chore perf ci |
| 提交前自检 | git diff · git diff --check |
| Prettier | 无分号 · 单引号 · 100 字符行宽 |
| 集成测试 | *IT.java 后缀,从 ./mvnw test 排除;用 ./mvnw -Dtest='*IT' test 或 ./scripts/dev/test.sh integration |
| 迁移命名 | V{N}__{description}.sql,置于 init-db/migrations/ |
| Docker 容器 | 非 root appuser:appgroup · 多阶段构建 |
| 后端 DTO 枚举 | 后端 DTO 字段使用 String(前端用 TS enum);新代码优先推进后端 enum 化 |
| 分支策略 | 默认在 main 直接提交(多文件 / 多 commit / 跨模块亦可) |
| 危险操作 | git push / merge / publish / 改写历史 / 改第三方资源 必须显式批准 |
完整规范:AGENTS.md · CLAUDE.md · docs/CONTRIBUTING.md
UltiCode 维护一份分层的工程知识库,按需查阅:
| 你是… | 从这里开始 |
|---|---|
| 第一次提 PR | docs/CONTRIBUTING.md |
| On-call 工程师 | docs/RUNBOOK.md §0 速查 + §4 常见问题 |
| 架构师 / 规划者 | wiki/ (entities/ + overview/,无 ADR/概念层) |
| 后端开发 | docs/CODEMAPS/backend.md + .claude/rules/springboot-rules.md |
| 前端开发 | docs/CODEMAPS/frontend.md + .claude/rules/frontend-rules.md |
| 数据库 / Flyway | docs/CODEMAPS/data.md + .claude/rules/database/01-flyway-migrations.md |
| 沙箱 / 评测 | docs/CODEMAPS/sandbox.md + docs/adr/0002-sandbox-hexagonal-dform.md |
| 运维 / 部署 / 密钥 | docs/ENV.md + docs/RUNBOOK.md |
| 安全审查 | docs/SECURITY_REVIEW_2026-06-06.md + .claude/agents/security-reviewer.md |
| 主题 / 样式 | docs/theme/README.md + docs/CODEMAPS/frontend.md §Theme |
| 决策记录(ADR) | 已退役 (2026-07-09)。设计决策沉淀在 AGENTS.md / CLAUDE.md / 源码 Javadoc + 迁移注释;wiki 仅保留"是什么 / 怎么拼"层 |
欢迎贡献代码、文档、Issue 与功能建议。在开始前请阅读:
- CONTRIBUTING.md — 开发环境、代码风格、PR 清单、评审礼仪
- AGENTS.md — 仓库级权威指南(结构、工具链、启动流程、运维命令)
- CLAUDE.md — Claude Code 协作约定、字符集陷阱、Arthas / PM2 速查
# 1. 看 diff
git diff && git diff --check
# 2. 触碰面测试(按矩阵执行)
./scripts/dev/test.sh quick # 日常
./scripts/dev/test.sh full # 涉及前端构建
./scripts/dev/test.sh integration # 涉及后端集成
# 3. 提交(Conventional Commits)
git add -A
git commit -m "feat(module): concise description"请使用 GitHub Issues,并附上:
- 复现步骤 / 期望 / 实际行为
- 环境(dev / prod、浏览器、Node / Java 版本)
- 关键日志(
pm2 logs ulticode-9001 --nostream --lines 200)
本项目基于 MIT License 开源。
MIT License
Copyright (c) 2026 UltiCode
Built with ❤️ by the UltiCode team
如果这个项目对你有帮助,欢迎 ⭐ Star!
















