diff --git a/.gitignore b/.gitignore index 519bbb0..8ec0f7c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,55 @@ -# 依赖 +# ============================================================ +# Monolith .gitignore — 什么该推送,什么不该推送 +# ============================================================ + +# ────────────────────── 依赖目录(不推送)────────────────────── node_modules/ -.next/ -# 构建产出 +# ────────────────────── 构建产出(不推送)────────────────────── dist/ .wrangler/ -.turbo/ -# 环境变量 +# ────────────────────── 环境变量与密钥(绝不推送)────────────────── +# 所有 .env 文件都可能含密钥,禁止推送 .env .env.local -.env.* +.env.*.local +.env.production !.env.example + +# Wrangler 本地密钥(含 ADMIN_PASSWORD / JWT_SECRET 等) .dev.vars -# 系统文件 +# ────────────────────── 系统与编辑器临时文件(不推送)────────────── .DS_Store +Thumbs.db *.swp *.swo +*~ -# IDE +# IDE 配置 .idea/ +.vscode/ *.code-workspace -# Wrangler 本地数据 -.wrangler/ - -# AI 助手记忆库(含私人配置、密码等,禁止推送) +# ────────────────────── AI 工具私有数据(绝不推送)────────────────── +# 记忆库含密码、PAT、私人偏好等敏感信息 .agents/ + +# 编辑器/AI 全局配置(Antigravity、Gemini、OpenCode 等) GEMINI.md +# ────────────────────── 日志与调试产物(不推送)────────────────── +*.log +npm-debug.log* + +# ────────────────────── 必须推送的重要文件 ────────────────────── +# 以下文件虽然常被误加 gitignore,但必须跟踪: +# ✅ package-lock.json — 锁定依赖版本,CI 的 npm ci 依赖它 +# ✅ client/functions/ — Pages Functions 反向代理,漏掉则 /api/* 回退为首页 HTML +# ✅ scripts/ — 部署脚本 (deploy-cloudflare.mjs) +# ✅ AGENTS.md — OpenCode 项目规则(不含密钥) +# ✅ opencode.json — OpenCode 项目配置(含 MCP 远程服务,不含本地密钥) +# ✅ .github/ — CI/CD workflows、Issue/PR 模板、分支保护 +# ✅ SECURITY.md — 安全政策 +# ✅ PRIVACY.md — 隐私政策 \ No newline at end of file diff --git a/.kilo/package-lock.json b/.kilo/package-lock.json deleted file mode 100644 index f78a498..0000000 --- a/.kilo/package-lock.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "name": ".kilo", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@kilocode/plugin": "7.2.14" - } - }, - "node_modules/@kilocode/plugin": { - "version": "7.2.14", - "resolved": "https://registry.npmjs.org/@kilocode/plugin/-/plugin-7.2.14.tgz", - "integrity": "sha512-mS+WA9HZIBH2qQ9ARA+v0q4MdQTSdfOvKbe4AOSkjP+P5hVA70OM/UVM9DVcvmjSOxU+wuUxmOy+j/EQIrgFmw==", - "license": "MIT", - "dependencies": { - "@kilocode/sdk": "7.2.14", - "zod": "4.1.8" - }, - "peerDependencies": { - "@opentui/core": ">=0.1.97", - "@opentui/solid": ">=0.1.97" - }, - "peerDependenciesMeta": { - "@opentui/core": { - "optional": true - }, - "@opentui/solid": { - "optional": true - } - } - }, - "node_modules/@kilocode/sdk": { - "version": "7.2.14", - "resolved": "https://registry.npmjs.org/@kilocode/sdk/-/sdk-7.2.14.tgz", - "integrity": "sha512-Naz83lFrsbavuDp6UwxRuglOaSNvRBsZfcRNvb7RpWYAwbuJP0dBdhpXj6uO3ta5qxeQ2JzxKNC9Ffz+LCLLDg==", - "license": "MIT", - "dependencies": { - "cross-spawn": "7.0.6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/zod": { - "version": "4.1.8", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/.playwright-mcp/console-2026-04-19T04-35-34-885Z.log b/.playwright-mcp/console-2026-04-19T04-35-34-885Z.log deleted file mode 100644 index 114d3cb..0000000 --- a/.playwright-mcp/console-2026-04-19T04-35-34-885Z.log +++ /dev/null @@ -1,2 +0,0 @@ -[ 8384ms] [VERBOSE] [DOM] Input elements should have autocomplete attributes (suggested: "new-password"): (More info: https://goo.gl/9p2vKq) %o @ https://910f51c7.monolith-client.pages.dev/admin/login:0 -[ 26957ms] [LOG] App ready to work offline @ https://910f51c7.monolith-client.pages.dev/assets/index-CMx-6i-H.js:199 diff --git a/.playwright-mcp/page-2026-04-19T04-35-40-096Z.yml b/.playwright-mcp/page-2026-04-19T04-35-40-096Z.yml deleted file mode 100644 index b6cfb54..0000000 --- a/.playwright-mcp/page-2026-04-19T04-35-40-096Z.yml +++ /dev/null @@ -1 +0,0 @@ -- paragraph [ref=e6]: 验证身份中... \ No newline at end of file diff --git a/.playwright-mcp/page-2026-04-19T04-35-49-532Z.yml b/.playwright-mcp/page-2026-04-19T04-35-49-532Z.yml deleted file mode 100644 index d5d5e7b..0000000 --- a/.playwright-mcp/page-2026-04-19T04-35-49-532Z.yml +++ /dev/null @@ -1,8 +0,0 @@ -- main [ref=e7]: - - generic [ref=e10]: - - generic [ref=e11]: - - heading "管理后台" [level=1] [ref=e13] - - paragraph [ref=e14]: 输入密码以进入管理界面 - - generic [ref=e15]: - - textbox "管理密码" [active] [ref=e16] - - button "登录" [disabled] [ref=e17] \ No newline at end of file diff --git a/.playwright-mcp/page-2026-04-19T04-35-58-544Z.png b/.playwright-mcp/page-2026-04-19T04-35-58-544Z.png deleted file mode 100644 index 56d636b..0000000 Binary files a/.playwright-mcp/page-2026-04-19T04-35-58-544Z.png and /dev/null differ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d768407 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,63 @@ +# Monolith 项目规则 + +## 项目概览 +Monolith 是基于 Cloudflare 边缘计算的全栈博客系统。 +- 前端:Vite 6 + React 19 + Tailwind CSS v4 + shadcn/ui + wouter +- 后端:Hono Workers + Drizzle ORM +- 代理层:Pages Functions(反向代理 /api/* /cdn/* /rss.xml) +- 存储:D1 (SQLite) + R2 (对象存储),支持 Turso/PostgreSQL/S3 切换 +- 主题:OKLCH 色彩空间双主题系统(暗色 Slate & Cyan / 亮色模式) + +## 架构要点 +- 存储层采用适配器模式:路由只依赖 `IDatabase` / `IObjectStorage` 接口,通过 `DB_PROVIDER` / `STORAGE_PROVIDER` 环境变量切换适配器 +- Pages Functions 代理层拦截 `/api/*`、`/cdn/*`、`/rss.xml`,转发到 Workers +- Pages Functions 的 `tsconfig.json` 独立引入 `@cloudflare/workers-types`,避免与主项目 DOM 类型冲突 +- DOMPurify 净化 Markdown 渲染输出,白名单允许 iframe/video 嵌入 +- `searchPosts()` 只搜索 `title + excerpt`,不扫描 `content` 大字段 + +## 工作区路径 +- 项目根目录:`/home/easy/001/Monolith` +- 客户端:`/home/easy/001/Monolith/client` +- 服务端:`/home/easy/001/Monolith/server` + +## 分支管理 +- 生产分支:`main`(Cloudflare Pages 自动部署绑定) +- 开发分支:`dev` +- 工作流:dev 开发 → commit → push → PR → squash merge 到 main → 部署 +- 严禁直接向 main 推送 + +## 常用命令 +- `npm run dev` — 同时启动前后端(client :5173, server :8787) +- `npm run dev:client` / `npm run dev:server` — 单独启动 +- `npm run build` — 构建前端 +- `npm run deploy:cloudflare` — 一键部署(迁移 + Workers + Pages) +- `npm run db:migrate:local` / `db:migrate:remote` — 数据库迁移 +- Node.js 需要 `source $HOME/.nvm/nvm.sh` 后才可用 + +## 部署铁律 +- 使用 `npm run deploy:cloudflare` 一键部署,禁止手动 `wrangler pages deploy` +- 必须从 `client/` 目录部署 `dist`,否则 Pages Functions 会被遗漏 +- `package-lock.json` 绝不能放入 `.gitignore` +- CI "Sync Worker secrets" 步骤通过 `wrangler secret put` 注入 ADMIN_PASSWORD / JWT_SECRET + +## 踩坑记录(项目特有) +- D1 迁移标记不同步时需手动 `INSERT INTO d1_migrations` +- Cloudflare CDN 有短暂缓存,验证时用部署唯一 URL +- 本地 `client/functions/api/` 目录的 tsconfig 独立,不与主项目混用 +- Hono v4 `verify()` 需要 3 个参数:`verify(token, secret, "HS256")` + +## 记忆库 +项目记忆库路径:`.agents/memory_bank/` +- `README.md` — 索引入口 +- `monolith_architecture.md` — 完整架构手册 +- `monolith_roadmap.md` — 功能路线图 +- `monolith_v1_status.md` — V1 状态报告 +- `system_config.md` — 系统配置与凭据 +- `ui_design_parameters.md` — UI 排版设计规范 +- `typecho_dev_guide.md` — Typecho 开发指南(已弃用项目) + +## CI 与安全 +- 仓库:`https://github.com/one-ea/Monolith` +- GitHub PAT:已配置在 system_config.md +- 后台密码:`monolith2026` +- 分支保护:main 需要 1 人审批 + 线性历史 + 状态检查 \ No newline at end of file diff --git a/client/src/components/admin-layout.tsx b/client/src/components/admin-layout.tsx index 1338ad7..09e6c57 100644 --- a/client/src/components/admin-layout.tsx +++ b/client/src/components/admin-layout.tsx @@ -25,13 +25,9 @@ export function AdminLayout({ children }: AdminLayoutProps) { useEffect(() => { if (!mobileMenuOpen) return; - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === "Escape") { - setMobileMenuOpen(false); - } + if (event.key === "Escape") setMobileMenuOpen(false); }; - window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [mobileMenuOpen]); @@ -66,42 +62,65 @@ export function AdminLayout({ children }: AdminLayoutProps) { }, ]; + const SidebarFooter = () => ( +
+
+ 主题 + +
+ + + 查看站点 + + +
+ ); + const SidebarContent = () => ( -
- {/* Brand */} -
- setMobileMenuOpen(false)}> -
+
+
+ setMobileMenuOpen(false)}> +
M
- Monolith + Monolith
- {/* Navigation */} -
); return ( -
- {/* Desktop Sidebar */} -