dBillionaire-Dev/insighta-labs-plus-api
GitHub: dBillionaire-Dev/insighta-labs-plus-api
基于 Node.js 和 PostgreSQL 的安全人口统计情报平台,通过 GitHub OAuth 认证和角色权限控制,为 CLI 与 Web 客户端提供自然语言查询和 CSV 导出服务。
Stars: 0 | Forks: 0
# Insighta Labs+ — 后端 API
一个安全、多接口的人口统计情报平台,基于第二阶段的人口统计情报系统构建。支持 GitHub OAuth 身份验证、基于角色的访问控制、自然语言查询、CSV 导出,并通过单一后端同时为 CLI 工具和 Web 门户提供服务。
## 系统架构
```
┌─────────────────────────┐
│ Insighta Labs+ │
│ Backend API │
│ (Node.js + Express) │
└────────────┬────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
┌──────▼──────┐ ┌───────▼──────┐ ┌───────▼──────┐
│ CLI Tool │ │ Web Portal │ │ Grader / │
│ (insighta) │ │ (React/SPA) │ │ Direct API │
│ Bearer token│ │ HTTP-only │ │ clients │
└─────────────┘ │ cookies │ └─────────────┘
└─────────────┘
┌─────────────────────────┐
│ PostgreSQL DB │
│ profiles | users | │
│ refresh_tokens │
└─────────────────────────┘
```
三个独立的仓库共享一个后端:
- **后端 (Backend)** — Express API,PostgreSQL,JWT 身份验证,OAuth
- **CLI** — 可全局安装的 `insighta` 终端工具
- **Web 门户 (Web Portal)** — 使用 HTTP-only cookie 的浏览器界面
## 技术栈
- **运行时 (Runtime)**: Node.js + TypeScript
- **框架 (Framework)**: Express
- **数据库 (Database)**: PostgreSQL
- **身份验证 (Auth)**: 带有 PKCE 的 GitHub OAuth 2.0
- **令牌 (Tokens)**: JSON Web Tokens (JWT)
- **部署 (Deployment)**: Railway
## 本地设置
### 前置条件
- Node.js 18+
- 本地运行的 PostgreSQL
### 步骤
```
git clone
cd profiles-api
npm install
cp .env.example .env # fill in all values
npm run build
npm run migrate # creates all tables + indexes
npm run seed # seeds 2026 profiles
npm run dev
```
### 环境变量
| 变量 | 描述 |
|---|---|
| `PORT` | 服务器端口(默认为 3000) |
| `DATABASE_URL` | PostgreSQL 连接字符串 |
| `NODE_ENV` | `development` 或 `production` |
| `GITHUB_CLIENT_ID` | 来自 GitHub OAuth App 设置 |
| `GITHUB_CLIENT_SECRET` | 来自 GitHub OAuth App 设置 |
| `GITHUB_CALLBACK_URL` | 必须与在 GitHub 上注册的完全一致 |
| `JWT_ACCESS_SECRET` | 用于签名 access token 的长随机字符串 |
| `JWT_REFRESH_SECRET` | 用于签名 refresh token 的长随机字符串 |
| `FRONTEND_URL` | Web 门户源(用于 CORS + cookie 重定向) |
| `CSRF_SECRET` | 用于生成 CSRF token 的密钥 |
## 身份验证流程
### GitHub OAuth — Web 门户
```
Browser → GET /auth/github
← Redirect to GitHub login page
→ User approves → GitHub redirects to /auth/github/callback?code=...
← Backend exchanges code for GitHub token
← Fetches GitHub user profile
← Creates/updates user in DB
← Sets HTTP-only access_token + refresh_token cookies
← Redirects browser to /dashboard
```
### GitHub OAuth — CLI (PKCE 流程)
```
CLI generates code_verifier + code_challenge (SHA-256)
CLI opens browser → GET /auth/github?code_challenge=...&code_verifier=...
GitHub redirects → /auth/github/callback?code=...&code_verifier=...
Backend verifies PKCE, exchanges code, returns JSON:
{ access_token, refresh_token, user }
CLI saves tokens to ~/.insighta/credentials.json
```
PKCE 可防止 token 被拦截——`code_verifier` 绝不会发送到 GitHub,只会发送其 challenge hash。后端会在签发 token 之前验证它们是否匹配。
## Token 处理
| Token | 有效期 | 存储 (CLI) | 存储 (Web) |
|---|---|---|---|
| Access token | 3 分钟 | `~/.insighta/credentials.json` | HTTP-only cookie |
| Refresh token | 5 分钟 | `~/.insighta/credentials.json` | HTTP-only cookie |
**轮换 (Rotation):** 每次使用 refresh token 时,它会立即从数据库中删除,并签发一对新的 token。重复使用旧的 refresh token 将返回 401。
**自动刷新:** 当 CLI 收到 401 响应时,会自动调用 `POST /auth/refresh`,使用新的 access token 重试原始请求,并将新 token 保存到磁盘。
## 角色权限控制
系统存在两种角色:`admin` 和 `analyst`。新用户在首次登录时默认被分配 `analyst` 角色。
| 端点 | analyst | admin |
|---|---|---|
| `GET /api/profiles` | ✅ | ✅ |
| `GET /api/profiles/:id` | ✅ | ✅ |
| `GET /api/profiles/search` | ✅ | ✅ |
| `GET /api/profiles/export` | ✅ | ✅ |
| `POST /api/profiles` | ❌ | ✅ |
| `DELETE /api/profiles/:id` | ❌ | ✅ |
角色信息被编码在 JWT payload 中,并在每次请求时由 `requireRole()` 中间件进行验证。同时,每次请求也会通过 `requireAuth` 与数据库进行交叉比对。
## API 版本控制
对 `/api/*` 的每一个请求都必须包含以下标头:
```
X-API-Version: 1
```
缺失或版本不正确将返回:
```
{ "status": "error", "message": "API version header required" }
```
## API 端点
### 身份验证
| 方法 | 端点 | 描述 |
|---|---|---|
| `GET` | `/auth/github` | 重定向至 GitHub OAuth |
| `GET` | `/auth/github/callback` | OAuth 回调——签发 token |
| `POST` | `/auth/refresh` | 刷新 access + refresh token |
| `POST` | `/auth/logout` | 使 refresh token 失效 |
| `GET` | `/auth/me` | 获取当前用户的个人资料 |
### 档案(均需要身份验证 + `X-API-Version: 1`)
| 方法 | 端点 | 角色 | 描述 |
|---|---|---|---|
| `GET` | `/api/profiles` | 任意 | 列表,支持过滤、排序、分页 |
| `GET` | `/api/profiles/search?q=` | 任意 | 自然语言搜索 |
| `GET` | `/api/profiles/export` | 任意 | 下载 CSV |
| `GET` | `/api/profiles/:id` | 任意 | 获取单个档案 |
| `POST` | `/api/profiles` | admin | 创建档案 |
| `DELETE` | `/api/profiles/:id` | admin | 删除档案 |
### 过滤参数(`GET /api/profiles`)
| 参数 | 类型 | 示例 |
|---|---|---|
| `gender` | string | `male` |
| `age_group` | string | `adult` |
| `country_id` | string | `NG` |
| `min_age` | number | `25` |
| `max_age` | number | `40` |
| `min_gender_probability` | float | `0.8` |
| `min_country_probability` | float | `0.5` |
| `sort_by` | string | `age` / `created_at` / `gender_probability` |
| `order` | string | `asc` / `desc` |
| `page` | number | `1` |
| `limit` | number | `10`(最大 50) |
### 分页响应结构
```
{
"status": "success",
"page": 1,
"limit": 10,
"total": 2026,
"total_pages": 203,
"data": [...]
}
```
## 自然语言解析
端点:`GET /api/profiles/search?q=`
基于规则的解析——不使用 AI,不使用 LLM。
| 查询 | 解析出的过滤器 |
|---|---|
| `young males from nigeria` | gender=male, min_age=16, max_age=24, country_id=NG |
| `females above 30` | gender=female, min_age=30 |
| `adult males from kenya` | gender=male, age_group=adult, country_id=KE |
| `seniors from ghana` | age_group=senior, country_id=GH |
| `people between 20 and 40` | min_age=20, max_age=40 |
**规则:**
- `young` → min_age=16, max_age=24(仅用于解析,不是已存储的年龄组)
- `above/over X` → min_age=X
- `below/under X` → max_age=X
- `between X and Y` → min_age=X, max_age=Y
- 性别词汇:male/man/men/boy → male;female/woman/women/girl → female
- 国家名称 → ISO 2 字母代码(已映射 65 个国家)
- 年龄组词汇:child/kids,teen/teenager,adult,senior/elderly/old
无法解析的查询将返回:
```
{ "status": "error", "message": "Unable to interpret query" }
```
## 速率限制
| 路由 | 限制 |
|---|---|
| `/auth/*` | 每分钟 10 次请求 |
| `/api/*` | 每分钟每个用户 60 次请求 |
## 请求日志
每次请求都会记录:`[timestamp] METHOD /path STATUS_CODE duration_ms`
示例:
```
[2026-04-27T08:00:00.000Z] GET /api/profiles 200 12ms
```
## CSV 导出
`GET /api/profiles/export` —— 支持所有的过滤参数,流式传输带有以下标头的 `.csv` 文件:
```
id, name, gender, gender_probability, age, age_group, country_id, country_name, country_probability, created_at
```
## 数据库架构
```
-- profiles
id, name, gender, gender_probability, sample_size, age, age_group,
country_id, country_name, country_probability, created_at
-- users
id, github_id, username, email, avatar_url, role,
is_active, last_login_at, created_at
-- refresh_tokens
id, user_id, token, expires_at, created_at
```
## 部署 (Railway)
启动命令:
```
npm run build && npm run migrate && npm run seed && npm start
```
在 Railway 上需要配置的环境变量:
```
DATABASE_URL (auto-injected from Postgres plugin)
NODE_ENV=production
GITHUB_CLIENT_ID
GITHUB_CLIENT_SECRET
GITHUB_CALLBACK_URL
JWT_ACCESS_SECRET
JWT_REFRESH_SECRET
FRONTEND_URL
CSRF_SECRET
```
标签:API后端, Bearer Token, B/S架构, Express, GitHub OAuth, GNU通用公共许可证, HTTP-only Cookies, MITM代理, Node.js, PostgreSQL, RBAC权限控制, React, RESTful API, Syscalls, Web门户, 人口统计智能平台, 单页应用, 安全认证, 提示词优化, 数据分析平台, 数据导出, 测试用例, 用户画像分析, 用户画像分析系统, 自动化攻击, 自然语言查询, 身份验证与授权