agr3012/epochzero-learn
GitHub: agr3012/epochzero-learn
一个基于 Next.js 和 Supabase 构建的逆向工程与恶意软件分析在线学习中心,提供文章、视频、在线测试及可验证证书颁发功能。
Stars: 0 | Forks: 0
# REMA Club — 学习门户
一个基于 Next.js 14 + Supabase + Resend 的逆向工程与恶意软件分析学习中心。提供公开文章、视频演示、带有可验证证书的 MCQ 测试,以及电子书和题库下载。
## 技术栈
- **Next.js 14** (App Router, TypeScript)
- **Tailwind CSS** + 自定义主题
- **Supabase** — Postgres, Auth, Storage, RLS
- **Resend** — 事务性邮件
- **@react-pdf/renderer** — 证书 PDF
- **next-mdx-remote** — 文章渲染
- **Vercel** — 托管 (Hobby 计划)
## 项目结构
```
rema-club/
├── app/ # App Router pages
│ ├── (api)
│ │ ├── auth/register, login/ # account auth — no email-domain restriction
│ │ ├── enrollment/redeem/ # POST: redeem a batch enrollment code
│ │ ├── admin/batches/ # GET/POST: generate & list enrollment codes
│ │ ├── tests/start/ # POST: login-gated, enrollment-checked attempt start
│ │ ├── tests/submit/ # POST: score test, trigger cert
│ │ └── certificates/generate/# POST: render PDF, upload, email
│ ├── articles/[slug]/ # Article reader (MDX)
│ ├── videos/[slug]/ # Video + step-by-step sidebar
│ ├── tests/[slug]/ # Test detail + engine
│ ├── verify/[uid]/ # Public certificate verification
│ ├── resources/ # Downloadable PDFs
│ ├── podcast/ # Audio episodes
│ ├── reels/ # Instagram reel grid
│ ├── about/
│ ├── page.tsx # Landing
│ └── layout.tsx
├── components/
│ ├── navbar.tsx
│ ├── footer.tsx
│ ├── test-engine.tsx # Multi-step MCQ engine (client)
│ ├── certificate-pdf.tsx # PDF document
│ └── video-player.tsx # YouTube embed wrapper
├── lib/
│ ├── supabase/ # client / server / admin clients
│ ├── resend.ts
│ ├── env.ts # Zod-validated env vars
│ └── utils.ts # formatters, slugify
├── supabase/migrations/
│ ├── 001_initial_schema.sql
│ └── 002_rls_policies.sql
├── public/
│ └── logo.png # REMA Club shield
├── scripts/
│ └── bootstrap-admin.mjs # promote a user to admin
├── middleware.ts # Supabase session refresh
├── tailwind.config.ts
├── next.config.js
└── .env.local.example
```
## 部署清单
请按以下顺序操作。跳过任何步骤都会导致后续步骤出错。
### 1. Supabase 项目
1. 在 创建一个新项目。
2. **SQL Editor → New query** → 粘贴 `supabase/migrations/001_initial_schema.sql` → Run。
3. **SQL Editor → New query** → 粘贴 `supabase/migrations/002_rls_policies.sql` → Run。
4. **Project Settings → API** — 复制以下内容:
- `Project URL` → `NEXT_PUBLIC_SUPABASE_URL`
- `anon public key` → `NEXT_PUBLIC_SUPABASE_ANON_KEY`
- `service_role key` → `SUPABASE_SERVICE_ROLE_KEY` (注意保密)
### 2. Resend 账户(电子邮件)
1. 在 注册。
2. **API Keys → Create API Key** → 复制并记为 `RESEND_API_KEY`。
3. **Domains → Add Domain** → 输入你要用于发送邮件的域名(例如 `epochzero.net`)。添加 Resend 提供给你的 DNS 记录 (SPF, DKIM, DMARC)。等待验证完成。
4. 将 `RESEND_FROM_EMAIL` 设置为已验证的发件人 — 例如 `REMA Club `。
- 如果在初始测试时没有已验证的域名,你可以使用 `onboarding@resend.dev`。
### 3. 本地开发
```
git clone
cd rema-club
cp .env.local.example .env.local
# 填写 .env.local 中的所有值
npm install
npm run dev
```
访问 。
### 4. Vercel 部署
1. 将代码仓库推送到 GitHub。
2. 进入 → **Add New → Project** → 导入该仓库。
3. **Environment Variables** → 添加 `.env.local.example` 中的所有变量。将 `NEXT_PUBLIC_SITE_URL` 设置为你的 Vercel URL(例如 `https://rema-club.vercel.app`)。
4. **Deploy。**
5. 部署完成后,如果你的 Resend 域名在首次部署时还未通过验证,请更新 `RESEND_FROM_EMAIL`,然后点击 **Redeploy**。
### 5. 引导创建管理员用户
管理面板受到 `admin_users` 上的 RLS 保护。要创建第一个管理员:
1. **Supabase Dashboard → Authentication → Add user** → 使用你的邮箱,并勾选启用 *Auto Confirm User*。
2. 运行:
node scripts/bootstrap-admin.mjs you@example.com super_admin
3. 现在前往 `/admin/login` 使用该邮箱登录应用(管理后台 UI 将在第 6 阶段构建)。
### 6. 添加内容
在管理后台 UI 上线之前,请直接通过 Supabase 的 **Table Editor** 或 SQL 插入内容:
- `articles` — 设置 `mdx_content`,`is_published = true`,`published_at = now()`
- `videos` — 设置 `youtube_id`,`steps` 可选设置为 JSON 数组
- `tests` + `test_questions` — 批量插入问题;确保设置了 `correct_index`
- `resources` — 将 PDF 上传到 Supabase Storage 的 `resources` bucket,并将公开的 URL 粘贴到 `file_url` 中
### 7. 端到端验证测试 → 证书流程
1. 通过 SQL Editor 插入一行测试数据 + 5 个问题。
2. 访问 `/tests/`。
3. 提交你的真实邮箱 → 检查收件箱获取 OTP → 参加测试 → 验证带有 PDF 附件的证书邮件是否成功发送。
4. 访问 `/verify/REMA-2026-XXXXXX` 以确认公开验证功能正常运行。
## 安全模型
- **正确答案绝不会离开服务器。** 测试引擎仅接收问题文本 + 选项。评分过程在 API 路由中使用 service role key 进行。
- **选项乱序通过完整性校验**:客户端回传 `option_permutation` 数组,服务端在评分前会重新应用该数组。
- **OTP 频率限制:** 每个邮箱每个测试每小时 5 个验证码。静态存储时使用 SHA-256 哈希加密。
- **仅限首次通过颁发证书。** 重复通过不会颁发新证书。
- 每个表都启用了 **RLS**。anon key 无法读取 `test_questions`、`attempts`、`email_otps` 或 `admin_users`。
- **Service role key** 仅在 API 路由和引导脚本中使用。绝不能将其导入到 Client Component 中。
- **可选的 Cloudflare Turnstile**:可通过设置 `TURNSTILE_SECRET_KEY` 和 `NEXT_PUBLIC_TURNSTILE_SITE_KEY` 来启用。
## 路线图
| 阶段 | 状态 | 描述 |
|-------|--------|-------------|
| 1. 基础架构 | ✓ 完成 | 脚手架、落地页、布局、Supabase、设计系统 |
| 2. 内容阅读 | ✓ 完成 | 文章 (MDX)、资源、播客、短视频 |
| 3. 视频学习 | ✓ 完成 | YouTube 网格布局、分步侧边栏 |
| 4. 测试引擎 + 证书 | ✓ 完成 | OTP、MCQ 流程、PDF 证书、邮件、公开验证 |
| 5. 学生仪表盘 | ◯ 待处理 | 无密码登录、历史尝试记录、可下载证书 |
| 6. 管理面板 | ◯ 待处理 | 文章/视频/测试的 CRUD 操作、批量导入 MCQ |
## 许可证
教育项目。内容许可按标记区分各个文章/视频。代码:MIT。
标签:DAST, Supabase, 云资产清单, 在线教育, 恶意软件分析, 测试用例, 自动化攻击, 逆向工程