Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 67 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@

```Markdown
# 标题1
## 标题2
## 标题2
```

每点击一行,左边都有加号按钮,可以快捷添加你要的内容块

![image.png](https://pub-fa1987abe8794da6ba45cdf9284954b3.r2.dev/users/7/contributing-guide/1765632611285-image.png)
Expand Down Expand Up @@ -71,7 +71,6 @@

点击右上角的commit changes


4. 点击 `Commit changes`,若是第一次投稿,GitHub 会提示先 Fork 仓库;按提示操作一次即可
![fork](./public//git_assets/need_fork.png)

Expand Down Expand Up @@ -182,31 +181,34 @@ git push origin doc_raven
**解决方案**:

1. **确保使用正确的 pnpm 版本**:

```bash
# 检查当前版本
pnpm --version

# 应该显示: 10.20.0
# 如果不是,请使用以下命令之一:

# 方法 1: 使用 corepack(推荐)
corepack enable
corepack prepare pnpm@10.20.0 --activate

# 方法 2: 全局安装
npm install -g pnpm@10.20.0
```

2. **验证版本一致性**:

```bash
pnpm check:pnpm-version
```

3. **如果 lockfile 已经被错误修改**:

```bash
# 丢弃 lockfile 的修改
git checkout pnpm-lock.yaml

# 确认使用正确的 pnpm 版本后重新安装
pnpm install
```
Expand All @@ -217,10 +219,12 @@ git push origin doc_raven
#### 问题:CI 检查失败,提示 lockfile 不一致

这通常意味着:

1. 你本地使用的 pnpm 版本与项目要求的不一致
2. lockfile 被错误修改或损坏

**解决方案**:

```bash
# 1. 确认并切换到正确的 pnpm 版本
corepack enable
Expand All @@ -239,12 +243,14 @@ git status
#### 问题:为什么要使用 corepack 而不是全局安装?

**Corepack 的优势**:

- 自动读取 `package.json` 的 `packageManager` 字段
- 每个项目可以使用不同的 pnpm 版本而不冲突
- 新贡献者克隆项目后自动使用正确的版本
- 减少版本不匹配导致的问题

**如何为团队启用 corepack**:

```bash
# 一次性设置,之后所有项目都会受益
corepack enable
Expand Down Expand Up @@ -305,13 +311,13 @@ pnpm check:pnpm-version
#### ⚠️ 为什么版本一致性很重要?

不同版本的 pnpm 在序列化 `pnpm-lock.yaml` 时可能使用不同的格式(如单引号 vs 双引号),导致:

- PR 中产生大量无意义的 diff
- 增加代码审查负担
- 可能导致 CI 检查失败

我们的 CI 工作流会自动检查版本一致性,如果检测到版本不匹配会导致构建失败。


### 3. 本地开发

运行开发服务器:
Expand Down Expand Up @@ -343,6 +349,59 @@ pnpm postinstall # 同步必要的 Husky/Fumadocs 配置

---

## 🔐 基础设施访问

项目除了 GitHub 仓库,还有几个对外/对内服务。所有登录都走**同一个 GitHub 账号**,不再有每处独立密码。

### 服务一览

| 用途 | URL | 谁能进 | 登录方式 |
| ------------ | ----------------------------------------------- | --------------------------------------- | --------------------------------------- |
| 主站 | `https://involutionhell.com` | 所有登录用户 | GitHub OAuth |
| 后端 API | `https://api.involutionhell.com` | — (内部调用) | sa-token (cookie/header) |
| **密钥管理** | `https://secrets.involutionhell.com` | **所有登录协作者**,按 project 权限查看 | GitHub OAuth(复用主站 App) |
| 数据库管理 | `https://api.involutionhell.com/admin/pgadmin/` | **仅 admin** | 主站 cookie 自动通过 Caddy forward_auth |
| 网站分析 | `https://umami.involutionhell.com` | **仅 admin** | 本地 umami 账号 |
Comment on lines +358 to +364
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “后端 API” row says auth is sa-token (cookie/header), but the frontend code actually sends the token under the satoken header and syncs a satoken cookie (see lib/use-auth.tsx). Please clarify the exact header/cookie key names here to avoid misconfiguration when people try to call the API directly.

Suggested change
| 用途 | URL | 谁能进 | 登录方式 |
| ------------ | ----------------------------------------------- | --------------------------------------- | --------------------------------------- |
| 主站 | `https://involutionhell.com` | 所有登录用户 | GitHub OAuth |
| 后端 API | `https://api.involutionhell.com` | — (内部调用) | sa-token (cookie/header) |
| **密钥管理** | `https://secrets.involutionhell.com` | **所有登录协作者**,按 project 权限查看 | GitHub OAuth(复用主站 App) |
| 数据库管理 | `https://api.involutionhell.com/admin/pgadmin/` | **仅 admin** | 主站 cookie 自动通过 Caddy forward_auth |
| 网站分析 | `https://umami.involutionhell.com` | **仅 admin** | 本地 umami 账号 |
| 用途 | URL | 谁能进 | 登录方式 |
| ------------ | ----------------------------------------------- | --------------------------------------- | ---------------------------------------------------------- |
| 主站 | `https://involutionhell.com` | 所有登录用户 | GitHub OAuth |
| 后端 API | `https://api.involutionhell.com` | — (内部调用) | sa-tokenheader: `satoken` / cookie: `satoken` |
| **密钥管理** | `https://secrets.involutionhell.com` | **所有登录协作者**,按 project 权限查看 | GitHub OAuth(复用主站 App) |
| 数据库管理 | `https://api.involutionhell.com/admin/pgadmin/` | **仅 admin** | 主站 cookie 自动通过 Caddy forward_auth |
| 网站分析 | `https://umami.involutionhell.com` | **仅 admin** | 本地 umami 账号 |

Copilot uses AI. Check for mistakes.

### 怎么拿到 admin / 密钥权限

1. **申请 admin 角色**:现有 superadmin 在 `/admin/users` 页面勾选即可授予(产品规则:superadmin 本身不能通过 API 变动)
2. **申请 Infisical 项目访问**:登录 `secrets.involutionhell.com` 后(GitHub OAuth 自动建账号),联系现有 admin 加到对应 project。Infisical 内部按 environment 分 `dev` / `prod` / `shared`
3. **不要自己手动 INSERT `user_accounts` 表挂 admin 角色** —— OAuth 登录按 `github_<id>` 匹配 username,手工 insert 的人类 username 行永远是孤儿,用户登录后会另开一行丢 admin。历史上有人踩过

### `.env` 文件规则

- 本地 dev:
- 后端:`involution-hell-project/backend/.env`(`set -a && . ./.env && set +a` 注入 Spring Boot)
- 前端:`involution-hell-project/frontend/.env`
- 生产:`/home/ubuntu/involution-hell/.env`(**只在部署机**,不在仓库里;CI 不覆盖)
- 两份 .env **故意有差异**(PGHOST / SERVER_PORT / AUTH_URL)—— 不要强行统一,参见 wiki [Changelog 2026-04-17](https://github.com/InvolutionHell/involutionhell/wiki/Changelog-2026-04-17-Self-Hosted-Infra) 的架构说明
- **所有秘密值**将来会迁到 Infisical 单一真源,`.env` 只存极少数 bootstrap 配置。改动期间前后仓两份并存,改值要同步改两处
Comment on lines +374 to +379
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .env paths here don’t match this repository’s layout (this repo has .env.sample at the root and typically uses .env.local for Next.js; there is no frontend/ directory in-repo). Please rewrite this section to describe the env file location(s) for this repo explicitly, and (if needed) separately describe the external backend repo’s .env so contributors don’t create files in non-existent paths.

Suggested change
- 本地 dev:
- 后端:`involution-hell-project/backend/.env``set -a && . ./.env && set +a` 注入 Spring Boot)
- 前端:`involution-hell-project/frontend/.env`
- 生产:`/home/ubuntu/involution-hell/.env`**只在部署机**,不在仓库里;CI 不覆盖)
- 两份 .env **故意有差异**(PGHOST / SERVER_PORT / AUTH_URL)—— 不要强行统一,参见 wiki [Changelog 2026-04-17](https://github.com/InvolutionHell/involutionhell/wiki/Changelog-2026-04-17-Self-Hosted-Infra) 的架构说明
- **所有秘密值**将来会迁到 Infisical 单一真源,`.env` 只存极少数 bootstrap 配置。改动期间前后仓两份并存,改值要同步改两处
- **本仓库(当前仓库)**
- 根目录的 `.env.sample` 是模板;本地开发时按需在**仓库根目录**创建 `.env.local`
- 这个仓库里**没有** `frontend/` 目录,不要创建 `frontend/.env`
- **外部后端仓库(如你同时在本地跑后端)**
- 后端的 `.env`**后端仓库自己的根目录/约定位置**,不在当前仓库内
- 如需注入 Spring Boot,进入后端仓库后再使用该仓库自己的 `.env`(例如 `set -a && . ./.env && set +a`
- **生产环境**`/home/ubuntu/involution-hell/.env`**只在部署机**,不在当前仓库里;CI 不覆盖)
- 不同环境 / 不同仓库的 `.env` **故意有差异**(如 PGHOST / SERVER_PORT / AUTH_URL)—— 不要强行统一,参见 wiki [Changelog 2026-04-17](https://github.com/InvolutionHell/involutionhell/wiki/Changelog-2026-04-17-Self-Hosted-Infra) 的架构说明
- **所有秘密值**将来会迁到 Infisical 单一真源,`.env` 只存极少数 bootstrap 配置。改动期间若前后端仓库同时依赖本地配置,改值时请分别同步到各自仓库

Copilot uses AI. Check for mistakes.

### 开发者自助入口

登录主站后,访问**自己**的个人主页 `/u/<你的 github id>`,在顶部按钮栏能看到:

- **密钥管理 ↗**(本人访问自己主页时可见) → 跳 Infisical
- **管理员界面**(仅 admin 本人访问自己主页时可见) → 跳 `/admin`
- **编辑**(仅本人访问自己主页时可见) → 跳 profile 编辑

三个按钮都走 "只有本人看自己主页时才渲染",路人和其他登录用户在这里看不到。
**但 Infisical 站本身** (`secrets.involutionhell.com`) **对所有登录协作者开放** ——
入口按钮只是 UX 便利,不影响访问权(路人可以直接敲地址栏进入)。

### Spring Boot 后端本地启动

```bash
cd involution-hell-project/backend
set -a && . ./.env && set +a # .env 里有 SERVER_PORT=8081 等
./mvnw spring-boot:run
```

前端 `BACKEND_URL` 指 `http://localhost:8081`,前后一致。
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line hard-codes BACKEND_URL as http://localhost:8081, but the repo’s .env.sample currently documents BACKEND_URL=http://localhost:8080. To prevent local dev confusion, either align the port here with .env.sample or phrase it as “set BACKEND_URL to your backend’s local address (see .env.sample)”.

Suggested change
前端 `BACKEND_URL` `http://localhost:8081`,前后一致
前端 `BACKEND_URL` 请设置为你本地后端的访问地址,具体示例请参见 `.env.sample`,并确保前后一致

Copilot uses AI. Check for mistakes.

---

## 📚 文档规范

所有文档放在 `docs/` 目录。
Expand Down
49 changes: 49 additions & 0 deletions app/u/[username]/DeveloperToolsIfOwner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"use client";

/**
* 个人主页的"开发者选项"入口块。
*
* 和 AdminLinkIfOwnerAdmin 的区别——这里**不限 admin**,只要是主页 owner(当前登录
* 用户 === 这个主页本人)就看得见。理由:
* - 密钥管理 (Infisical) 是每个开发者都要用的,不是管理员专属。
* Infisical 自己按 project / environment 做权限细分,进去后看不到自己没权限的 secrets。
* - 以后其他"个人开发者工具"(比如 CI tokens、个人 API key 管理)也可以挂在这里
*
* 渲染条件:
* 1. 已登录
* 2. 当前登录用户就是这个主页的 owner(路人看不到)
*
* 注意:单独加 Link 而不是走 AdminGuard 风格,因为这是"入口按钮"不是"整页权限",
* 二次校验由目标服务(Infisical)自己做。
*/

import Link from "next/link";
import { useAuth } from "@/lib/use-auth";

interface Props {
ownerGithubId: number | null;
ownerUsername: string;
}

export function DeveloperToolsIfOwner({ ownerGithubId, ownerUsername }: Props) {
const { user, status } = useAuth();
if (status !== "authenticated" || !user) return null;

const isOwner =
(ownerGithubId != null && user.githubId === ownerGithubId) ||
user.username === ownerUsername;
if (!isOwner) return null;

return (
<Link
href="https://secrets.involutionhell.com"
target="_blank"
rel="noopener noreferrer"
className="font-mono text-[11px] uppercase tracking-widest px-2 py-1 border border-[var(--foreground)] text-[var(--foreground)] hover:bg-[var(--foreground)] hover:text-[var(--background)] transition-colors font-bold"
data-umami-event="profile_devtools_secrets_click"
title="Infisical 密钥管理(GitHub OAuth 登录,按 project 权限查看)"
Comment on lines +38 to +44
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

href is hard-coded to the production Infisical domain. Other “open external infra” links in the codebase are configurable via a NEXT_PUBLIC_* env override (e.g. pgAdmin uses NEXT_PUBLIC_PGADMIN_URL), which makes preview deployments / self-host / domain changes possible without code changes. Consider reading the URL from an env var (e.g. NEXT_PUBLIC_INFISICAL_URL) and documenting it in .env.sample.

Copilot uses AI. Check for mistakes.
>
密钥管理 ↗
</Link>
);
}
7 changes: 7 additions & 0 deletions app/u/[username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Footer } from "@/app/components/Footer";
import { ProfileCard } from "./ProfileCard";
import { EditLinkIfOwner } from "./EditLinkIfOwner";
import { AdminLinkIfOwnerAdmin } from "./AdminLinkIfOwnerAdmin";
import { DeveloperToolsIfOwner } from "./DeveloperToolsIfOwner";
import { ActivityHeatmap } from "./ActivityHeatmap";
import { FollowButton } from "./FollowButton";
import { GithubRepos, GithubReposSkeleton } from "./GithubRepos";
Expand Down Expand Up @@ -411,6 +412,12 @@ export default async function UserProfilePage({ params }: Param) {
ownerUsername={user.username}
identifier={username}
/>
{/* 开发者工具入口(所有本人都看得见;权限由目标服务自己管):
目前只有 Infisical 密钥管理,未来可挂 CI token / API key 等 */}
<DeveloperToolsIfOwner
ownerGithubId={user.githubId ?? null}
ownerUsername={user.username}
/>
{/* 管理员自见入口:只有 roles=admin 的本人访问自己主页时才渲染 */}
<AdminLinkIfOwnerAdmin
ownerGithubId={user.githubId ?? null}
Expand Down
Loading