Compare commits
7 Commits
v0.1.0
..
a8d48ad745
| Author | SHA1 | Date | |
|---|---|---|---|
| a8d48ad745 | |||
| 93bc10a795 | |||
| d3a79ee028 | |||
| e228ec3973 | |||
| 9d5a92a4a2 | |||
| 3c75ea4775 | |||
| 925acb8a40 |
@@ -1,21 +0,0 @@
|
|||||||
# 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`:中文提交信息格式。
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
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 是否合理。
|
|
||||||
- 中文摘要是否覆盖主改动。
|
|
||||||
- 是否需要正文。
|
|
||||||
- 正文是否按文件或内容块归纳。
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
---
|
|
||||||
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 或情绪化标记替代项目内中文说明。
|
|
||||||
|
|
||||||
## 落地检查
|
|
||||||
|
|
||||||
- 修改后的文件头是否准确。
|
|
||||||
- 新增/修改的导出声明是否有必要说明。
|
|
||||||
- 复杂逻辑是否解释了约束而不是复述代码。
|
|
||||||
- 旧注释是否仍然可信。
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
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
|
|
||||||
+1
-5
@@ -1,6 +1,2 @@
|
|||||||
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_local
|
ROLE_USER_SESSION_COOKIE=role_user_session
|
||||||
APP_ENV=local
|
|
||||||
APP_ENV_LABEL=本地环境
|
|
||||||
PORT=3210
|
|
||||||
HOSTNAME=0.0.0.0
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
@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,23 +26,11 @@ 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_local
|
ROLE_USER_SESSION_COOKIE=role_user_session
|
||||||
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
|
||||||
@@ -50,10 +38,6 @@ 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 当前实现范围
|
## 当前实现范围
|
||||||
@@ -99,12 +83,8 @@ pnpm start:prod
|
|||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
|
||||||
- `.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 协作规则。
|
||||||
|
|
||||||
## 关联项目
|
## 关联项目
|
||||||
|
|||||||
+1
-6
@@ -3,14 +3,9 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"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",
|
"dev": "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,22 +1029,6 @@ 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);
|
||||||
|
|||||||
+2
-13
@@ -1,7 +1,5 @@
|
|||||||
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 = {
|
||||||
@@ -26,19 +24,10 @@ export const viewport: Viewport = {
|
|||||||
themeColor: "#ffffff"
|
themeColor: "#ffffff"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||||
await connection();
|
|
||||||
|
|
||||||
const environmentLabel = getAppEnvLabel();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<body>
|
<body>{children}</body>
|
||||||
<div className="environment-badge" aria-label={`当前环境:${environmentLabel}`}>
|
|
||||||
{environmentLabel}
|
|
||||||
</div>
|
|
||||||
{children}
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
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()];
|
|
||||||
}
|
|
||||||
+1
-3
@@ -2,8 +2,6 @@ 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() {
|
||||||
@@ -19,7 +17,7 @@ export async function setSessionToken(token: string) {
|
|||||||
|
|
||||||
cookieStore.set(getSessionCookieName(), token, {
|
cookieStore.set(getSessionCookieName(), token, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: getAppEnv() === "production",
|
secure: process.env.NODE_ENV === "production",
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 60 * 60 * 8
|
maxAge: 60 * 60 * 8
|
||||||
|
|||||||
Reference in New Issue
Block a user