Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8415291772 | |||
| f8386d7b02 | |||
| 5fe2e2c75c | |||
| 3e1789e124 | |||
| 3efb2182b2 | |||
| 6953f48344 |
@@ -0,0 +1,21 @@
|
|||||||
|
# role-user Agent Skills
|
||||||
|
|
||||||
|
本目录存放 `role-user` 的项目级 Agent skill。规则参考 SeaCloud 项目的 agent skill 组织方式,并按当前员工端 Next.js、TypeScript、移动端工作台场景保留最小必要规范。
|
||||||
|
|
||||||
|
## 使用入口
|
||||||
|
|
||||||
|
1. 进入仓库后先读 `AGENTS.md` 和 `RTK.md`。
|
||||||
|
2. 创建或修改代码文件时,使用 `header-comment-sync` 保持中文文件头、导出声明和复杂逻辑注释同步。
|
||||||
|
3. 提交或推送代码时,使用 `chinese-commit-message` 生成英文 type 前缀加中文摘要的 commit message。
|
||||||
|
4. 所有 skill 的触达文件补齐规则只处理本次任务相关文件,不要求为了单次任务全仓扫描。
|
||||||
|
|
||||||
|
## 当前项目事实
|
||||||
|
|
||||||
|
- 应用类型:员工端 C 端移动优先工作台。
|
||||||
|
- 技术栈:Next.js App Router、React、TypeScript。
|
||||||
|
- 关键边界:BFF Route Handlers 负责会话与后端转发,前端不持久化 JWT 或明文密码。
|
||||||
|
|
||||||
|
## Skill 索引
|
||||||
|
|
||||||
|
- `header-comment-sync`:中文文件头、导出声明、复杂逻辑和风险边界注释。
|
||||||
|
- `chinese-commit-message`:中文提交信息格式。
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
name: chinese-commit-message
|
||||||
|
description: 在本仓库执行 git commit、整理提交说明或准备推送时使用,保持提交信息使用英文类型前缀加中文描述。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 中文提交信息
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 用户要求提交、推送或整理 commit message。
|
||||||
|
- 你准备执行 `git commit`。
|
||||||
|
- 需要总结当前 diff 的提交说明。
|
||||||
|
|
||||||
|
## 核心要求
|
||||||
|
|
||||||
|
1. 提交信息必须使用英文 type 加中文摘要,例如 `feat: 补齐员工端 agent skill 规范`。
|
||||||
|
2. 常用 type 优先使用 `feat`、`fix`、`refactor`、`docs`、`chore`。
|
||||||
|
3. 不强制 scope;只有模块边界非常清楚时才使用 `feat(auth): ...`。
|
||||||
|
4. 标题部分使用简洁中文,直接说明改动,不写“修改一下”“更新代码”这类空泛描述。
|
||||||
|
5. 非 trivial 改动建议补中文正文,用扁平 bullet 按文件或内容块说明关键动作。
|
||||||
|
6. 正文与标题之间空一行;正文每条 bullet 对应一个独立文件或明确内容块。
|
||||||
|
7. 如果用户指定提交信息,优先尊重用户原意,只做必要格式整理。
|
||||||
|
|
||||||
|
## 触达文件补齐
|
||||||
|
|
||||||
|
- 不要求为了提交信息单独全仓扫描。
|
||||||
|
- 提交前如果 diff 中的触达文件明显违反对应 skill 的触达补齐要求,应先修正当前相关链路,再整理 commit message。
|
||||||
|
- commit 正文应概括本次触达补齐,例如“补齐触达文件注释”“同步 README 目录说明”。
|
||||||
|
|
||||||
|
## 推荐结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat: 补齐员工端 agent skill 规范
|
||||||
|
|
||||||
|
- .agents/README.md: 新增项目级 skill 索引和使用入口
|
||||||
|
- .agents/skills: 补充中文提交与注释同步规则
|
||||||
|
- AGENTS.md: 增加本地 skill 入口
|
||||||
|
```
|
||||||
|
|
||||||
|
## 不推荐写法
|
||||||
|
|
||||||
|
- `新增规则`
|
||||||
|
- `feat: add skills`
|
||||||
|
- `fix bug`
|
||||||
|
- `update`
|
||||||
|
- 复杂改动只有标题没有正文。
|
||||||
|
- 正文写成长段流水账或嵌套列表。
|
||||||
|
|
||||||
|
## 落地检查
|
||||||
|
|
||||||
|
- type 是否合理。
|
||||||
|
- 中文摘要是否覆盖主改动。
|
||||||
|
- 是否需要正文。
|
||||||
|
- 正文是否按文件或内容块归纳。
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
name: header-comment-sync
|
||||||
|
description: 在本仓库创建或修改 ts、tsx、js、jsx、mjs、cjs、vue、astro 文件时使用,保持中文文件头、导出声明、复杂逻辑和风险边界注释准确。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 注释规范与同步
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
让下一次进入文件的维护者能快速理解当前职责、关键约束和风险边界。注释解释“为什么”和“边界”,不复述代码表面行为。
|
||||||
|
|
||||||
|
## 适用场景
|
||||||
|
|
||||||
|
- 新增或修改页面、组件、Hook、store、service、utils、类型、配置或脚本文件。
|
||||||
|
- 修改 BFF Route Handler、鉴权、Cookie、权限、后端协议转换、缓存或错误兜底逻辑。
|
||||||
|
- 发现旧注释与当前代码行为不一致。
|
||||||
|
|
||||||
|
## 核心原则
|
||||||
|
|
||||||
|
- 注释使用中文,描述当前事实。
|
||||||
|
- 简单局部变量不强行注释。
|
||||||
|
- 文件头说明文件当前职责,1 到 2 行即可。
|
||||||
|
- 导出的函数、组件、Hook、类型、配置对象、service method 应有用途说明。
|
||||||
|
- 复杂兼容逻辑、后端协议、竞态锁、缓存、权限映射和会话安全边界需要短注释。
|
||||||
|
- TODO/FIXME 必须说明触发条件、剩余动作和可删除条件。
|
||||||
|
|
||||||
|
## 文件头规则
|
||||||
|
|
||||||
|
- 每个适用文件都要有准确文件头。
|
||||||
|
- 如果文件必须以 `"use client"` 或 `"use server"` 开头,文件头注释放在指令之后、导入之前。
|
||||||
|
- Vue 文件不为了补头注释重排模板结构;在 `<script>` 或 `<script setup>` 顶部补当前职责说明。
|
||||||
|
- 文件头不要写“本文件用于...”这类空话,直接说明业务角色。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工端任务详情页,负责加载任务、发起流转动作并展示备注时间线。
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
## JSDoc 与局部注释
|
||||||
|
|
||||||
|
- 导出的函数、类、组件、Hook、类型、常量和配置对象优先使用 JSDoc。
|
||||||
|
- 非导出但复杂的解析、格式化、请求构造、状态派生、回调工厂也要补。
|
||||||
|
- 只在局部逻辑确实有约束时使用行内注释,例如竞态锁、兼容字段、后端协议和临时迁移。
|
||||||
|
- 不要在每一行、每个 JSX 片段、每个短生命周期变量上堆注释。
|
||||||
|
|
||||||
|
## 触达文件补齐
|
||||||
|
|
||||||
|
- 不要求为了注释规范单独全仓扫描。
|
||||||
|
- 只要本次任务修改了适用文件,就顺手补齐明显缺失或过时的文件头、导出声明、共享类型、复杂回调和协议注释。
|
||||||
|
- 大文件可按触达区域优先,但同文件内裸露的顶层导出和共享类型应一起补。
|
||||||
|
- 如果一次补齐整个大文件会明显超出需求范围,至少补齐当前需求链路和顶层声明,并在交付说明里说明剩余范围。
|
||||||
|
|
||||||
|
## 不推荐的写法
|
||||||
|
|
||||||
|
- 注释只写“处理数据”“点击事件”这种无信息内容。
|
||||||
|
- 注释描述旧方案,和当前代码矛盾。
|
||||||
|
- 为每个 JSX 片段、简单赋值、短生命周期变量写注释。
|
||||||
|
- 用英文口号、emoji 或情绪化标记替代项目内中文说明。
|
||||||
|
|
||||||
|
## 落地检查
|
||||||
|
|
||||||
|
- 修改后的文件头是否准确。
|
||||||
|
- 新增/修改的导出声明是否有必要说明。
|
||||||
|
- 复杂逻辑是否解释了约束而不是复述代码。
|
||||||
|
- 旧注释是否仍然可信。
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3501/api
|
||||||
|
ROLE_USER_SESSION_COOKIE=role_user_session_develop
|
||||||
|
APP_ENV=develop
|
||||||
|
APP_ENV_LABEL=测试环境
|
||||||
|
PORT=3211
|
||||||
|
HOSTNAME=0.0.0.0
|
||||||
+5
-1
@@ -1,2 +1,6 @@
|
|||||||
ACCESS_MANAGE_API_BASE_URL=http://localhost:3500/api
|
ACCESS_MANAGE_API_BASE_URL=http://localhost:3500/api
|
||||||
ROLE_USER_SESSION_COOKIE=role_user_session
|
ROLE_USER_SESSION_COOKIE=role_user_session_local
|
||||||
|
APP_ENV=local
|
||||||
|
APP_ENV_LABEL=本地环境
|
||||||
|
PORT=3210
|
||||||
|
HOSTNAME=0.0.0.0
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3500/api
|
||||||
|
ROLE_USER_SESSION_COOKIE=role_user_session
|
||||||
|
APP_ENV=production
|
||||||
|
APP_ENV_LABEL=生产环境
|
||||||
|
PORT=3210
|
||||||
|
HOSTNAME=0.0.0.0
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3501/api
|
||||||
|
ROLE_USER_SESSION_COOKIE=role_user_session_develop
|
||||||
|
APP_ENV=develop
|
||||||
|
APP_ENV_LABEL=测试环境
|
||||||
|
PORT=3211
|
||||||
|
HOSTNAME=0.0.0.0
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
@RTK.md
|
||||||
|
|
||||||
|
# role-user Agent 入口
|
||||||
|
|
||||||
|
## 必用 Skill
|
||||||
|
|
||||||
|
- 创建或修改 `ts`、`tsx`、`js`、`jsx`、`mjs`、`cjs`、`vue`、`astro` 文件时,使用 `./.agents/skills/header-comment-sync/SKILL.md`。
|
||||||
|
- 执行 `git commit`、整理提交说明或准备推送时,使用 `./.agents/skills/chinese-commit-message/SKILL.md`。
|
||||||
|
|
||||||
|
## 本地规则
|
||||||
|
|
||||||
|
- 先读 `RTK.md`,再按任务读取 `.agents/README.md` 中匹配的 skill。
|
||||||
|
- skill 的触达文件补齐只处理本次修改相关文件,不为单次任务全仓扫描。
|
||||||
@@ -26,11 +26,23 @@ pnpm dev
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
ACCESS_MANAGE_API_BASE_URL=http://localhost:3500/api
|
ACCESS_MANAGE_API_BASE_URL=http://localhost:3500/api
|
||||||
ROLE_USER_SESSION_COOKIE=role_user_session
|
ROLE_USER_SESSION_COOKIE=role_user_session_local
|
||||||
|
APP_ENV=local
|
||||||
|
APP_ENV_LABEL=本地环境
|
||||||
|
PORT=3210
|
||||||
|
HOSTNAME=0.0.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
`ACCESS_MANAGE_API_BASE_URL` 指向 `access-manage` 服务端 API 根路径。员工登录会调用后端 `POST /api/auth/employee/login`,登录成功后只把 JWT 写入 Next.js 服务端 HttpOnly Cookie,不写入 `localStorage`。
|
`ACCESS_MANAGE_API_BASE_URL` 指向 `access-manage` 服务端 API 根路径。员工登录会调用后端 `POST /api/auth/employee/login`,登录成功后只把 JWT 写入 Next.js 服务端 HttpOnly Cookie,不写入 `localStorage`。
|
||||||
|
|
||||||
|
环境标识按 `APP_ENV` 区分:
|
||||||
|
|
||||||
|
- `local`: 本地环境,默认使用 `.env.example` 复制出的 `.env.local`。
|
||||||
|
- `develop`: 测试环境,参考 `.env.develop.example`;`.env.test.example` 保留为兼容入口。
|
||||||
|
- `production`: 生产环境,参考 `.env.production.example`。
|
||||||
|
|
||||||
|
`APP_ENV_LABEL` 可覆盖页面右上角显示文案;未配置时会按 `APP_ENV` 自动显示“本地环境”“测试环境”或“生产环境”。Cookie 只在 `APP_ENV=production` 时设置 `Secure`,避免测试环境 HTTP 访问时登录后被浏览器丢弃 Cookie。
|
||||||
|
|
||||||
## 可用命令
|
## 可用命令
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -38,6 +50,10 @@ pnpm dev
|
|||||||
pnpm typecheck
|
pnpm typecheck
|
||||||
pnpm lint
|
pnpm lint
|
||||||
pnpm build
|
pnpm build
|
||||||
|
pnpm build:develop
|
||||||
|
pnpm build:prod
|
||||||
|
pnpm start:develop
|
||||||
|
pnpm start:prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## 当前实现范围
|
## 当前实现范围
|
||||||
@@ -83,8 +99,12 @@ pnpm build
|
|||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
|
- `.agents/README.md`: 本项目 Agent skill 索引和使用入口。
|
||||||
|
- `.agents/skills/chinese-commit-message/SKILL.md`: 中文提交信息规范。
|
||||||
|
- `.agents/skills/header-comment-sync/SKILL.md`: 中文文件头和注释同步规范。
|
||||||
- `docs/C_EMPLOYEE_APP_REQUIREMENTS.md`: C 端员工工作台需求文档。
|
- `docs/C_EMPLOYEE_APP_REQUIREMENTS.md`: C 端员工工作台需求文档。
|
||||||
- `docs/FULLSTACK_BACKEND_GAP_ANALYSIS.md`: C 端员工工作台三端缺口与改动范围分析。
|
- `docs/FULLSTACK_BACKEND_GAP_ANALYSIS.md`: C 端员工工作台三端缺口与改动范围分析。
|
||||||
|
- `AGENTS.md`: Codex/Agent 入口规则,转到 `RTK.md` 并登记本地 skill。
|
||||||
- `RTK.md`: 本项目 Codex/Agent 协作规则。
|
- `RTK.md`: 本项目 Codex/Agent 协作规则。
|
||||||
|
|
||||||
## 关联项目
|
## 关联项目
|
||||||
|
|||||||
+6
-1
@@ -3,9 +3,14 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3210",
|
"dev": "APP_ENV=local APP_ENV_LABEL=本地环境 ACCESS_MANAGE_API_BASE_URL=http://localhost:3500/api ROLE_USER_SESSION_COOKIE=role_user_session_local next dev -p 3210",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
"build:develop": "APP_ENV=develop APP_ENV_LABEL=测试环境 ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3501/api ROLE_USER_SESSION_COOKIE=role_user_session_develop next build",
|
||||||
|
"build:test": "pnpm build:develop",
|
||||||
|
"build:prod": "APP_ENV=production APP_ENV_LABEL=生产环境 ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3500/api ROLE_USER_SESSION_COOKIE=role_user_session next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
|
"start:develop": "APP_ENV=develop APP_ENV_LABEL=测试环境 ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3501/api ROLE_USER_SESSION_COOKIE=role_user_session_develop next start -p 3211",
|
||||||
|
"start:prod": "APP_ENV=production APP_ENV_LABEL=生产环境 ACCESS_MANAGE_API_BASE_URL=http://127.0.0.1:3500/api ROLE_USER_SESSION_COOKIE=role_user_session next start -p 3210",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
"typecheck": "tsc --noEmit --incremental false"
|
"typecheck": "tsc --noEmit --incremental false"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1029,6 +1029,22 @@ textarea:focus-visible {
|
|||||||
color: var(--accent-ink);
|
color: var(--accent-ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.environment-badge {
|
||||||
|
background: rgba(20, 20, 24, 0.86);
|
||||||
|
border-radius: 999px;
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.16);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 750;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 8px 10px;
|
||||||
|
position: fixed;
|
||||||
|
right: 12px;
|
||||||
|
top: 12px;
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
|
||||||
.skeleton {
|
.skeleton {
|
||||||
animation: pulse 1.2s ease-in-out infinite;
|
animation: pulse 1.2s ease-in-out infinite;
|
||||||
background: linear-gradient(90deg, #ececef, #fafafa, #ececef);
|
background: linear-gradient(90deg, #ececef, #fafafa, #ececef);
|
||||||
|
|||||||
+13
-2
@@ -1,5 +1,7 @@
|
|||||||
import type { Metadata, Viewport } from "next";
|
import type { Metadata, Viewport } from "next";
|
||||||
|
import { connection } from "next/server";
|
||||||
|
|
||||||
|
import { getAppEnvLabel } from "@/lib/environment";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -24,10 +26,19 @@ export const viewport: Viewport = {
|
|||||||
themeColor: "#ffffff"
|
themeColor: "#ffffff"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
export default async function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||||
|
await connection();
|
||||||
|
|
||||||
|
const environmentLabel = getAppEnvLabel();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<body>{children}</body>
|
<body>
|
||||||
|
<div className="environment-badge" aria-label={`当前环境:${environmentLabel}`}>
|
||||||
|
{environmentLabel}
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import "server-only";
|
||||||
|
|
||||||
|
export type AppEnv = "local" | "develop" | "production";
|
||||||
|
|
||||||
|
export function getAppEnv(): AppEnv {
|
||||||
|
const appEnv = process.env.APP_ENV;
|
||||||
|
|
||||||
|
if (appEnv === "production") {
|
||||||
|
return "production";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appEnv === "develop" || appEnv === "test") {
|
||||||
|
return "develop";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appEnv === "local") {
|
||||||
|
return "local";
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.env.NODE_ENV === "production" ? "production" : "local";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAppEnvLabel() {
|
||||||
|
if (process.env.APP_ENV_LABEL) {
|
||||||
|
return process.env.APP_ENV_LABEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labels: Record<AppEnv, string> = {
|
||||||
|
local: "本地环境",
|
||||||
|
develop: "测试环境",
|
||||||
|
production: "生产环境"
|
||||||
|
};
|
||||||
|
|
||||||
|
return labels[getAppEnv()];
|
||||||
|
}
|
||||||
+3
-1
@@ -2,6 +2,8 @@ import "server-only";
|
|||||||
|
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
|
|
||||||
|
import { getAppEnv } from "@/lib/environment";
|
||||||
|
|
||||||
const DEFAULT_COOKIE_NAME = "role_user_session";
|
const DEFAULT_COOKIE_NAME = "role_user_session";
|
||||||
|
|
||||||
export function getSessionCookieName() {
|
export function getSessionCookieName() {
|
||||||
@@ -17,7 +19,7 @@ export async function setSessionToken(token: string) {
|
|||||||
|
|
||||||
cookieStore.set(getSessionCookieName(), token, {
|
cookieStore.set(getSessionCookieName(), token, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === "production",
|
secure: getAppEnv() === "production",
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 60 * 60 * 8
|
maxAge: 60 * 60 * 8
|
||||||
|
|||||||
Reference in New Issue
Block a user