Skip to content
Draft
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
34 changes: 29 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
# Copy to .env, fill real values, then run: chmod 600 .env
# Validate without exposing values: npm run preflight -- --target ingest:send

# ---- DeepSeek (排名 / 总结 / 影响;OpenAI 兼容协议) ----
DEEPSEEK_API_KEY=sk-...

# ---- Supabase (共享数据库;本地写,云端 UI 读) ----
# ---- Supabase (共享数据库;本地任务与 Web 服务端使用) ----
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ... # 仅本地 ingest 用,勿放进前端
SUPABASE_SERVICE_ROLE_KEY=sb_secret_... # 仅 server-side,绝不得使用 NEXT_PUBLIC_

# ---- Server酱 (每晚推送到微信) ----
# 去 https://sct.ftqq.com 用微信扫码登录、关注服务号,复制 SendKey 填这里。
# 兼容老版 Turbo(SCT...) 与 Server酱³(sctp...) 两种 key,代码自动适配。
SERVERCHAN_SENDKEY=SCT...

# ---- 可选 SMTP 邮件推送(配置以下 7 项后与微信双通道发送) ----
# 163 邮箱示例收件人:hgjly1206@163.com;SMTP_PASS 使用授权码,不是登录密码。
# SMTP_HOST=smtp.163.com
# SMTP_PORT=465
# SMTP_SECURE=true
# SMTP_USER=your-sender@163.com
# SMTP_PASS=your-smtp-app-password
# EMAIL_FROM=your-sender@163.com
# EMAIL_TO=hgjly1206@163.com

# ---- 可选:抬高 github 未鉴权速率限制 ----
GITHUB_TOKEN=

# ---- 可选:网页深链回前台 ----
WEB_BASE_URL=https://your-app.vercel.app
# ---- OpenAlex:配置校验可选,稳定采集强烈建议填写官方免费 API key ----
# 未填写时不会阻断其他来源,但 OpenAlex 匿名访问可能单独降级。
OPENALEX_API_KEY=

# ---- 反馈一键链接签名(任意随机串;本地与 Vercel 私有站需一致)----
# ---- owner 登录后确认的一次性反馈链接(ingest / ingest:send / push:last 必需)----
# 仅填 origin:本地可用 http://127.0.0.1:3000,生产使用最终 HTTPS origin。
WEB_BASE_URL=
# 至少 32 字节;可用 openssl rand -hex 32 生成。
FEEDBACK_SECRET=

# ---- 独立失败告警 webhook(不依赖微信/SMTP 投递通道) ----
# 手工运行时可不配;npm run doctor、launchd 安装和云任务要求配置 URL。
# URL 必须是 HTTPS;bearer token 可选。告警失败不会覆盖原始任务错误。
# URL 也可能含密钥,URL/token 均不得使用 NEXT_PUBLIC_、VITE_ 等公开前缀。
# ALERT_WEBHOOK_URL=https://alerts.example.com/frontier
# ALERT_WEBHOOK_TOKEN=replace-with-alert-token
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
- package-ecosystem: npm
directory: "/web"
schedule:
interval: weekly
open-pull-requests-limit: 5
92 changes: 92 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: CI

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
quality:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
web/package-lock.json
- name: Install zsh for macOS scheduler contract tests
run: sudo apt-get update && sudo apt-get install -y zsh
- run: npm ci
- run: npm --prefix web ci
- run: npm run lint
- run: npm run typecheck
- run: npm run test:coverage
- run: npm --prefix web run lint
- run: npm --prefix web run typecheck
- run: npm --prefix web run test:coverage
env:
FEEDBACK_SECRET: ffffffffffffffffffffffffffffffffffffffff
WEB_BASE_URL: https://papers.example.com
- run: npm --prefix web run build
env:
AUTH_OWNER_EMAIL: owner@example.com
DEEPSEEK_API_KEY: sk-dddddddddddddddddddddddddddddddddddddddd
FEEDBACK_SECRET: ffffffffffffffffffffffffffffffffffffffff
RATE_LIMIT_SECRET: rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
RATE_LIMIT_SECRET_VERSION: 1
SUPABASE_PUBLISHABLE_KEY: sb_publishable_pppppppppppppppppppppppppppppppppppppppp
SUPABASE_URL: http://127.0.0.1:9
SUPABASE_SERVICE_ROLE_KEY: sb_secret_eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
WEB_BASE_URL: https://papers.example.com
- run: npm audit --omit=dev --audit-level=high
- run: npm --prefix web audit --omit=dev --audit-level=high

e2e:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: web/package-lock.json
- run: npm --prefix web ci
- run: npm --prefix web exec playwright install -- --with-deps chromium
- run: npm --prefix web run test:e2e

database:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run db:test

authorization:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: |
package-lock.json
web/package-lock.json
- run: npm ci
- run: npm --prefix web ci
- run: npm --prefix web exec playwright install -- --with-deps chromium
- run: npm run test:idor
56 changes: 56 additions & 0 deletions .github/workflows/scheduled-ingest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Scheduled ingest (disabled by default)

on:
schedule:
# GitHub cron is UTC. 14:15 UTC = 22:15 Asia/Shanghai.
- cron: "15 14 * * *"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: frontier-paper-dispatch-production-ingest
cancel-in-progress: false

jobs:
ingest:
# A new repository has no variable, so both cron and manual runs stay disabled.
if: ${{ vars.ENABLE_CLOUD_INGEST == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- name: Materialize validated private runtime files
run: npm run cloud:materialize
env:
ALERT_WEBHOOK_TOKEN: ${{ secrets.ALERT_WEBHOOK_TOKEN }}
ALERT_WEBHOOK_URL: ${{ secrets.ALERT_WEBHOOK_URL }}
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
EMAIL_FROM: ${{ secrets.EMAIL_FROM }}
EMAIL_TO: ${{ secrets.EMAIL_TO }}
FEEDBACK_SECRET: ${{ secrets.FEEDBACK_SECRET }}
GITHUB_TOKEN: ${{ github.token }}
OPENALEX_API_KEY: ${{ secrets.OPENALEX_API_KEY }}
PROFILE_MD: ${{ secrets.PROFILE_MD }}
SERVERCHAN_SENDKEY: ${{ secrets.SERVERCHAN_SENDKEY }}
SMTP_HOST: ${{ secrets.SMTP_HOST }}
SMTP_PASS: ${{ secrets.SMTP_PASS }}
SMTP_PORT: ${{ secrets.SMTP_PORT }}
SMTP_SECURE: ${{ secrets.SMTP_SECURE }}
SMTP_USER: ${{ secrets.SMTP_USER }}
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
WEB_BASE_URL: ${{ secrets.WEB_BASE_URL }}
- run: npm run preflight -- --target ingest:send
- run: npm run ingest:send
- name: Remove private runtime files
if: always()
run: rm -f -- .env config/profile.md
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
node_modules/
/node_modules
node_modules.nosync/
node_modules.cloud-old.nosync/
node_modules.cloud-conflict.nosync/
.env
.env.local
.env.*
!.env.example
*.log
.DS_Store
dist/
coverage/
.backups/
test-results/
playwright-report/
config/profile.suggested.md
config/profile.md.bak
config/profile.md
config/scope.suggested.md
legacy/
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
Loading
Loading