DevysonSilva/kiroku

GitHub: DevysonSilva/kiroku

Kiroku 是一款基于 Next.js 构建的私有动漫与漫画追踪应用,帮助个人用户集中记录和管理跨媒体的观看阅读历程。

Stars: 8 | Forks: 0

# Kiroku 記録

Next.js 16 React 19 TypeScript strict Prisma + MongoDB 305 tests

*Kiroku* (記録, "记录") 用一个集中记录你作为观众和读者所有历程的地方,取代了分散的电子表格和列表——无论你想看什么、正在看什么、已看完、暂停还是 放弃——这里都有一个完整且可审计的历史记录。
Painel no tema Neon (roxo) Painel no tema Sakura (rosa) Painel no tema Tinta (vermelho) com a fonte Torii

三个主题下的同一个面板Neon · Sakura · Tinta。Feature 009:3 种暗色调色板 × 4 种标题字体,可实时切换并通过 cookie 记忆(在首次绘制时应用,无闪烁)。

## 🤖 我的第一个结合 *spec-driven development* + Claude 的项目 这是我的**第一个基于规范驱动开发构建的项目**—— 使用 [**spec-kit**](https://github.com/github/spec-kit) 并将 **Claude (Claude Code)** 作为结对 编程伙伴。 其核心思想是颠倒“直接开始写代码”的常规顺序:**每个 feature 都源自一份规范**,代码 再根据规范生成。意图存在于文档中;代码是其结果。在实践中,每个 feature 都会经历以下流程: ``` constitution → specify → clarify → plan → tasks → (testes RED) → implement → analyze → merge ``` - 一份包含 10 条不可妥协原则的**[宪法](.specify/memory/constitution.md)**统领一切——它的优先级高于任何代码习惯。 - 每一个 feature 对应 [`specs/00N-*`](specs/) 中的一个文件夹,每一个 feature 对应一个分支。 - **优先编写测试**(RED-first),并且在实现**之前**就会失败。 - 每个区域都有自己的 `CLAUDE.md`(动态文档),并在代码变更的**同一个 PR** 中更新——过时的文档即视为 bug。 - **每次合并前的质量门禁**:`typecheck` + `lint` + `test` + `build`,全部必须零错误。 这是一种学习如何以高级工程师的严谨纪律进行开发的方式——同时也留下了清晰的痕迹,记录了*为什么*要做出每一项决策。 ## ✨ 功能特性 | # | Feature | 描述 | |---|---------|-------| | 001 | **所有者访问** | GitHub (OAuth) 登录,单人 *allowlist*,应用 100% 私有。 | | 002 | **设计系统 + 框架** | Tokens、组件 (shadcn) 以及已登录区域的导航。 | | 003 | **动漫** | 通过**复制 AniList** 添加,基于单集的状态/进度、网格视图、详情页、“继续观看”和历史记录。 | | 004 | **阅读** | 在同一引擎下处理 Mangá/manhwa/manhua —— 手动录入,按连续章节追踪进度。 | | 005 | **评分与笔记** | 总评分、各类型分类、各单元评分、三个列表(角色、最佳、语录)。 | | 006 | **整理** | 可编辑的 genre、支持无拼音音调自动补全的自由 **tags**、所有者的**列表**(包含“收藏夹”)。 | | 007 | **搜索与过滤** | 从 7 个维度切割合集并支持排序 —— 筛选状态保留在**地址** (URL) 中,搜索忽略重音符号。 | | 008 | **面板** | 统计数据与推荐 —— 宏观视角,100% 读取,缺失数据始终明确声明。 | | 009 | **主题** | 3 种暗色调色板 (Neon · Tinta · Sakura) × 4 种标题字体,可切换,通过 cookie 记忆(无闪烁)。 | | 010 | **PWA + 移动端** | 可**安装**到主屏幕,手机端底部导航栏,返回按钮,响应式布局。 | **核心理念:** anime、mangá、manhwa 和 manhua 属于**同一种通用作品** (`Work` + `UserEntry`); ~90% 的逻辑只需编写**一次**,仅通过 `mediaType` 进行区分。一个引擎,多种媒体。 ## 📸 界面截图
Coleção de animes
Animes — busca sem acento, filtros e grid de capas (119 obras na coleção).
Tela Continuar
Continuar — retomar de onde parou em cada obra (temporada · episódio).
Coleção de leituras
Leituras — mangá / manhwa / manhua, cadastro manual, progresso por capítulo.
Listas e tags
Listas e tags — Favoritos garantido; tags nascem do uso, sem cadastro prévio.
## 🧩 技术栈 - **Next.js 16** (App Router, React Server Components) · **React 19** · **TypeScript** strict (零 `any`) - **Auth.js** (next-auth v5) — GitHub 登录,单人 *allowlist*,`httpOnly` JWT session - **Prisma 6** · **MongoDB** (Atlas) — 独立的目录副本,仅追加的历史记录 - **Tailwind CSS 4** · **shadcn/ui** (`radix-ui`) · **lucide-react** - **AniList** (GraphQL) — 外部 anime 数据源,在添加时本地复制 - **PWA** — 自带的 manifest 和 service worker(0 PWA 依赖),*fail-closed*(不缓存任何已登录内容) - **Vitest** + `mongodb-memory-server` — **305 个测试** · **Vercel** — 部署 ## 📱 工作原理(快速导览) 1. 使用 GitHub **登录** —— 仅所有者(在 *allowlist* 中的您的 id)可通过。 2. 通过在 AniList 中搜索来**添加 anime**:数据(封面、简介、剧集)将被**复制**到 您的数据库中。即使 AniList 随后宕机,也不会丢失任何数据。 3. 手动**添加阅读内容**(mangá/manhwa/manhua 没有外部数据源)。 4. **持续追踪**:标记剧集/章节,更改状态(想看 · 观看中 · 已完成 · 已暂停 · 已放弃),这一切都将成为**历史记录中的事件**(不会被删除)。 5. **评分与笔记**:总评分、分类、单集评分、最爱角色、语录。 6. 使用 **tags** 和**列表**进行**整理**(“收藏夹”是必不可少的)。 7. **查找**:搜索(忽略重音)并从 7 个维度进行筛选 —— 筛选结果保留在 URL 中,因此可以 分享并能在浏览器历史记录中恢复。 8. **俯瞰全局**:**面板**汇总了一切 —— 总数、分布、时间演变,以及基于您个人合集的推荐。 9. **个性化**:选择调色板(Neon/Tinta/Sakura)和标题字体 —— 通过 cookie 记忆。 10. **安装**到手机(添加到主屏幕)并使用底部导航栏。 ## 🚀 本地运行 **前置条件:** Node **20.9+**(推荐 22),一个 **MongoDB Atlas** cluster(免费版 即可)以及一个 GitHub 账号。 ``` # 1. 克隆和安装 git clone https://github.com/DevysonSilva/kiroku.git cd kiroku npm install # 2. secrets cp .env.example .env.local # 填写 5 个变量(见下方部分) # 3. 在 MongoDB 中创建 collections(Prisma 使用 db push — 无 SQL migrations) # ⚠ Prisma CLI 读取 .env,而不是 .env.local。请 export URL 或为此单独使用一个 .env: DATABASE_URL="sua-connection-string" npx prisma db push npx prisma generate # 4. 运行 npm run dev ``` 打开 **http://localhost:3000**。 ### 配置 GitHub 登录 1. GitHub → **Settings → Developer settings → OAuth Apps → New OAuth App**。 2. **Authorization callback URL**:`http://localhost:3000/api/auth/callback/github`。 3. 复制 **Client ID** 并生成 **Client Secret** → `.env.local`。 4. 您的 GitHub **数字 id**(用于 `OWNER_GITHUB_ID`)可在 `https://api.github.com/users/YOUR_USERNAME` 获取 → `id` 字段。 ## 🔑 环境变量 所有变量都在启动时由 Zod 验证 —— **少一个,应用就无法启动**(*fail-closed*)。 ``` # --- 认证 (Auth.js v5 + GitHub OAuth) --- # 签名会话 JWT(至少 32 个字符)。使用以下命令生成: npx auth secret # 或者: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" AUTH_SECRET= # 你的 GitHub OAuth App 凭据 AUTH_GITHUB_ID= AUTH_GITHUB_SECRET= # 你的数字 GitHub ID — 一个 allowlist(仅你能进入) # https://api.github.com/users/SEU_USUARIO -> "id" 字段 OWNER_GITHUB_ID= # --- 数据库 (MongoDB Atlas) --- # 包含路径中数据库名称的 connection string:.../mongodb.net/kiroku?retryWrites=true... DATABASE_URL= ``` ## 🛠️ 命令 | 命令 | 描述 | |---------|-------| | `npm run dev` | 开发服务器 | | `npm run build` | 生产环境构建 | | `npm run start` | 提供构建后的服务 | | `npm run lint` | ESLint | | `npm run typecheck` | `tsc --noEmit` | | `npm run test` | Vitest (305 个测试) | **每次合并前的质量门禁:** `typecheck` + `lint` + `test` + `build`,全部必须零错误。 ## 🏗️ 构建方式 (spec-kit) 每个 feature 都通过 [spec-kit](https://github.com/github/spec-kit) 的流程诞生,每个 feature 对应 `specs/00N-*` 中的一个文件夹。文档是**事实的唯一来源**:意图存在于规范中,代码 再据此生成。 - **宪法** ([`.specify/memory/constitution.md`](.specify/memory/constitution.md)) — 10 条 凌驾于任何代码习惯之上的原则。 - **`specify` → `clarify` → `plan` → `tasks`** — feature 转化为 spec,解决问题,生成技术计划 并排序任务。 - **RED-first 测试** — 由独立的会话编写,在实现**之前**就会失败。 - **`implement`** — 代码根据任务生成;**`analyze`** 将 spec × 计划 × 代码进行交叉比对。 - **动态文档** — 区域地图和约定位于 [`AGENTS.md`](AGENTS.md);每个 关键文件夹都有自己的 `CLAUDE.md`,在同一个 PR 中更新。 ## 📂 结构(按职责划分) | 区域 | 包含内容 | |------|---------------| | `app/` | 页面 (App Router, RSC) 和 `app/api/` (HTTP 路由) | | `components/` | shadcn 基础组件 (`ui/`) 及复合组件 | | `lib/auth/` · `lib/services/auth/` | session 基础设施 · 纯 allowlist 规则 | | `lib/services//` | 业务逻辑(works, entries, organization, collection, stats) | | `lib/media/` · `lib/appearance/` · `lib/anime-api/` | 按媒体划分的词汇表 · 主题 · AniList adapter | | `prisma/` | Prisma + MongoDB 的 schema 和约定 | | `specs/` · `.specify/` | feature 规范 · 宪法及模板 | 流程始终是 **`schema → service → route → UI`**(单向分层):UI 不直接访问 数据库,也不包含业务逻辑。 ## ☁️ 部署 (Vercel) 1. 将仓库导入 **Vercel**(Next 的标准构建;无需额外配置)。 2. **Environment Variables** (Production):与 `.env.local` 中的 5 个变量相同。 3. 在 **GitHub OAuth App** 中,添加生产环境的回调: `https://YOUR-DOMAIN.vercel.app/api/auth/callback/github` *(OAuth App 接受多个回调 —— 请将 `localhost` 和 Vercel 的地址保留在一起。)* 4. 在 **MongoDB Atlas → Network Access** 中,放行 Vercel 的访问权限(`0.0.0.0/0` 或其 IP)—— 否则应用在登录并读取数据库时会卡住。 Vercel 通过 **HTTPS** 提供服务,这使得 PWA 能够真正在手机上**安装**。 ## 📜 原则(宪法摘要) 1. **单一来源类型定义** — 类型源自 schema/Zod;无 `any`,无 barrel。 2. **单向分层** — `schema → service → route → UI`。 3. **一个引擎,多种媒体** — `mediaType` 是唯一的区分点。 4. **数据主权** — 本地目录副本;仅追加的历史记录。 5. **统一的 API 契约** — 所有路由共用一个 envelope。 6. **边界验证** — 所有外部输入均使用 Zod。 7. **fail-closed 安全性** — 无密钥,应用不启动;所有操作都需要 session。 8. **Token 化与可访问的 UI** — 0 硬编码颜色,符合 WCAG AA。 9. **RED-first 测试 + 门禁** — 只有门禁通过才能合并。 10. **动态文档** — 每个区域都有自己的 `CLAUDE.md`,并在同一个 PR 中更新。 *[@DevysonSilva](https://github.com/DevysonSilva) 的个人项目,使用 spec-kit + Claude 构建。 Kiroku (記録, "记录")。*
标签:MongoDB, Prisma, React, Syscalls, TypeScript, 个人记录, 内容追踪, 安全插件, 自动化攻击