feat: rename portal brand to shopee circle

This commit is contained in:
QiuSW
2026-07-08 17:05:20 +08:00
parent d5aa29e4d5
commit 5c9f070d15
19 changed files with 88 additions and 30 deletions
@@ -1,6 +1,6 @@
你好, 你好,
请打开下面的链接完成 cmhub 邮箱验证: 请打开下面的链接完成虾皮圈邮箱验证:
{{ activate_url }} {{ activate_url }}
@@ -1 +1 @@
[cmhub] 验证你的邮箱 [虾皮圈] 验证你的邮箱
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}登录 - cmhub{% endblock %} {% block title %}登录 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<section class="cmhub-panel"> <section class="cmhub-panel">
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}退出 - cmhub{% endblock %} {% block title %}退出 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<section class="cmhub-panel"> <section class="cmhub-panel">
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}注册 - cmhub{% endblock %} {% block title %}注册 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<section class="cmhub-panel"> <section class="cmhub-panel">
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}验证邮箱 - cmhub{% endblock %} {% block title %}验证邮箱 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<section class="cmhub-panel"> <section class="cmhub-panel">
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}API Key - cmhub{% endblock %} {% block title %}API Key - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<div class="d-flex flex-column gap-4"> <div class="d-flex flex-column gap-4">
+2 -2
View File
@@ -4,14 +4,14 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}cmhub{% endblock %}</title> <title>{% block title %}虾皮圈{% endblock %}</title>
<link href="{% static 'portal/vendor/bootstrap/bootstrap.min.css' %}" rel="stylesheet"> <link href="{% static 'portal/vendor/bootstrap/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'portal/brand.css' %}" rel="stylesheet"> <link href="{% static 'portal/brand.css' %}" rel="stylesheet">
</head> </head>
<body class="{% block body_class %}{% endblock %}"> <body class="{% block body_class %}{% endblock %}">
<nav class="navbar navbar-expand"> <nav class="navbar navbar-expand">
<div class="container"> <div class="container">
<a class="navbar-brand fw-semibold" href="{% url 'portal-home' %}">cmhub</a> <a class="navbar-brand fw-semibold" href="{% url 'portal-home' %}">虾皮圈</a>
<div class="ms-auto d-flex gap-2 flex-wrap justify-content-end"> <div class="ms-auto d-flex gap-2 flex-wrap justify-content-end">
{% with current_url=request.resolver_match.url_name %} {% with current_url=request.resolver_match.url_name %}
{% if user.is_authenticated %} {% if user.is_authenticated %}
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}控制台 - cmhub{% endblock %} {% block title %}控制台 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<div class="d-flex flex-column gap-4"> <div class="d-flex flex-column gap-4">
+3 -3
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}cmhub AI 电商生成台{% endblock %} {% block title %}虾皮圈 AI 电商生成台{% endblock %}
{% block body_class %}home-page{% endblock %} {% block body_class %}home-page{% endblock %}
{% block body %} {% block body %}
@@ -9,7 +9,7 @@
<div class="home-container home-hero-grid"> <div class="home-container home-hero-grid">
<div> <div>
<div class="home-eyebrow">AI 生成 / 点数计费 / 桌面端接入</div> <div class="home-eyebrow">AI 生成 / 点数计费 / 桌面端接入</div>
<h1>cmhub AI 电商生成台</h1> <h1>虾皮圈 AI 电商生成台</h1>
<p class="home-lead"> <p class="home-lead">
把生成标题、生成主图能力封装成稳定的 HTTP API。桌面端填入 API Key 后按本地点数扣费, 把生成标题、生成主图能力封装成稳定的 HTTP API。桌面端填入 API Key 后按本地点数扣费,
余额不足直接拦截,失败自动退点。 余额不足直接拦截,失败自动退点。
@@ -140,7 +140,7 @@
<div class="home-download-box"> <div class="home-download-box">
{% if current_release and current_release.has_download %} {% if current_release and current_release.has_download %}
<h3>Windows 客户端 {{ current_release.version }}</h3> <h3>Windows 客户端 {{ current_release.version }}</h3>
<p>当前版本已发布,可下载后填入 cmhub API Key 使用。</p> <p>当前版本已发布,可下载后填入虾皮圈 API Key 使用。</p>
<div class="home-actions"> <div class="home-actions">
<a class="btn btn-primary" href="{{ current_release.download_url }}">下载客户端</a> <a class="btn btn-primary" href="{{ current_release.download_url }}">下载客户端</a>
{% if current_import_template_download_url %} {% if current_import_template_download_url %}
+1 -1
View File
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}可用模型 - cmhub{% endblock %} {% block title %}可用模型 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<div class="d-flex align-items-center justify-content-between gap-3 mb-4"> <div class="d-flex align-items-center justify-content-between gap-3 mb-4">
+1 -1
View File
@@ -1,7 +1,7 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% load static %} {% load static %}
{% block title %}充值 - cmhub{% endblock %} {% block title %}充值 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<div class="d-flex flex-column gap-4"> <div class="d-flex flex-column gap-4">
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}充值记录 - cmhub{% endblock %} {% block title %}充值记录 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<div class="d-flex flex-column gap-4"> <div class="d-flex flex-column gap-4">
@@ -1,6 +1,6 @@
{% extends "portal/base.html" %} {% extends "portal/base.html" %}
{% block title %}点数记录 - cmhub{% endblock %} {% block title %}点数记录 - 虾皮圈{% endblock %}
{% block content %} {% block content %}
<div class="d-flex flex-column gap-4"> <div class="d-flex flex-column gap-4">
+40 -1
View File
@@ -166,6 +166,13 @@ class PortalAccountFlowTests(TestCase):
html, html,
) )
def assert_portal_branding(self, response):
self.assertContains(response, "虾皮圈")
self.assertNotContains(response, ">cmhub</a>")
self.assertNotContains(response, " - cmhub</title>")
self.assertNotContains(response, "cmhub AI 电商生成台")
self.assertNotContains(response, "cmhub API Key")
def test_signup_rate_limit_is_configured(self): def test_signup_rate_limit_is_configured(self):
self.assertEqual(settings.ACCOUNT_RATE_LIMITS["signup"], "20/m/ip") self.assertEqual(settings.ACCOUNT_RATE_LIMITS["signup"], "20/m/ip")
@@ -273,7 +280,8 @@ class PortalAccountFlowTests(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.resolver_match.url_name, "portal-home") self.assertEqual(response.resolver_match.url_name, "portal-home")
self.assertContains(response, "cmhub AI 电商生成台") self.assertContains(response, "虾皮圈 AI 电商生成台")
self.assert_portal_branding(response)
self.assertContains(response, "注册领 100 点") self.assertContains(response, "注册领 100 点")
self.assertContains(response, "注册送 100 点") self.assertContains(response, "注册送 100 点")
self.assertContains(response, "登录") self.assertContains(response, "登录")
@@ -299,6 +307,37 @@ class PortalAccountFlowTests(TestCase):
self.assertContains(response, "b" * 64) self.assertContains(response, "b" * 64)
self.assertContains(response, "修复下载入口并补充 SHA256") self.assertContains(response, "修复下载入口并补充 SHA256")
self.assertContains(response, "未知发布者") self.assertContains(response, "未知发布者")
self.assertContains(response, "填入虾皮圈 API Key 使用")
self.assertNotContains(response, "填入 cmhub API Key 使用")
def test_portal_pages_use_shopee_circle_branding(self):
user = self.create_verified_user()
UserWallet.objects.create(user=user, points_balance=10)
public_paths = ("/", "/signup", "/login")
for path in public_paths:
with self.subTest(path=path):
response = self.client.get(path)
self.assertEqual(response.status_code, 200)
self.assert_portal_branding(response)
self.client.force_login(user)
authenticated_paths = (
"/dashboard",
"/recharge",
"/apikeys",
"/models",
"/records/recharge",
"/records/usage",
"/logout",
)
for path in authenticated_paths:
with self.subTest(path=path):
response = self.client.get(path)
self.assertEqual(response.status_code, 200)
self.assert_portal_branding(response)
def test_homepage_shows_current_import_template_download_link(self): def test_homepage_shows_current_import_template_download_link(self):
self.create_download_release() self.create_download_release()
+2 -2
View File
@@ -38,7 +38,7 @@
## 当前阶段 ## 当前阶段
当前项目处于:**Phase 6 增强任务推进期**。Phase 2 计费核心已完成到 T-204;Phase 3 已完成 T-301 API Key 鉴权、T-302 生成标题 / 图片接口、T-303 余额查询接口、T-304 充值回调、T-305 扫码充值下单 + 轮询与 T-306 对外 API 安全加固;Phase 4 已完成 T-501 注册 / 登录(allauth)、T-502 API Key 自助管理页、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化;Phase 5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档;Phase 6 已完成 T-601「可用别名发现」、T-602「django-admin 中文化第 1-3 层」、T-603「django-admin 字段级中文化」、T-604「中文敏感词本地过滤」、T-605「免邮箱验证策略落地」、T-606「公开首页 + 客户端下载入口」、T-607「桌面端最新版本检查接口」、T-608「新用户注册赠送 100 点试用点数」、T-609「桌面端版本检查接口增加强制更新标记」与 T-610「首页导入模板下载入口」;T-611「用户端品牌名统一为虾皮圈」已登记为下一项 TODO。生产侧仍需补真实支付回调到账闭环、配置并发布客户端下载包和图片生成真实耗时验证;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。 当前项目处于:**Phase 6 增强任务推进期**。Phase 2 计费核心已完成到 T-204;Phase 3 已完成 T-301 API Key 鉴权、T-302 生成标题 / 图片接口、T-303 余额查询接口、T-304 充值回调、T-305 扫码充值下单 + 轮询与 T-306 对外 API 安全加固;Phase 4 已完成 T-501 注册 / 登录(allauth)、T-502 API Key 自助管理页、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化;Phase 5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档;Phase 6 已完成 T-601「可用别名发现」、T-602「django-admin 中文化第 1-3 层」、T-603「django-admin 字段级中文化」、T-604「中文敏感词本地过滤」、T-605「免邮箱验证策略落地」、T-606「公开首页 + 客户端下载入口」、T-607「桌面端最新版本检查接口」、T-608「新用户注册赠送 100 点试用点数」、T-609「桌面端版本检查接口增加强制更新标记」、T-610「首页导入模板下载入口」与 T-611「用户端品牌名统一为虾皮圈」。生产侧仍需补真实支付回调到账闭环、配置并发布客户端下载包和图片生成真实耗时验证;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。
优先路径: 优先路径:
@@ -48,7 +48,7 @@
4. Phase 3:对外 API 与充值 —— T-301 Key 鉴权、T-302 生成接口、T-303 余额查询、T-304 充值回调、T-305 扫码下单与轮询、T-306 安全加固已完成。 4. Phase 3:对外 API 与充值 —— T-301 Key 鉴权、T-302 生成接口、T-303 余额查询、T-304 充值回调、T-305 扫码下单与轮询、T-306 安全加固已完成。
5. Phase 4:用户端(Django 模板 SSR)—— T-501 注册登录、T-502 API Key 管理、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化已完成。 5. Phase 4:用户端(Django 模板 SSR)—— T-501 注册登录、T-502 API Key 管理、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化已完成。
6. Phase 5:后台与发布 —— T-401 运营后台完善、T-402 完整验收 MVP、T-403 部署 / 运行文档已完成;计划内 MVP 任务已收尾。 6. Phase 5:后台与发布 —— T-401 运营后台完善、T-402 完整验收 MVP、T-403 部署 / 运行文档已完成;计划内 MVP 任务已收尾。
7. Phase 6:增强(MVP 后)—— T-601 可用别名发现已完成,实现 `/api/v1/models` 与 portal 只读「可用模型」页;T-602 已完成 django-admin 分组/表名中文化;T-603 已完成字段级中文标签代码与 no-op 迁移并人工确认 admin 字段中文化;T-604 已完成中文敏感词本地过滤;T-605 已完成免邮箱验证策略落地;T-606 已完成公开首页 + 客户端下载入口;T-607 已完成桌面端最新版本检查接口;T-608 已完成新用户注册赠送 100 点试用点数;T-609 已完成桌面端版本检查接口增加强制更新标记;T-610 已完成首页导入模板下载入口;T-611 已拆为「用户端品牌名统一为虾皮圈」,下一步可领取实现。 7. Phase 6:增强(MVP 后)—— T-601 可用别名发现已完成,实现 `/api/v1/models` 与 portal 只读「可用模型」页;T-602 已完成 django-admin 分组/表名中文化;T-603 已完成字段级中文标签代码与 no-op 迁移并人工确认 admin 字段中文化;T-604 已完成中文敏感词本地过滤;T-605 已完成免邮箱验证策略落地;T-606 已完成公开首页 + 客户端下载入口;T-607 已完成桌面端最新版本检查接口;T-608 已完成新用户注册赠送 100 点试用点数;T-609 已完成桌面端版本检查接口增加强制更新标记;T-610 已完成首页导入模板下载入口;T-611 已完成用户端品牌名统一为虾皮圈。
## 领取任务规则 ## 领取任务规则
+1 -1
View File
@@ -89,7 +89,7 @@
| T-608 | 新用户注册赠送 100 点试用点数 | T-501, T-203, T-401 | 把 2026-07-08 的产品口径落地为账本安全实现。**业务口径**:只对 T-608 上线后的新注册用户自动发放 100 点;历史用户是否补发不在本任务内,需单独审批和批处理任务。**数据与服务**:新增 `PointsLedger.ChangeType.SIGNUP_BONUS`(展示为注册赠点)和 MySQL 兼容的数据库级幂等兜底 `SignupBonusGrant(user UNIQUE)`,不要用 partial unique / 条件唯一约束;新增 `apps.billing.services.grant_signup_bonus(user, points=100)`,在事务内锁/创建钱包、发放点数、写 `PointsLedger(signup_bonus,+100,balance_after,reason)`,重复调用或并发触发不得重复发放。**接入点**:allauth adapter 注册成功后调用 billing 服务,不得在 portal 直接写 `points_balance`;失败要清晰暴露并保持注册 / 账务一致性。**页面与文案**:公开首页、注册页、dashboard/记录页等用户端文案同步「注册送 100 点」;点数记录页能展示注册赠点正向流水;admin 可检索该流水和注册赠点记录。**防刷**:免邮箱验证策略下显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT`(默认 `20/m/ip`),由 allauth signup rate limit 执行;图形验证码 / 人机验证仍作为上线前风控增强项。**测试**:注册后余额为 100 且有一条 `signup_bonus` 流水;重复调用服务不重复加点;并发触发不重复发放;现有用户不会自动补发;dashboard / 点数记录显示一致;`check`/迁移/目标测试通过并在 `../progress.md` 留证据 | DONE | | T-608 | 新用户注册赠送 100 点试用点数 | T-501, T-203, T-401 | 把 2026-07-08 的产品口径落地为账本安全实现。**业务口径**:只对 T-608 上线后的新注册用户自动发放 100 点;历史用户是否补发不在本任务内,需单独审批和批处理任务。**数据与服务**:新增 `PointsLedger.ChangeType.SIGNUP_BONUS`(展示为注册赠点)和 MySQL 兼容的数据库级幂等兜底 `SignupBonusGrant(user UNIQUE)`,不要用 partial unique / 条件唯一约束;新增 `apps.billing.services.grant_signup_bonus(user, points=100)`,在事务内锁/创建钱包、发放点数、写 `PointsLedger(signup_bonus,+100,balance_after,reason)`,重复调用或并发触发不得重复发放。**接入点**:allauth adapter 注册成功后调用 billing 服务,不得在 portal 直接写 `points_balance`;失败要清晰暴露并保持注册 / 账务一致性。**页面与文案**:公开首页、注册页、dashboard/记录页等用户端文案同步「注册送 100 点」;点数记录页能展示注册赠点正向流水;admin 可检索该流水和注册赠点记录。**防刷**:免邮箱验证策略下显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT`(默认 `20/m/ip`),由 allauth signup rate limit 执行;图形验证码 / 人机验证仍作为上线前风控增强项。**测试**:注册后余额为 100 且有一条 `signup_bonus` 流水;重复调用服务不重复加点;并发触发不重复发放;现有用户不会自动补发;dashboard / 点数记录显示一致;`check`/迁移/目标测试通过并在 `../progress.md` 留证据 | DONE |
| T-609 | 桌面端版本检查接口增加强制更新标记 | T-607 | 在 `GET /api/v1/client/releases/latest?platform=windows` 的当前版本响应中,为 `release` 对象新增布尔字段 `force_update`,用于桌面端判断是否必须升级。**接口兼容**:只新增字段,不删除既有 `version` / `download_url` / `sha256` / `release_notes` / `published_at` 字段;无当前版本或无下载地址时仍返回 `release:null`,不返回 `force_update`。**数据来源**:在 `DownloadRelease` 增加 `force_update` 布尔字段,默认 `false`;django-admin 可编辑并在列表展示。**示例**:`{platform:"windows", release:{version:"0.1.1", download_url:"...0.1.1.zip", release_notes:"优化了ai模块的生图的功能", force_update:true}}`。**安全**:接口仍公开匿名只读,不读取用户、不扣点、不暴露后台 ID、本地文件路径或内部状态。**文档**:同步 `api.md`、`routes.md`、`04-architecture.md`、`current-state.md`、版本接口对接文档口径。**测试**:覆盖 `force_update=true` / 默认 `false`、无 current release 不返回该字段、响应字段白名单更新、admin 字段可见;`makemigrations` / `migrate` / `check` / 目标测试通过并在 `../progress.md` 留证据 | DONE | | T-609 | 桌面端版本检查接口增加强制更新标记 | T-607 | 在 `GET /api/v1/client/releases/latest?platform=windows` 的当前版本响应中,为 `release` 对象新增布尔字段 `force_update`,用于桌面端判断是否必须升级。**接口兼容**:只新增字段,不删除既有 `version` / `download_url` / `sha256` / `release_notes` / `published_at` 字段;无当前版本或无下载地址时仍返回 `release:null`,不返回 `force_update`。**数据来源**:在 `DownloadRelease` 增加 `force_update` 布尔字段,默认 `false`;django-admin 可编辑并在列表展示。**示例**:`{platform:"windows", release:{version:"0.1.1", download_url:"...0.1.1.zip", release_notes:"优化了ai模块的生图的功能", force_update:true}}`。**安全**:接口仍公开匿名只读,不读取用户、不扣点、不暴露后台 ID、本地文件路径或内部状态。**文档**:同步 `api.md`、`routes.md`、`04-architecture.md`、`current-state.md`、版本接口对接文档口径。**测试**:覆盖 `force_update=true` / 默认 `false`、无 current release 不返回该字段、响应字段白名单更新、admin 字段可见;`makemigrations` / `migrate` / `check` / 目标测试通过并在 `../progress.md` 留证据 | DONE |
| T-610 | 首页导入模板下载入口 | T-606 | 在公开首页“下载客户端”按钮右侧新增“下载导入模板”链接,让用户下载桌面端导入商品数据使用的 Excel 模板。**产品口径**:模板下载是公开资源,匿名可见;不需要登录、不需要 API Key、不扣点、不占用生成接口限流。**后台配置**:新增独立 `ImportTemplate`(不要复用 `DownloadRelease`,两者生命周期不同),字段建议包含 `name`、`file`(FileField,`MEDIA_ROOT/import_templates/`)、`external_url`(可选,有则优先,后续切 CDN/对象存储)、`sha256`(可选)、`is_current`、`notes`、`created_at`、`updated_at`;admin 可上传/更新模板并标记当前模板;每次保存 current 时把其他 current 置为 false,避免使用 MySQL 不支持的条件唯一约束。**首页行为**:`HomeView` 同时读取 Windows 当前 `DownloadRelease` 和当前 `ImportTemplate`;有当前模板且有可下载地址时,在“下载客户端”右侧展示“下载导入模板”链接;无模板时不显示该链接或显示不可用提示,不能影响客户端下载入口和首页 200。**托管策略**:本地上传模板复用生产 Nginx `/media/` 静态托管,不经 Django/Gunicorn 传大文件;`external_url` 优先于 `file.url`,响应/页面不得暴露本地 `MEDIA_ROOT` 或服务器文件路径。**UI**:保持 T-606 下载区现有布局,桌面端按钮为主按钮,导入模板为次级链接/按钮;移动端需换行不重叠。**文档**:同步 `02-requirements.md`、`04-architecture.md`、`routes.md`、`api.md`、`current-state.md`。**测试**:覆盖首页有模板时展示链接且 href 为绝对/可访问 media URL,`external_url` 优先,本地路径不泄露,无模板时首页正常且不显示错误;admin 字段可见;`makemigrations` / `migrate` / `check` / 目标测试通过并在 `../progress.md` 留证据 | DONE | | T-610 | 首页导入模板下载入口 | T-606 | 在公开首页“下载客户端”按钮右侧新增“下载导入模板”链接,让用户下载桌面端导入商品数据使用的 Excel 模板。**产品口径**:模板下载是公开资源,匿名可见;不需要登录、不需要 API Key、不扣点、不占用生成接口限流。**后台配置**:新增独立 `ImportTemplate`(不要复用 `DownloadRelease`,两者生命周期不同),字段建议包含 `name`、`file`(FileField,`MEDIA_ROOT/import_templates/`)、`external_url`(可选,有则优先,后续切 CDN/对象存储)、`sha256`(可选)、`is_current`、`notes`、`created_at`、`updated_at`;admin 可上传/更新模板并标记当前模板;每次保存 current 时把其他 current 置为 false,避免使用 MySQL 不支持的条件唯一约束。**首页行为**:`HomeView` 同时读取 Windows 当前 `DownloadRelease` 和当前 `ImportTemplate`;有当前模板且有可下载地址时,在“下载客户端”右侧展示“下载导入模板”链接;无模板时不显示该链接或显示不可用提示,不能影响客户端下载入口和首页 200。**托管策略**:本地上传模板复用生产 Nginx `/media/` 静态托管,不经 Django/Gunicorn 传大文件;`external_url` 优先于 `file.url`,响应/页面不得暴露本地 `MEDIA_ROOT` 或服务器文件路径。**UI**:保持 T-606 下载区现有布局,桌面端按钮为主按钮,导入模板为次级链接/按钮;移动端需换行不重叠。**文档**:同步 `02-requirements.md`、`04-architecture.md`、`routes.md`、`api.md`、`current-state.md`。**测试**:覆盖首页有模板时展示链接且 href 为绝对/可访问 media URL,`external_url` 优先,本地路径不泄露,无模板时首页正常且不显示错误;admin 字段可见;`makemigrations` / `migrate` / `check` / 目标测试通过并在 `../progress.md` 留证据 | DONE |
| T-611 | 用户端品牌名统一为“虾皮圈” | T-606 | 把用户端页面上对外展示的项目/产品名从 `cmhub` 统一改为“虾皮圈”。**范围**:只改终端用户可见的 portal 页面文案和浏览器标题,包括公开首页、顶部导航品牌、注册/登录/登出页、控制台、充值、API Key、可用模型、充值记录、点数记录等模板中作为品牌/产品名出现的 `cmhub`;用户端文案里的“cmhub API Key”应改为“虾皮圈 API Key”。**不改**:仓库名、Python 包名、Django app 名、数据库表名、环境变量、API 路径、域名、对外接口字段、后台内部模型名和技术文档里指代服务代号的 `cmhub`。**文档**:同步 `02-requirements.md`、`00-ai-start-here.md`、`current-state.md` 与 `../progress.md`。**测试**:更新 portal 相关断言,覆盖首页展示“虾皮圈”且不再展示旧标题 `cmhub AI 电商生成台`;关键用户端页面渲染不含作为品牌展示的 `cmhub`;`check`、`makemigrations --check --dry-run`、目标 portal 测试通过并在 `../progress.md` 留证据 | TODO | | T-611 | 用户端品牌名统一为“虾皮圈” | T-606 | 把用户端页面上对外展示的项目/产品名从 `cmhub` 统一改为“虾皮圈”。**范围**:只改终端用户可见的 portal 页面文案和浏览器标题,包括公开首页、顶部导航品牌、注册/登录/登出页、控制台、充值、API Key、可用模型、充值记录、点数记录等模板中作为品牌/产品名出现的 `cmhub`;用户端文案里的“cmhub API Key”应改为“虾皮圈 API Key”。**不改**:仓库名、Python 包名、Django app 名、数据库表名、环境变量、API 路径、域名、对外接口字段、后台内部模型名和技术文档里指代服务代号的 `cmhub`。**文档**:同步 `02-requirements.md`、`00-ai-start-here.md`、`current-state.md` 与 `../progress.md`。**测试**:更新 portal 相关断言,覆盖首页展示“虾皮圈”且不再展示旧标题 `cmhub AI 电商生成台`;关键用户端页面渲染不含作为品牌展示的 `cmhub`;`check`、`makemigrations --check --dry-run`、目标 portal 测试通过并在 `../progress.md` 留证据 | DONE |
## 里程碑 ## 里程碑
File diff suppressed because one or more lines are too long
+20 -1
View File
@@ -1595,8 +1595,27 @@
- 用户端文案中的“cmhub API Key”改为“虾皮圈 API Key”。 - 用户端文案中的“cmhub API Key”改为“虾皮圈 API Key”。
- 不改仓库名、Python 包名、Django app 名、数据库表名、环境变量、API 路径、域名、对外接口字段、后台内部模型名和技术文档里作为服务代号的 `cmhub`。 - 不改仓库名、Python 包名、Django app 名、数据库表名、环境变量、API 路径、域名、对外接口字段、后台内部模型名和技术文档里作为服务代号的 `cmhub`。
- 文档变更: - 文档变更:
- `docs/06-tasks.md`:新增 T-611「用户端品牌名统一为虾皮圈」,状态 TODO,并增加 M10 里程碑。 - `docs/06-tasks.md`:新增 T-611「用户端品牌名统一为虾皮圈」,并增加 M10 里程碑。
- `docs/02-requirements.md`:新增 P1 用户端品牌展示需求。 - `docs/02-requirements.md`:新增 P1 用户端品牌展示需求。
- `docs/00-ai-start-here.md`、`docs/current-state.md`:记录 T-611 为下一个可领取任务。 - `docs/00-ai-start-here.md`、`docs/current-state.md`:记录 T-611 为下一个可领取任务。
- 验收口径:更新 portal 相关断言,覆盖首页展示“虾皮圈”且不再展示旧标题 `cmhub AI 电商生成台`;关键用户端页面渲染不含作为品牌展示的 `cmhub`;`check`、`makemigrations --check --dry-run`、目标 portal 测试通过。 - 验收口径:更新 portal 相关断言,覆盖首页展示“虾皮圈”且不再展示旧标题 `cmhub AI 电商生成台`;关键用户端页面渲染不含作为品牌展示的 `cmhub`;`check`、`makemigrations --check --dry-run`、目标 portal 测试通过。
- 下一步:领取 T-611,先搜索 portal 模板与测试里的品牌文案,再做最小范围替换。 - 下一步:领取 T-611,先搜索 portal 模板与测试里的品牌文案,再做最小范围替换。
## 2026-07-08 实施:T-611 用户端品牌名统一为“虾皮圈”
- 状态:DONE。
- 代码变更:
- `apps/portal/templates/portal/base.html`:浏览器默认标题与顶部导航品牌从 `cmhub` 改为“虾皮圈”。
- `apps/portal/templates/portal/home.html`:首页 title、H1 与下载区“cmhub API Key”文案改为“虾皮圈”。
- `apps/portal/templates/account/*.html`、`apps/portal/templates/portal/*.html`:注册、登录、退出、控制台、充值、API Key、可用模型、充值记录、点数记录等页面标题统一为“虾皮圈”。
- `apps/portal/templates/account/email/*`:allauth 邮件模板品牌同步为“虾皮圈”(当前免邮箱验证不会发送,但保留一致性)。
- `apps/portal/tests.py`:新增品牌断言,覆盖公开首页、注册/登录页和登录后的关键用户端页面;保留 CSS 类名、API Key 前缀、mock 支付票据、下载文件名里的内部 `cmhub` 不变。
- 文档变更:
- `docs/06-tasks.md`:T-611 标记为 DONE。
- `docs/00-ai-start-here.md`、`docs/current-state.md`:同步 T-611 已完成与最新验证。
- 验证:
- `py -3.12 manage.py check`:通过,0 issues。
- `py -3.12 manage.py makemigrations --check --dry-run`:通过,No changes detected。
- `git diff --check`:通过,仅 Windows CRLF 提示。
- `py -3.12 manage.py test apps.portal.tests.PortalAccountFlowTests.test_homepage_is_public_and_shows_anonymous_onboarding_without_release apps.portal.tests.PortalAccountFlowTests.test_homepage_shows_current_download_release apps.portal.tests.PortalAccountFlowTests.test_portal_pages_use_shopee_circle_branding --keepdb --noinput --verbosity 2`:通过,3 tests OK。
- 下一步:如需线上生效,部署最新代码到 185.216.248.75 并重启服务;无数据库迁移需要执行。