一个极简的双端互动问答应用。iPhone 端发送带选项的问题,对方 Apple Watch 震动后抬腕即可直接点击作答,或在 iPhone 上通过灵动岛 / 长按通知直接回答,全程不需要打开 App。
A 在 iPhone 发送问题 + 选项(可选择哪些选项高亮蓝色)
↓
B 的 Apple Watch 震动 / iPhone 灵动岛弹出或弹通知
↓
B 直接点选作答(Watch 抬腕 / iPhone 灵动岛点选 / 长按通知)
↓
A 收到"对方已回答"通知(显示问题和选项)
| 层级 | 技术 |
|---|---|
| 后端 | Go · Gin · MySQL · APNs |
| 推送 | APNs HTTP/2(sideshow/apns2),支持 Push-to-Start Live Activity |
| iPhone | SwiftUI · async/await · StoreKit 2 · ActivityKit |
| Apple Watch | SwiftUI · WKNotificationScene · 独立登录 |
| iPhone 通知 | Notification Content Extension(长按直接回答) |
| 灵动岛 | Live Activity Widget Extension · Push-to-Start · LiveActivityIntent |
| 登录同步 | WatchConnectivity(iPhone → Watch 传 JWT+userId)+ Watch 独立登录 |
| 认证 | JWT(7 天有效期) |
| 邮件 | 标准 SMTP(默认 Gmail,可换任意服务商) |
| 项目管理 | XcodeGen(project.yml 生成 .xcodeproj) |
| 部署 | Rocky Linux 9 · Nginx · Cloudflare |
TapBB/
├── TapBB.xcodeproj # 由 XcodeGen 生成,不要手动编辑
├── project.yml # XcodeGen 项目配置(所有 target 定义)
├── TapBB/ # iPhone App
├── TapBBWatch Watch App/ # Watch App
├── TapBBNotification/ # iPhone 通知扩展(交互式回答)
├── TapBBLiveActivity/ # 灵动岛 Widget Extension
├── Shared/ # 主 App 与灵动岛共享代码(ActivityAttributes + LiveActivityIntents)
├── backend/ # Go 后端
│ ├── main.go
│ ├── config/
│ ├── handlers/
│ ├── models/
│ ├── middleware/
│ ├── push/
│ ├── email/
│ └── apitest/ # 集成测试
├── deploy/
│ ├── nginx.conf # Nginx 反向代理配置
│ └── .env.production # 生产环境变量模板
├── tests/
│ ├── docker-compose.yml # 测试用 MySQL(端口 13306)
│ ├── .env.test
│ ├── run.sh
│ ├── watch_notification_test.apns
│ └── iphone_notification_test.apns
├── docker-compose.dev.yml # 本地开发 MySQL
├── Makefile
└── .env # 本地环境变量(不提交 git)
# 启动 MySQL
docker compose -f docker-compose.dev.yml up -d
# 建表
make migrate
# 启动后端
make dev # 监听 :8080make build-all
# 输出:
# bin/tapbb-server-linux-amd64
# bin/tapbb-server-linux-arm64
# bin/tapbb-server-darwin-arm64
# bin/tapbb-server-windows-amd64.exe服务器运行目录只需两个文件:
/你的目录/
├── tapbb-server # 二进制(linux/amd64 或 arm64)
└── .env # 环境变量
步骤:
# 1. 编译
make build-all
# 2. 上传二进制
scp bin/tapbb-server-linux-amd64 服务器:/你的目录/tapbb-server
# 3. 建表(首次)或迁移(新字段)— 二进制直接执行 migrate 子命令
/你的目录/tapbb-server migrate
# 4. 启动
/你的目录/tapbb-serverNginx 配置(/etc/nginx/conf.d/tapbb.conf):
server {
listen 80;
server_name tapbb.zgentime.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}sudo nginx -t && sudo systemctl reload nginxCloudflare 负责 HTTPS,Nginx 只做反向代理转发到 :8080。
PORT=8080
JWT_SECRET=至少32位随机字符串
# 数据库
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=tapbb_user
DB_PASSWORD=密码
DB_NAME=tapbb
# SMTP(留空 SMTP_PASSWORD 则跳过邮件发送,默认 Gmail)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_PASSWORD=xxxx xxxx xxxx xxxx
EMAIL_FROM=your@gmail.com
# APNs(留空则跳过推送)
APNS_KEY_PATH=./AuthKey_XXXXXXXXXX.p8
APNS_KEY_ID=XXXXXXXXXX
APNS_TEAM_ID=XXXXXXXXXX
APNS_TOPIC=com.zgentime.TapBB
APNS_SANDBOX=true # Xcode 开发签名用,上线后删掉
APP_BASE_URL=https://tapbb.zgentime.com生产环境模板见 deploy/.env.production。
# Watch 通知(Watch 模拟器必须在表盘界面)
xcrun simctl push <watch-uuid> com.zgentime.TapBBWatch.watchkitapp tests/watch_notification_test.apns
# iPhone 通知(长按展开可直接回答)
xcrun simctl push <iphone-uuid> com.zgentime.TapBB tests/iphone_notification_test.apnsbash tests/run.sh独立 Docker MySQL(端口 13306),测试后自动销毁。
除注册、登录、邮箱验证、忘记/重置密码外,所有接口均需 Authorization: Bearer <token>。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /auth/register |
邮箱注册(含 username 字段) |
| POST/GET | /auth/verify-email |
验证邮箱(GET 供邮件链接直接跳转) |
| POST | /auth/login |
登录,返回 token + user |
| POST | /auth/resend-verification |
重新发送验证邮件 |
| POST | /auth/forgot-password |
发送重置密码邮件 |
| POST | /auth/reset-password |
重置密码 |
| POST | /auth/change-password |
修改密码(需当前密码) |
| POST | /auth/change-email |
修改邮箱(需密码验证) |
| POST | /auth/change-nickname |
修改昵称 |
| POST | /auth/change-username |
修改用户名(唯一,正则 ^[a-z0-9_]{3,20}$) |
| POST | /device/register |
注册 APNs device token(platform: iphone/watch/liveactivity) |
| GET | /friend/search?q= |
搜索用户 |
| POST | /friend/request |
发送好友请求 |
| GET | /friend/sent |
已发出的好友请求 |
| DELETE | /friend/request/:id |
撤销好友请求 |
| POST | /friend/respond |
接受 / 拒绝好友请求 |
| GET | /friend/list |
好友列表(含 alias) |
| GET | /friend/pending |
待处理好友请求(含昵称) |
| PUT | /friend/:id/alias |
设置好友备注 |
| DELETE | /friend/:id |
删除好友 |
| POST | /message/send |
发送问题(2~4 选项) |
| POST | /message/reply |
回传答案 |
| GET | /message/history |
历史记录(分页) |
| GET | /message/:id |
消息详情 |
- Go 后端:用户系统 · 好友 · 消息 · APNs · 标准 SMTP 邮件
- 消息过期定时任务(每小时,24 小时后标记 expired)
- 集成测试框架
- Watch App:通知直接回答 · 历史记录 · 消息详情回答 · 独立登录
- iPhone App:登录 · 好友 · 发送 · 历史 · 消息详情回答 · 设置 · Tip Jar
- iPhone 通知扩展:长按通知直接回答(Notification Content Extension)
- 账号管理:修改昵称 · 用户名 · 邮箱 · 密码
- 好友增强:备注 · 已发请求 · 撤销请求
- WatchConnectivity JWT+userId 同步(含自动重推)
- 选项高亮(highlight_indices 多选,星标图标)
- 四平台编译
- 生产部署(Rocky Linux 9 · Nginx · Cloudflare · tapbb.zgentime.com)
- 全面代码审查 + 安全修复(后端 15 项 + iOS 11 项)
- APNs 真机联调(iPhone 推送 + 交互式通知回答 + 回答通知)
- Xcode Capabilities(Push Notifications · Time Sensitive)
- 历史记录搜索(本地过滤问题/选项)
- 好友搜索/添加分离(搜索过滤好友列表 + 独立添加好友入口)
- iOS 26 Liquid Glass 搜索栏(
.searchToolbarBehavior(.minimize)) - 发送页 UI 优化(星标高亮 · 键盘发送键 · 滚动收键盘)
- 灵动岛 / Live Activity(Push-to-Start 远程启动 · 灵动岛内直接回答/关闭)
- XcodeGen 项目管理(
project.yml定义所有 target) - 上线