Skip to content

lijiext/ics_reminder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Contract Expiry ICS Reminder Service

一个简单的 TypeScript + SQLite 服务:外部系统通过 webhook 推送全量工单/合同快照,服务保存每一次完整 payload,记录本次与上一次 active 数据的差异,并提供动态 ICS 订阅地址。

功能

  • POST /webhook/contractsPOST /webhook/tickets 接收外部应用推送的全量工单/合同信息。
  • SQLite 保存当前 active 数据、每一次完整 webhook 快照、每一次新增/修改/删除日志。
  • GET /contracts.ics 每次请求都实时读取 SQLite 最新 active 数据生成 ICS。
  • GET /sync-logs 查看最近同步差异。
  • GET /health 健康检查。

环境要求

  • Node.js 22.5 或更高版本。
  • npm。

本项目使用 Node 自带的 node:sqlite,不依赖第三方 SQLite 驱动。

安装

npm install
npm run init-db

启动服务

npm run serve

默认监听:

http://127.0.0.1:3000

管理员订阅地址:

http://127.0.0.1:3000/contracts.ics

生产部署建议至少配置 WEBHOOK_SECRET。如果 ICS 订阅地址不应该公开,也配置 CALENDAR_TOKEN

Webhook 推送

每次 webhook 请求表示一次完整快照。也就是说,如果某个旧工单没有出现在本次 payload 中,系统会认为它已被删除,并从 ICS 中移除。

curl -X POST "http://127.0.0.1:3000/webhook/contracts?source=test-system" \
  -H "content-type: application/json" \
  -H "x-webhook-secret: your-webhook-secret" \
  -d '{
    "tickets": [
      {
        "id": "ticket-001",
        "userName": "张三",
        "expiresAt": "2026-05-01T10:00:00+08:00",
        "description": "A 产品 120 件,年度服务合同",
        "reminderDaysBefore": 1
      },
      {
        "id": "ticket-002",
        "userName": "李四",
        "expiresAt": "2026-05-10T18:00:00+08:00",
        "description": "B 产品 80 件,季度续约合同",
        "reminderDaysBefore": 3
      }
    ]
  }'

响应会包含本次变化统计和明细:

{
  "ok": true,
  "snapshotId": "1",
  "itemCount": 2,
  "added": 2,
  "modified": 0,
  "deleted": 0
}

支持的外层数组字段名:

  • contracts
  • tickets
  • items
  • data

也可以直接 POST 数组。

为了避免误删,空数组会被拒绝。如果确实需要清空所有 active 工单,建议先增加专门的确认接口,而不是复用普通同步 webhook。

单条数据支持这些字段别名:

  • ID: id, contractId, ticketId, workOrderId
  • 用户名: userName, user_name, username, user, customerName
  • 到期时间: expiresAt, expires_at, expireTime, expire_time, expiredAt, dueAt, due_at
  • 简述: description, summary, brief, remark, content
  • 提前提醒天数: reminderDaysBefore, reminder_days_before, remindDaysBefore, alarmDaysBefore

查看同步日志

curl "http://127.0.0.1:3000/sync-logs?limit=10"

日志中会记录:

  • added: 本次新增的工单。
  • modified: 本次发生字段变化的工单,包含 beforeafter
  • deleted: 本次快照缺失、因此被标记删除的旧工单。

数据表

contracts: 当前工单/合同数据。只有 status = 'active' 会出现在 ICS 中。

webhook_snapshots: 每一次 webhook 的完整原始 payload。

sync_logs: 每一次 webhook 与上一份 active 数据比较后的新增、修改、删除日志。

配置

可以通过环境变量调整:

DATABASE_PATH=./data/contracts.sqlite \
PORT=3000 \
HOST=127.0.0.1 \
CALENDAR_NAME="合同到期提醒" \
WEBHOOK_SECRET="change-me" \
CALENDAR_TOKEN="calendar-token" \
ADMIN_TOKEN="admin-token" \
CORS_ORIGIN="https://example.com" \
MAX_BODY_BYTES=5242880 \
npm run serve

安全相关配置:

  • WEBHOOK_SECRET: 设置后,webhook 请求必须携带 x-webhook-secretAuthorization: Bearer <token>
  • CALENDAR_TOKEN: 设置后,订阅 ICS 时必须携带 ?token=<token>x-calendar-token 或 Bearer token。
  • ADMIN_TOKEN: 设置后,访问 /sync-logs 时必须携带 ?token=<token>x-admin-token 或 Bearer token。
  • CORS_ORIGIN: 默认不返回 CORS 头。只有确实需要浏览器跨域调用时再配置具体来源。
  • MAX_BODY_BYTES: webhook 请求体最大字节数,默认 5242880

允许其他机器访问时,可以显式监听所有网卡:

npm start -- serve --host 0.0.0.0 --port 8080

如果配置了 CALENDAR_TOKEN,订阅地址类似:

http://127.0.0.1:3000/contracts.ics?token=calendar-token

Docker 部署

构建镜像:

docker build -t contract-expiry-ics:latest .

运行容器:

docker run -d \
  --name contract-expiry-ics \
  -p 3000:3000 \
  -v contract-expiry-ics-data:/app/data \
  -e WEBHOOK_SECRET="change-me" \
  -e CALENDAR_TOKEN="calendar-token" \
  -e ADMIN_TOKEN="admin-token" \
  contract-expiry-ics:latest

容器默认配置:

  • 监听 0.0.0.0:3000
  • SQLite 数据库路径为 /app/data/contracts.sqlite
  • /app/data 已声明为持久化卷。
  • 运行阶段使用非 root 用户。

常用命令

npm run build
npm test
npm run init-db
npm run serve

测试用示例数据:

npm run seed-sample

静态生成 ICS 仍保留为调试命令,部署订阅时不需要定时生成文件:

npm run generate

后续接入真实 SQL 数据库

当前数据库访问集中在 src/contracts.ts。后续如果换成 MySQL、PostgreSQL 或其他 SQL 数据库,主要替换 ContractRepository,HTTP 接口和 ICS 生成逻辑不需要大改。

About

使用webhook传入合同信息,通过ics暴露出所有合同的到期时间,适用于销售等需要人工提醒用户续期的需求

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors