# triple
**Repository Path**: libingquan/triple
## Basic Information
- **Project Name**: triple
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-31
- **Last Updated**: 2026-09-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Triple App
日历 + 待办 + Flomo 速记,自托管效率工具。Spring Boot + Vue 3 实现,移动端 PWA 免安装。
## 功能
| 模块 | 功能 |
|------|------|
| 📅 日历 | 月/周/日三视图、事件 CRUD(含编辑)、颜色标签、全天事件、重复事件(每日/每周多选/每月/每年 + 间隔 + 结束日期)、当日面板一键完成待办 |
| ✅ 待办 | 多列表(长按删除,级联清理)、优先级、截止日期、备注、筛选(全部/未完成/已完成/今天/高优先级)、快速添加、编辑、列表内拖拽排序、左滑完成/删除 |
| 💡 Flomo | 快速记录、#标签、Markdown、链接自动识别与预览卡、时间线、搜索、每日回顾、一键复制(卡片图标 / 左滑)、左滑编辑/删除 |
| 🌙 体验 | 深色模式(跟随系统/浅色/深色手动切换) |
| 📊 看板 | 周期统计卡片 + 近 30 天 echarts 趋势图表 |
| 🧾 物品 | 归物本:记录购买时间与价格,自动计算已用天数与每日成本,置顶总资产/日均成本(仅现役),预定义分类 + 现役/退役状态 + 名称模糊搜索 |
| 🔗 分享 | 家庭共享的 HTML 攻略/计划列表(管理员放置文件到服务器目录或在 App 内粘贴发布,自动扫描 + `
` 识别标题,新标签页公开打开),详见 [`SHARE-FEATURE.md`](./SHARE-FEATURE.md) |
| 👤 用户 | JWT 认证、修改密码、数据隔离、管理员用户管理(生产关闭自助注册) |
| 🔔 提醒 | 邮件提醒(R1:待办当天 09:00 / 事件提前 / 全天事件前一天,均可配置,「我的」页设置);iOS Web Push(R2:Safari 16.4+ 走 APNs,需配 VAPID 密钥,见 `ALIYUN-DEPLOY.md` §5.4;Android 走邮件兜底) |
## 技术栈
- **后端**: Spring Boot 3.4 + Spring Security + JPA + H2
- **前端**: Vue 3 + Vite + Vant UI + Pinia
- **部署**: Caddy + systemd + 自有域名(自动 HTTPS)
## 快速开始(本地开发)
### 后端
```bash
cd backend
./mvnw spring-boot:run
# 默认端口 8082,H2 控制台 http://localhost:8082/h2-console
# 默认管理员: admin / admin123
```
### 前端
```bash
cd frontend
pnpm install
pnpm dev
# 默认端口 5173,自动代理 /api → localhost:8082
```
> 构建前端需要 Node.js ≥ 22.13(新版 pnpm 要求)。如果本机默认是 Node 18,请先执行
> `nvm use 22` 或 `nvm alias default 22`。
## 生产部署
> 速查(现状 → 上线 → 运维,推荐先看):[`DEPLOY-QUICKSTART.md`](./DEPLOY-QUICKSTART.md)
> 完整方案(地域选择、备案、OSS 异地备份〔可选层〕、探活告警、运维手册、事实核查):[`ALIYUN-DEPLOY.md`](./ALIYUN-DEPLOY.md)。以下为速查摘要。
### 0. 前提
- 选择**海外免备案地域**;香港轻量部分规格已停售/缺货,可用**马来西亚(吉隆坡)**等替代。买一个**自有域名**(如 `triple.example.com`,解析子域名 A 记录到服务器公网 IP)。
- 服务器规格:阿里云轻量 2C2G / 40GB ESSD / 200Mbps 峰值 / 1 IPv4 / 无固定流量,Ubuntu 22.04 即可。
### 1. 服务器初始化(一次性)
```bash
# 1) Caddy 官方仓库(Ubuntu 22.04 官方源没有 caddy 包,勿用 apt install caddy)
sudo apt update && sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl wget git unzip
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install -y caddy openjdk-17-jdk-headless
# 2) 应用专用用户(无登录 shell)
sudo useradd -r -s /bin/false triple
sudo timedatectl set-timezone Asia/Shanghai
# 3) 初始化 Caddy 全局"导入壳"(一次性)
# 全局 Caddyfile 是多项目共享的壳,只负责 import 各项目分片;
# deploy.sh 只写本项目分片 /etc/caddy/sites.d/triple.caddy,绝不整体覆盖它。
# 若服务器已有多项目在用,先按 CADDY-MULTI-PROJECT.md 第二节做拆分迁移(备份→拆分片→写壳→validate→reload),勿直接覆盖!
sudo mkdir -p /etc/caddy/sites.d
sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF'
# 全局 Caddy 配置壳:只导入各项目分片(勿整体覆盖本文件)
# 如需全局选项(如 email you@example.com),在本文件顶部加 { ... } 块
import /etc/caddy/sites.d/*.caddy
EOF
```
### 2. 首次部署环境变量(仅首次)
```bash
export JWT_SECRET="$(openssl rand -base64 48)"
export ADMIN_PASSWORD="你的管理员密码"
```
> 首次部署写入 `/etc/triple/triple.env`(chmod 600)。**再次部署可省略**——脚本复用旧文件,避免轮换 JWT_SECRET 导致已登录用户全部掉线。
### 3. 本地构建并上传(推荐,2G 内存不跑构建)
```bash
# —— 开发机 ——
cd backend && mvn clean package -DskipTests && cd ..
cd frontend && pnpm install && pnpm build && cd ..
ssh root@ 'mkdir -p /root/triple-release/static'
scp backend/target/triple-0.0.1.jar root@:/root/triple-release/triple.jar
scp -r frontend/dist/* root@:/root/triple-release/static/
scp deploy.sh Caddyfile triple.service root@:/root/triple-release/
# —— 服务器 ——
cd /root/triple-release
./deploy.sh triple.example.com --skip-build
```
> `deploy.sh <域名> [--skip-build]`:`--skip-build` 跳过构建,直接读取服务器 `/root/triple-release/triple.jar` 和 `/root/triple-release/static/`;不带参数则在服务器上全量构建(需 2G+ swap)。
>
> `deploy.sh` 不再整体覆盖 `/etc/caddy/Caddyfile`,只写本项目分片 `/etc/caddy/sites.d/triple.caddy` 后 reload(多项目互不影响,详见 `CADDY-MULTI-PROJECT.md`);若服务器全局 Caddyfile 尚未初始化为导入壳,脚本会报错中止——按第 1 节步骤 3 初始化即可。
### 4. 验证
```bash
sudo systemctl status triple # active (running)
curl -sI https://triple.example.com | head -3 # HTTP/2 200
```
浏览器打开 `https://triple.example.com` → admin 登录 → **设置 → 用户管理** 给家人建号(自助注册已在生产关闭)。
> 如果域名刚注册仍处于实名审核中,HTTPS 证书暂时无法签发;等待审核通过并添加 A 记录后,执行
> `sudo systemctl reload caddy`,Caddy 会自动补齐证书。
### 5. 备份(三重)
- 应用内 `DatabaseBackupService` 每日 03:00 执行 H2 `BACKUP` → `/opt/triple/backup/triple-日期.zip`(保留 7 天)
- OSS 异地(可选层):每日 03:30 cron 用 `ossutil` 上传最新 zip 到与服务器同地域的 Bucket(内网 endpoint 免流量,保留 30 天;不配不影响上线,可后置补)
- 本地兜底:每月手动/NAS 拉一次全量
恢复:`sudo /opt/triple/restore.sh triple-日期.zip`(支持 zip 与 .mv.db;跨机迁移须连同 `/etc/triple/triple.env` 一起搬)。
## 安全
- 所有流量通过 Caddy 自动 HTTPS 加密
- 密码 bcrypt 哈希(cost 12)
- JWT 双 token:access(15min,仅前端内存)+ refresh(7d,httpOnly + Secure + SameSite Cookie,不落 localStorage),带类型声明互不混用,改密/登出即时失效
- 数据按用户隔离,从 JWT 提取 userId
- 速记链接预览:服务器按内容首个链接抓取 og 元数据生成卡片,经**私网 IP 守卫(SSRF 防护)+ 每日配额**,仅 http/https、响应限长/超时;失败不影响速记保存,可关(`app.link-preview.enabled=false`)
- 生产**关闭自助注册**(`app.registration.enabled=false`),账号由管理员在「用户管理」页创建;管理员可删除用户(不能删除自己)
- SSH 建议密钥登录,防火墙只放行 22/80/443
## 数据备份
- 数据库:H2 file 模式(详见 PRD 第七章选型分析)
- 定时备份:每日凌晨 3 点自动执行 H2 `BACKUP` 生成 zip(`DatabaseBackupService` → `/opt/triple/backup/`),保留最近 7 天
- 异地备份(可选层):`ossutil` 上传至阿里云 OSS(详见 ALIYUN-DEPLOY.md;不配时保持每月手动拉取兜底)
- 手动冷备:`backup.sh`(服务运行中会自动停服 → 拷贝 → 重启,保证 `.mv.db` 一致性)
- 恢复:`restore.sh`,同时支持 `.zip`(应用内自动备份)与 `.mv.db`(冷备文件);恢复后自动 `chown triple`
- 数据导出/导入:设置页「导出数据」一键导出全部 JSON;「导入数据」把导出的 JSON 重新导入当前账号(追加合并)
- 生产 schema:`ddl-auto: validate` + Flyway 版本化迁移(V1 初始化),避免隐式改表
## 项目结构
```
triple-app/
├── backend/ # Spring Boot
│ ├── src/main/java/com/triple/
│ │ ├── config/ # Security, CORS, DataInit, 定时备份
│ │ ├── security/ # JWT, AuthFilter, Utils
│ │ ├── user/ # User entity, service, controller
│ │ ├── calendar/ # CalendarEvent entity, service, controller, Dashboard
│ │ ├── task/ # TaskList, TaskItem entities, service, controller
│ │ ├── memo/ # Memo entity, service, controller
│ │ ├── reminder/ # 提醒:Planner/Scheduler、邮件+Web Push 通道、订阅、偏好
│ │ ├── share/ # 分享(攻略):扫描本地 HTML 生成列表
│ │ ├── item/ # 物品(归物本):购买/价格/日均成本/分类/状态
│ │ ├── export/ # 数据导出 / 导入
│ │ └── common/ # ApiResponse, ExceptionHandler
│ ├── src/main/resources/
│ │ ├── application.yml
│ │ ├── application-prod.yml
│ │ └── db/migration/ # Flyway 版本化迁移
│ └── src/test/ # 集成 + 单元测试(211 用例)
├── frontend/ # Vue 3 + Vite
│ ├── src/
│ │ ├── api/ # Axios client + module APIs
│ │ ├── stores/ # Pinia stores
│ │ ├── views/ # Page components(含 UserManagementView、ShareView、ItemsView)
│ │ ├── components/ # Reusable components
│ │ ├── utils/ # 工具(recurrence/push/renderMarkdown/links/date/priority/tags)
│ │ ├── router/ # Vue Router
│ │ ├── styles/ # Global CSS
│ │ └── sw.js # 自定义 Service Worker(预缓存 + Web Push)
│ ├── e2e/ # Playwright E2E 冒烟(8 步)
│ └── public/
│ └── icons/ # App icons(manifest 由 VitePWA 生成)
├── Caddyfile # Caddy 站点分片模板(部署写入 /etc/caddy/sites.d/triple.caddy)
├── CADDY-MULTI-PROJECT.md # 多项目共享 Caddy 的分片化改造方案
├── triple.service # systemd unit file
├── deploy.sh # One-click deployment script
├── backup.sh # Database backup script
├── restore.sh # Database restore script
├── healthcheck.sh # 探活脚本(4 探针 + 企业微信告警,--self-test 自测)
├── ALIYUN-DEPLOY.md # 阿里云部署完整方案
├── DEPLOY-QUICKSTART.md # 部署速查(现状→上线→运维)
├── PRD.md # 产品需求文档
├── TESTING.md # 测试方案与状态
├── SHARE-FEATURE.md # 分享(攻略)功能说明 + 完整升级方案
└── generate-icons.sh # PWA icon generator
```
## API 文档
详见 PRD 文档中的 API 设计章节。
## License
MIT