38 Commits

Author SHA1 Message Date
Codex ec3e256a8c fix(payment): route Philippine GCash separately from QRIS 2026-07-29 19:21:20 +08:00
Codex 3547f49bd9 revert(payment): remove unsupported Stripe and EzPay upgrade 2026-07-29 17:23:01 +08:00
Codex ee6ab77f4d fix(payment): restore wallet order and English labels 2026-07-29 15:22:43 +08:00
Codex ce3f0af82d fix(payment): allow Stripe after closing QRIS 2026-07-29 14:31:49 +08:00
Codex 638fc054b1 fix(payment): keep character and mobile actions visible 2026-07-29 13:01:08 +08:00
Codex 897bce11db fix(payment): resume QRIS after closing dialog 2026-07-29 12:26:27 +08:00
Codex 1466cb01d2 feat(payment): confirm renewal only at checkout 2026-07-29 11:26:42 +08:00
Codex f6c75dcb86 fix(payment): inherit chat recipient without selector 2026-07-28 19:33:59 +08:00
Codex 187de82eaf ci: encode domestic SSH key secret 2026-07-28 18:26:14 +08:00
Codex d372541925 ci: add isolated domestic frontend deployment 2026-07-28 18:18:42 +08:00
Codex ef9b79bc83 feat(payment): add chat support discounts and gratitude 2026-07-28 17:43:08 +08:00
Codex aee35353a3 feat(payment): expand Stripe methods and checkout handoff 2026-07-28 16:27:03 +08:00
Codex fcb2492118 feat(external-entry): define Facebook business links 2026-07-28 14:53:58 +08:00
Codex cab2ba868f feat(payment): accept support character guidance scene 2026-07-28 12:09:33 +08:00
Codex dab9e2e45a fix(payment): hide first recharge banner 2026-07-28 11:10:51 +08:00
Codex 54ce485f41 feat(private-zone): default to albums tab 2026-07-27 18:56:21 +08:00
Codex e36f94add3 fix(payment): portal checkout dialogs to viewport 2026-07-27 18:50:39 +08:00
Codex ca9cac21f1 feat(chat): render role-bound payment guidance 2026-07-27 18:14:48 +08:00
Codex 662e5e67ea feat(auth): add Messenger topup handoff entry 2026-07-27 17:17:32 +08:00
Codex f403c47052 fix(ci): deploy frontend production as lzf 2026-07-27 16:57:31 +08:00
Codex ac36837add test(chat): enforce locked image URL masking 2026-07-27 14:42:34 +08:00
Codex fe9d31146b feat(subscription): separate selection from payment and add issue feedback 2026-07-27 11:35:42 +08:00
Codex 01c55f5630 fix(external-entry): preserve legacy private room links 2026-07-27 11:28:27 +08:00
Codex b21ef2f6ec feat(chat): send idempotent client message ids 2026-07-27 10:58:51 +08:00
Codex a44fc4860e feat(private-zone): add paid video moments 2026-07-24 20:17:28 +08:00
Codex ff2759cf0f feat(chat): add support action cards and live entitlements 2026-07-24 18:04:05 +08:00
Codex d746d04503 feat(call): add streaming voice call experience 2026-07-24 16:36:36 +08:00
Codex 2a90b4d9ec fix(ci): scope frontend image cleanup 2026-07-24 13:16:35 +08:00
Codex 9094bcbab0 fix(pwa): 同步预发 favicon 源图 2026-07-24 12:20:18 +08:00
Codex 29abd746da fix(pwa): 统一桌面安装图标 2026-07-24 12:17:53 +08:00
Codex 556bfd2919 feat(mobile): improve image viewer and install entry 2026-07-24 11:24:23 +08:00
Codex e3ef289b53 fix(chat): debounce post-send action menu 2026-07-23 20:08:16 +08:00
Codex 46588bd98c feat(payment): support user-bound seven-discount offers 2026-07-23 16:11:20 +08:00
Codex 05f625dd0b feat(chat): render commercial actions and persist greetings 2026-07-23 14:52:34 +08:00
Codex 3790fb813f feat(splash): simplify multi-character home layout 2026-07-23 13:27:16 +08:00
Codex a55a59bff4 fix(private-zone): hide incomplete albums and refresh Maya cover 2026-07-23 11:47:22 +08:00
Codex d2a46ff6b9 refactor(private-zone): use canonical product name 2026-07-23 10:53:41 +08:00
Codex a4c4ca6666 fix(multi-role): enable Maya and Nayeli commercial flows 2026-07-22 20:49:28 +08:00
9 changed files with 39 additions and 39 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ on:
push: push:
branches: branches:
- main - main
- pre - test
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@@ -48,7 +48,7 @@ jobs:
DEPLOY_ENV="prod" DEPLOY_ENV="prod"
NEXT_ENV_FILE=".env.production" NEXT_ENV_FILE=".env.production"
;; ;;
pre) test)
DEPLOY_ENV="test" DEPLOY_ENV="test"
NEXT_ENV_FILE=".env.local" NEXT_ENV_FILE=".env.local"
;; ;;
+2 -2
View File
@@ -72,12 +72,12 @@ copy_env_by_branch() {
START_PORT=9185 START_PORT=9185
echo "=== env: copied .env.production (main → prod) ===" >> "$LOG_FILE" echo "=== env: copied .env.production (main → prod) ===" >> "$LOG_FILE"
;; ;;
pre) test)
cp -f env-example/.env.local.example .env.local cp -f env-example/.env.local.example .env.local
ENV_FILE=".env.local" ENV_FILE=".env.local"
DEPLOY_ENV="test" DEPLOY_ENV="test"
START_PORT=9135 START_PORT=9135
echo "=== env: copied .env.local (pre branch → test runtime) ===" >> "$LOG_FILE" echo "=== env: copied .env.local (test → test) ===" >> "$LOG_FILE"
;; ;;
dev) dev)
cp -f env-example/.env.development.example .env.local cp -f env-example/.env.development.example .env.local
+8 -8
View File
@@ -12,7 +12,7 @@
| 环境 | Git remote | 推送分支 | 宿主机端口 | 容器端口 | 部署脚本 | | 环境 | Git remote | 推送分支 | 宿主机端口 | 容器端口 | 部署脚本 |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 预发环境 | `test` | `pre` | `9135` | `3000` | `scripts/deploy/deploy_web_test.sh` | | 测试环境 | `test` | `test` | `9135` | `3000` | `scripts/deploy/deploy_web_test.sh` |
| 生产环境 | `production` | `main` | `9185` | `3000` | `scripts/deploy/deploy_web.sh` | | 生产环境 | `production` | `main` | `9185` | `3000` | `scripts/deploy/deploy_web.sh` |
当前 remote 配置示例: 当前 remote 配置示例:
@@ -26,15 +26,15 @@ production root@43.106.13.130:/root/cozsweet-repos/main
## 本地发布流程 ## 本地发布流程
预发环境发布流程(脚本迁移前): 测试环境发布流程(脚本迁移前):
1. 进入 pre worktree`cozsweet-frontend-nextjs.worktrees/cozsweet-nextjs-pre` 1. 进入 test worktree`cozsweet-frontend-nextjs.worktrees/cozsweet-nextjs-test`
2. 确认当前分支。 2. 确认当前分支。
3. 执行 `git rebase dev`,把 `dev` 的最新代码变基到 `pre` 分支。 3. 执行 `git rebase dev`,把 `dev` 的最新代码变基到 `test` 分支。
4. 复制测试环境图标到 `public/` 4. 复制测试环境图标到 `public/`
5. 复制 `env-example/.env.local.example``.env.local` 5. 复制 `env-example/.env.local.example``.env.local`
6. 执行旧版 `scripts/deploy/deploy_web_test.sh` 6. 执行旧版 `scripts/deploy/deploy_web_test.sh`
7. 旧版 `deploy_web_test.sh` 推送 `test` remote 的 `pre` 分支。 7. 旧版 `deploy_web_test.sh` 推送 `test` remote 的 `test` 分支。
8. 推送成功后尝试清除 Cloudflare CDN 缓存。 8. 推送成功后尝试清除 Cloudflare CDN 缓存。
旧生产环境发布流程(脚本迁移前): 旧生产环境发布流程(脚本迁移前):
@@ -71,7 +71,7 @@ production root@43.106.13.130:/root/cozsweet-repos/main
| 服务端分支 | 环境变量复制 | 宿主机端口 | 容器名 | 镜像标签 | | 服务端分支 | 环境变量复制 | 宿主机端口 | 容器名 | 镜像标签 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| `main` | `env-example/.env.production.example``.env.production` | `9185` | `cozsweet-web-prod` | `cozsweet-web:prod-<commit>` | | `main` | `env-example/.env.production.example``.env.production` | `9185` | `cozsweet-web-prod` | `cozsweet-web:prod-<commit>` |
| `pre` | `env-example/.env.local.example``.env.local` | `9135` | `cozsweet-web-test` | `cozsweet-web:test-<commit>` | | `test` | `env-example/.env.local.example``.env.local` | `9135` | `cozsweet-web-test` | `cozsweet-web:test-<commit>` |
| `dev` | `env-example/.env.development.example``.env.local` | `9135` | `cozsweet-web-dev` | `cozsweet-web:dev-<commit>` | | `dev` | `env-example/.env.development.example``.env.local` | `9135` | `cozsweet-web-dev` | `cozsweet-web:dev-<commit>` |
| 其他分支 | 使用默认 `.env.local` | `9135` | `cozsweet-web-<branch>` | `cozsweet-web:<branch>-<commit>` | | 其他分支 | 使用默认 `.env.local` | `9135` | `cozsweet-web-<branch>` | `cozsweet-web:<branch>-<commit>` |
@@ -264,12 +264,12 @@ ABORTED ... (docker compose up failed)
1. `scripts/deploy/*` 只负责推送代码,不负责本地构建和本地启动。 1. `scripts/deploy/*` 只负责推送代码,不负责本地构建和本地启动。
2. 自动构建和自动重启只发生在服务器端 `post-receive` hook。 2. 自动构建和自动重启只发生在服务器端 `post-receive` hook。
3. `main` 分支对应生产环境,`pre` 分支对应预发环境。 3. `main` 分支对应生产环境,`test` 分支对应测试环境。
4. 生产推送当前使用 `git push --force production main` 4. 生产推送当前使用 `git push --force production main`
5. 构建失败时不会重启容器,旧容器继续运行。 5. 构建失败时不会重启容器,旧容器继续运行。
6. 服务启动由 Docker Compose 管理,不再使用 `nohup pnpm run start` 6. 服务启动由 Docker Compose 管理,不再使用 `nohup pnpm run start`
7. 服务器需要安装 Docker,并支持 `docker compose` 或旧版 `docker-compose` 命令。 7. 服务器需要安装 Docker,并支持 `docker compose` 或旧版 `docker-compose` 命令。
8. 预发环境和生产环境都通过同一套 `post-receive` 容器化流程部署,差异仅由分支、环境变量文件和端口决定。 8. 测试环境和生产环境都通过同一套 `post-receive` 容器化流程部署,差异仅由分支、环境变量文件和端口决定。
## 后续优化建议 ## 后续优化建议
+7 -7
View File
@@ -8,13 +8,13 @@
| Workflow | 触发时机 | 职责 | | Workflow | 触发时机 | 职责 |
| --- | --- | --- | | --- | --- | --- |
| `.gitea/workflows/ci.yml` | `dev``main``pre` push / PR | 安装依赖、执行完整质量检查、Python 后端 OpenAPI 差异检查、移动端 smoke,并校验 bundle 预算 | | `.gitea/workflows/ci.yml` | `dev``main``test` push / PR | 安装依赖、执行完整质量检查、Python 后端 OpenAPI 差异检查、移动端 smoke,并校验 bundle 预算 |
| `.gitea/workflows/docker-image.yml` | `main``pre` push / 手动触发 | 构建 Docker 镜像、推送到镜像仓库,并通过 SSH 部署 | | `.gitea/workflows/docker-image.yml` | `main``test` push / 手动触发 | 构建 Docker 镜像、推送到镜像仓库,并通过 SSH 部署 |
这样可以避免所有开发分支都发布镜像,并确保生产镜像通过发布门禁。 这样可以避免所有开发分支都发布镜像,并确保生产镜像通过发布门禁。
`main` 分支发布前会执行 Docker workflow 内的完整质量和 bundle 门禁。`pre` `main` 分支发布前会执行 Docker workflow 内的完整质量和 bundle 门禁。`test`
分支用于快速部署预发环境,会跳过完整质量检查,但仍必须通过 bundle 预算;独立的 分支快速部署测试环境,会跳过完整质量检查,但仍必须通过 bundle 预算;独立的
`ci.yml` 会同时执行完整检查并提供测试结果。 `ci.yml` 会同时执行完整检查并提供测试结果。
## 必需 Secrets ## 必需 Secrets
@@ -39,7 +39,7 @@ Next.js 的 `NEXT_PUBLIC_*` 会在构建期固化到产物中,因此测试环
## 镜像 Tag 规则 ## 镜像 Tag 规则
`pre` 分支发布时继续使用现有 `test-*` 运行镜像标签 `test` 分支发布:
```bash ```bash
REGISTRY_IMAGE:test-<short_sha> REGISTRY_IMAGE:test-<short_sha>
@@ -81,7 +81,7 @@ volumes:
## 验证方式 ## 验证方式
推送到 `pre` 分支后,检查 Actions 日志中是否出现: 推送到 `test` 分支后,检查 Actions 日志中是否出现:
```text ```text
Build Docker image Build Docker image
@@ -124,4 +124,4 @@ gitea.banlv-ai.com/admin/cozsweet-web:prod-<short_sha>
- `prod-*` 精确 tag 只保留最近 3 个,`prod-latest` 不计入也不删除。 - `prod-*` 精确 tag 只保留最近 3 个,`prod-latest` 不计入也不删除。
- 当前刚推送的 `IMAGE_VERSION_TAG` 永远不会被删除。 - 当前刚推送的 `IMAGE_VERSION_TAG` 永远不会被删除。
SSH 部署成功后,服务器本机只保留当前环境正在运行的一个精确版本镜像;预发环境清理旧 `test-*`,生产环境清理旧 `prod-*` SSH 部署成功后,服务器本机只保留当前环境正在运行的一个精确版本镜像;测试环境清理旧 `test-*`,生产环境清理旧 `prod-*`
+7 -7
View File
@@ -3,7 +3,7 @@
当前推荐部署链路: 当前推荐部署链路:
```text ```text
push pre/main push test/main
→ Gitea Actions 构建并推送 Docker 镜像 → Gitea Actions 构建并推送 Docker 镜像
→ Actions 通过 SSH 登录目标服务器 → Actions 通过 SSH 登录目标服务器
→ 目标服务器 docker pull 指定镜像 tag → 目标服务器 docker pull 指定镜像 tag
@@ -16,7 +16,7 @@ push pre/main
| 分支 | 环境 | 镜像 tag | 宿主机端口 | 默认服务器目录 | 容器名 | | 分支 | 环境 | 镜像 tag | 宿主机端口 | 默认服务器目录 | 容器名 |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| `pre` | 预发环境 | `test-<short_sha>` | `9135` | `/opt/cozsweet-web-test` | `cozsweet-web-test` | | `test` | 测试环境 | `test-<short_sha>` | `9135` | `/opt/cozsweet-web-test` | `cozsweet-web-test` |
| `main` | 生产环境 | `prod-<short_sha>` | `9185` | `/opt/cozsweet-web-prod` | `cozsweet-web-prod` | | `main` | 生产环境 | `prod-<short_sha>` | `9185` | `/opt/cozsweet-web-prod` | `cozsweet-web-prod` |
## Gitea Secrets ## Gitea Secrets
@@ -75,14 +75,14 @@ prod-<short_sha> 最近 3 个
`test-latest` / `prod-latest` 不计入保留数量,也不会主动删除。 `test-latest` / `prod-latest` 不计入保留数量,也不会主动删除。
部署脚本会在 `docker compose up` 成功后清理服务器本机旧镜像,只保留当前环境正在运行的一个精确版本镜像:预发环境保留当前 `test-<short_sha>`,生产环境保留当前 `prod-<short_sha>` 部署脚本会在 `docker compose up` 成功后清理服务器本机旧镜像,只保留当前环境正在运行的一个精确版本镜像:测试环境保留当前 `test-<short_sha>`,生产环境保留当前 `prod-<short_sha>`
## 本地发布入口 ## 本地发布入口
本地发布脚本现在只负责推送 Gitea 分支,触发 Actions 本地发布脚本现在只负责推送 Gitea 分支,触发 Actions
```bash ```bash
# 预发环境 # 测试环境
./scripts/release/pre_release_web.sh ./scripts/release/pre_release_web.sh
# 生产环境 # 生产环境
@@ -92,16 +92,16 @@ prod-<short_sha> 最近 3 个
也可以直接推送: 也可以直接推送:
```bash ```bash
git push gitea pre git push gitea test
git push --force gitea main git push --force gitea main
``` ```
## 验证 ## 验证
预发环境: 测试环境:
```bash ```bash
ssh <user>@<pre-host> ssh <user>@<test-host>
cd /opt/cozsweet-web-test cd /opt/cozsweet-web-test
docker compose ps docker compose ps
curl -I http://127.0.0.1:9135/ curl -I http://127.0.0.1:9135/
+2 -2
View File
@@ -27,8 +27,8 @@ pnpm exec playwright install chromium
For local development on macOS, `pnpm test:e2e:chrome` can reuse the installed Google Chrome. For local development on macOS, `pnpm test:e2e:chrome` can reuse the installed Google Chrome.
`pnpm test:e2e:mobile-smoke` runs the critical authentication, logout, token `pnpm test:e2e:mobile-smoke` runs the critical authentication, logout, token
refresh and paid-image unlock paths with the Pixel 7 profile. CI 在所有 pull refresh and paid-image unlock paths with the Pixel 7 profile. CI runs this tier
request 以及 `dev` / `pre` / `main` push 时运行这一层测试。 on every pull request and `dev` / `test` / `main` push.
## Environment overrides ## Environment overrides
+1 -1
View File
@@ -3,7 +3,7 @@
# 推送指定分支到指定远端。 # 推送指定分支到指定远端。
# 当前发布由 Gitea Actions 构建镜像并通过 SSH 部署;本脚本只负责触发分支 push。 # 当前发布由 Gitea Actions 构建镜像并通过 SSH 部署;本脚本只负责触发分支 push。
# 调用方:deploy_web.shproduction)→ push_to_remote "gitea" "main" # 调用方:deploy_web.shproduction)→ push_to_remote "gitea" "main"
# deploy_web_test.shpre)→ push_to_remote "gitea" "pre" # deploy_web_test.shtest)→ push_to_remote "gitea" "test"
push_to_remote() { push_to_remote() {
local remote="$1" local remote="$1"
local branch="$2" local branch="$2"
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# ========================================== # ==========================================
# 预发环境 Web 部署脚本(Next.js + Gitea Actions SSH 部署模型) # 测试环境 Web 部署脚本(Next.js + Gitea Actions SSH 部署模型)
# 原始 Dart: scripts/deploy/deploy_web_test.sh # 原始 Dart: scripts/deploy/deploy_web_test.sh
# ========================================== # ==========================================
@@ -11,7 +11,7 @@ source "$SCRIPT_DIR/_deploy_lib.sh"
# 主函数 # 主函数
main() { main() {
push_to_remote "gitea" "pre" push_to_remote "gitea" "test"
} }
main main
+8 -8
View File
@@ -11,9 +11,9 @@ unset_git_hook_env() {
unset_git_hook_env unset_git_hook_env
# pre 分支 worktree 路径 # Test 分支 worktree 路径
WORKTREE_PATH="/Users/chase/Documents/frontend/cozsweet-frontend-nextjs.worktrees/cozsweet-nextjs-pre" WORKTREE_PATH="/Users/chase/Documents/frontend/cozsweet-frontend-nextjs.worktrees/cozsweet-nextjs-test"
echo "=== 进入 pre 分支 worktree ===" echo "=== 进入 test 分支 worktree ==="
cd "$WORKTREE_PATH" || { echo "错误: 无法进入 $WORKTREE_PATH"; exit 1; } cd "$WORKTREE_PATH" || { echo "错误: 无法进入 $WORKTREE_PATH"; exit 1; }
echo "=== 检查当前分支 ===" echo "=== 检查当前分支 ==="
@@ -22,17 +22,17 @@ git branch --show-current
echo "=== 变基到 dev 分支 ===" echo "=== 变基到 dev 分支 ==="
git rebase dev git rebase dev
# 复制预发环境图标(运行资源目录仍为 icons/test # 复制测试环境图标(source: $WORKTREE_PATH/icons/test → dest: $WORKTREE_PATH/public/
echo "=== 复制预发环境图标(icons/test → public/ ===" echo "=== 复制测试环境图标(icons/test → public/ ==="
cp -f "$WORKTREE_PATH/icons/test/favicon.ico" "$WORKTREE_PATH/public/favicon.ico" cp -f "$WORKTREE_PATH/icons/test/favicon.ico" "$WORKTREE_PATH/public/favicon.ico"
cp -f "$WORKTREE_PATH/icons/test/icons/Icon-192.png" "$WORKTREE_PATH/public/images/icons/Icon-192.png" cp -f "$WORKTREE_PATH/icons/test/icons/Icon-192.png" "$WORKTREE_PATH/public/images/icons/Icon-192.png"
cp -f "$WORKTREE_PATH/icons/test/icons/Icon-512.png" "$WORKTREE_PATH/public/images/icons/Icon-512.png" cp -f "$WORKTREE_PATH/icons/test/icons/Icon-512.png" "$WORKTREE_PATH/public/images/icons/Icon-512.png"
# 准备预发环境变量(运行配置仍使用 .env.local # 准备测试环境变量($WORKTREE_PATH/env-example/.env.local.example → $WORKTREE_PATH/.env.local
echo "=== 准备预发环境变量(env-example/.env.local.example → .env.local ===" echo "=== 准备测试环境变量(env-example/.env.local.example → .env.local ==="
cp -f "$WORKTREE_PATH/env-example/.env.local.example" "$WORKTREE_PATH/.env.local" cp -f "$WORKTREE_PATH/env-example/.env.local.example" "$WORKTREE_PATH/.env.local"
echo "=== 执行构建部署脚本(预发环境)===" echo "=== 执行构建部署脚本(测试环境)==="
./scripts/deploy/deploy_web_test.sh ./scripts/deploy/deploy_web_test.sh
echo "=== 预发布完成 ===" echo "=== 预发布完成 ==="