Open
feat(cloud): 为 db-init 增加可选 ADMIN_TOKEN 保护 (#2) #2
feat(cloud): 为 db-init 增加可选 ADMIN_TOKEN 保护 (#2) #2
Open
雅皮士Add on 9 days ago
Total: 32 files changed+658-90
@@ -13,3 +13,7 @@ dist/
13 13 
14# 日志14# 日志
15*.log15*.log
16+ 
17+# Python
18+__pycache__/
19+*.py[cod]
ALICENSE+21-0
@@ -0,0 +1,21 @@
1+MIT License
2+ 
3+Copyright (c) 2026 Wenhao Jiang
4+ 
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+ 
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+ 
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
MREADME.md+80-6
@@ -70,7 +70,8 @@ Function 执行端点,Function 用 Server SDK(API Key)读写 Database,
70| 项目 | 要求 | 检查或获取方式 |70| 项目 | 要求 | 检查或获取方式 |
71| --- | --- | --- |71| --- | --- | --- |
72| 基础知识 | ArkTS、HTTP、数据库基础 | 可选:HarmonyOS 官方 ArkTS 教程 |72| 基础知识 | ArkTS、HTTP、数据库基础 | 可选:HarmonyOS 官方 ArkTS 教程 |
73-| 开发环境 | Windows/macOS、DevEco Studio、Node.js | `node -v`、DevEco 界面路径 |73+| 开发环境 | Windows/macOS、DevEco Studio、Node.js、Python 3.8+ | `node -v`、`python --version`、DevEco 界面路径 |
74+| Python 依赖 | 无(`deploy.py` 仅用标准库) | 无需 `pip install` |
74| 测试设备 | 模拟器或真机 | `hdc list targets` |75| 测试设备 | 模拟器或真机 | `hdc list targets` |
75| 账号与服务 | 自托管 Appwrite 服务器可达、项目与 API Key 已建 | `GET /v1/health` 返回 `pass` |76| 账号与服务 | 自托管 Appwrite 服务器可达、项目与 API Key 已建 | `GET /v1/health` 返回 `pass` |
76| 权限与网络 | 服务器 80 端口可达;API Key 含 functions/databases 权限 | `GET /v1/functions` 正常返回 |77| 权限与网络 | 服务器 80 端口可达;API Key 含 functions/databases 权限 | `GET /v1/functions` 正常返回 |
@@ -87,7 +88,7 @@ Function 执行端点,Function 用 Server SDK(API Key)读写 Database,
87 88 
88| 占位符 | 含义 | 获取位置 | 安全存放位置 |89| 占位符 | 含义 | 获取位置 | 安全存放位置 |
89| --- | --- | --- | --- |90| --- | --- | --- | --- |
90-| `<appwrite_url>` | 服务器地址 | 服务器 IP + 端口 | 端侧公开配置 |91+| `APPWRITE_HOST` | 服务器地址 | 服务器 IP + 端口 | 端侧公开配置 |
91| `<project_id>` | Appwrite 项目 ID | 控制台 → 项目设置 | 端侧公开配置 |92| `<project_id>` | Appwrite 项目 ID | 控制台 → 项目设置 | 端侧公开配置 |
92| `<api_key>` | 服务器级 API Key | 控制台 → API Keys | 仅函数环境变量 / `.env` |93| `<api_key>` | 服务器级 API Key | 控制台 → API Keys | 仅函数环境变量 / `.env` |
93 94 
@@ -96,12 +97,28 @@ Function 执行端点,Function 用 Server SDK(API Key)读写 Database,
96 97 
97## 3. 快速体验98## 3. 快速体验
98 99 
99-> 这条路线面向「先把现成案例跑起来」的读者,目标是在 10–15 分钟内看到第一个成功结果。原理和完整搭建过程见[完整实践](#4-完整实践)。100+> 这条路线面向「先把现成案例跑起来」的读者,目标是约 1–2 小时(含一次性云环境准备)内看到第一个成功结果。原理和完整搭建过程见[完整实践](#4-完整实践)。
101+ 
102+### 0)用 AI 辅助配置云环境(可选)
103+ 
104+想跳过下面的手动步骤?把本仓库 `README.md` 与 `SKILL.md` 交给 AI 编程助手(码道 / CodeArts、Cursor 等),让它读完自动配置并部署云环境:
105+ 
106+```text
107+请阅读本仓库 README.md 与 SKILL.md,帮我自动配置并部署「单词打卡」云环境:
108+1. 按第 2 章「配置与敏感信息」列出需要我填写的占位符(Appwrite 地址、Project ID、API Key),等我填好 harmony_cloud/.env;
109+2. 运行 deploy/deploy.py 部署 6 个云函数(自动 npm install 并打包 tar.gz);
110+3. 调用 db-init 建集合与种子数据;
111+4. 把服务器地址与 Project ID 填入 HttpUtil.ets,编译并安装端侧;
112+5. 按第 5 章验收表逐项联调。
113+每完成一步报告结果;报错时贴完整日志并定位根因;API Key 只写本地 .env,不写入代码、不提交仓库。
114+```
115+ 
116+> **注意**:AI 只能操作你授权的环境。API Key 等敏感信息请只放在本地 `.env`(已被 `.gitignore` 忽略),不要让 AI 把凭据写进代码或提交。部署完成后,仍建议按下面各步骤的「完成标志」人工复核一遍。
100 117 
101### 1)获取已验证版本118### 1)获取已验证版本
102 119 
103```bash120```bash
104-git clone <repo-url>121+git clone https://gitcode.com/harmony-practice-center/word-check-in.git
105cd word-check-in122cd word-check-in
106```123```
107 124 
@@ -113,7 +130,7 @@ cd word-check-in
113cp harmony_cloud/.env.example harmony_cloud/.env130cp harmony_cloud/.env.example harmony_cloud/.env
114```131```
115 132 
116-1. 将 `.env` 中的 API Key、URL、Project ID 替换为第 2 章收集的值。133+1. 将 `.env` 中的 API Key、APPWRITE_HOST、Project ID 替换为第 2 章收集的值。
1172. 在 `harmony_app/entry/src/main/ets/utils/HttpUtil.ets` 填入 `APPWRITE_HOST` 和 `PROJECT_ID`。1342. 在 `harmony_app/entry/src/main/ets/utils/HttpUtil.ets` 填入 `APPWRITE_HOST` 和 `PROJECT_ID`。
118 135 
119**完成标志**:没有未替换占位符;敏感配置不会出现在 `git status` 中。136**完成标志**:没有未替换占位符;敏感配置不会出现在 `git status` 中。
@@ -129,10 +146,14 @@ curl -X POST http://<host>/v1/functions/db-init/executions \
129 -d '{"body":"{}","async":false}'146 -d '{"body":"{}","async":false}'
130```147```
131 148 
149+> `deploy.py` 会为每个函数自动执行 `npm install --omit=dev` 并打包依赖,无需手动安装 `node-appwrite`。
150+ 
132**完成标志**:`db-init` 执行后,`word_db` 下 3 个集合、58 个单词和管理员 `admin@company.com` / `123456` 已创建。151**完成标志**:`db-init` 执行后,`word_db` 下 3 个集合、58 个单词和管理员 `admin@company.com` / `123456` 已创建。
133 152 
134### 4)构建并运行端侧153### 4)构建并运行端侧
135 154 
155+> 首次编译前,先用 DevEco Studio 打开 `harmony_app` 目录,让它自动生成 `local.properties`(填入 `sdk.dir`);命令行编译还需设置环境变量 `DEVECO_SDK_HOME`。缺失会报 `00303217`,`sdk.dir` 被改写会报 `00308018`,路径含空格会报 `Space is not supported in HVIGOR_USER_HOME`。详见 [SKILL.md](./SKILL.md) 的「全量故障速查表」。
156+ 
136```powershell157```powershell
137Set-Location 'harmony_app'158Set-Location 'harmony_app'
138ohpm install159ohpm install
@@ -146,12 +167,41 @@ hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
146 167 
147> 这条路线面向「理解并复现案例」的读者。步骤按真实工作流排列,每一步都有可观察的完成标志。云函数编写规范、代码模板、打包与排障细节见 [SKILL.md](./SKILL.md)。168> 这条路线面向「理解并复现案例」的读者。步骤按真实工作流排列,每一步都有可观察的完成标志。云函数编写规范、代码模板、打包与排障细节见 [SKILL.md](./SKILL.md)。
148 169 
170+### 一句话让 AI 工作
171+ 
172+不想手动逐项操作?把下面这句话发给码道(华为云 CodeArts 鸿蒙开发智能体,或任意支持 HarmonyOS / Node.js 的 AI 编程助手),即可让它从需求澄清一路推进到端云联调。你也可以把词库规模、打卡规则换成自己的版本。
173+ 
174+```text
175+我想开发一款「单词打卡学习」HarmonyOS 端云一体化应用:端侧 ArkTS/ArkUI(登录、首页、闪卡、测试 4 个页面),云侧 Appwrite 自托管 Functions(Node.js,6 个云函数)+ Appwrite Database(word_db,3 个集合、58 词词库),支持注册登录、每日单词列表、闪卡翻转学习、看词选义测试、进度条与连续打卡。
176+ 
177+请按照标准研发流程推进:先提问澄清需求,再依次产出 requirements.md、design.md、tasks.md;然后分批实现 6 个云函数(注意 ESM 默认导出、node-appwrite v11、execute=["any"])、3 个集合的数据模型和端侧页面;最后给出部署(deploy.py 打包上传)与端云联调验收步骤。
178+ 
179+每一步都要有可观察的完成标志,关键节点停下来等我确认。
180+```
181+ 
182+### 如何指挥 AI 工作
183+ 
184+「一句话」只是开工信号,真正决定质量的是后续每一轮的指挥方式:
185+ 
186+- **一次只给一个明确目标**:每轮指令聚焦单一产出(需求 / 设计 / 任务 / 某一批代码 / 部署),让 AI 给出可观察结果,而不是一次铺开。
187+- **要求可观察的完成标志**:每步都让 AI 明确「做完是什么样子」,你据此判断能否进入下一步。
188+- **关键节点人工确认**:需求澄清、技术选型、Appwrite 配置、部署上线等不可逆或高成本节点,先看 AI 的方案再放行。
189+- **把真实报错带回去**:编译或部署失败时,把完整日志原文贴给 AI 定位,而不是让它凭空猜测。
190+ 
191+下面的步骤 1–5 每一步都附了「推荐指令」,可照此逐条指挥 AI;想对照手动操作时,看同一步骤的「操作」。
192+ 
149### 步骤 1:确认 Appwrite 服务器与收集信息193### 步骤 1:确认 Appwrite 服务器与收集信息
150 194 
151**目标**:确认自托管 Appwrite 可用,收集 Project ID 与 API Key。195**目标**:确认自托管 Appwrite 可用,收集 Project ID 与 API Key。
152 196 
153**为什么这样做**:自托管环境的可用运行时与端口取决于运维配置,先确认能避免后续部署返工。197**为什么这样做**:自托管环境的可用运行时与端口取决于运维配置,先确认能避免后续部署返工。
154 198 
199+**推荐指令**:
200+ 
201+```text
202+请帮我梳理这个案例需要确认的 Appwrite 环境信息:服务器地址、Project ID、API Key(含 functions 读写、databases 读写权限)、可用运行时(node-16.0)。把每项的获取位置和安全存放位置整理成表,并给出 /v1/health、/v1/functions/runtimes 等健康检查与权限验证方式。
203+```
204+ 
155**操作**:205**操作**:
156 206 
1571. 访问 `/v1/health` 确认服务器 `pass`。2071. 访问 `/v1/health` 确认服务器 `pass`。
@@ -159,7 +209,7 @@ hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
1593. 创建 API Key(含 functions.write/read、databases.write/read 权限)。2093. 创建 API Key(含 functions.write/read、databases.write/read 权限)。
1604. 调用 `GET /v1/functions/runtimes` 确认可用运行时(本例 `node-16.0`)。2104. 调用 `GET /v1/functions/runtimes` 确认可用运行时(本例 `node-16.0`)。
161 211 
162-**完成标志**:信息清单填齐,`<appwrite_url>` / `<project_id>` / `<api_key>` 均可用。212+**完成标志**:信息清单填齐,`APPWRITE_HOST` / `<project_id>` / `<api_key>` 均可用。
163 213 
164**如果失败**:`missing scopes (["projects.read"])` 说明 API Key 权限不足,用 `GET /v1/functions` 验证,见[验收与排障](#5-验收与排障)。214**如果失败**:`missing scopes (["projects.read"])` 说明 API Key 权限不足,用 `GET /v1/functions` 验证,见[验收与排障](#5-验收与排障)。
165 215 
@@ -169,6 +219,12 @@ hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
169 219 
170**为什么这样做**:Appwrite v1.9.0 不会自动安装依赖,且函数入口用 ESM 默认导出,写错会导致运行时报错。220**为什么这样做**:Appwrite v1.9.0 不会自动安装依赖,且函数入口用 ESM 默认导出,写错会导致运行时报错。
171 221 
222+**推荐指令**:
223+ 
224+```text
225+请按 Appwrite Functions 编写规范实现 6 个云函数(register、login、getDailyWords、learnWord、getProgress、db-init)。注意:ESM 默认导出、node-appwrite@^11.0.0(Node 16 兼容)、Server SDK 用 API Key 读写数据库、统一 {code,data,msg} 返回。完成后给出每个函数的依赖安装与 tar.gz 打包要求(根目录含 main.js + node_modules)。
226+```
227+ 
172**操作**:228**操作**:
173 229 
1741. 按 [SKILL.md](./SKILL.md) 的「云函数编写规范」与「代码模板」编写 6 个函数。2301. 按 [SKILL.md](./SKILL.md) 的「云函数编写规范」与「代码模板」编写 6 个函数。
@@ -184,6 +240,12 @@ hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
184 240 
185**为什么这样做**:手动路线便于逐项确认权限与运行时,自动路线适合批量复用;两条路线产出相同,交叉创建同名资源会导致冲突。241**为什么这样做**:手动路线便于逐项确认权限与运行时,自动路线适合批量复用;两条路线产出相同,交叉创建同名资源会导致冲突。
186 242 
243+**推荐指令**:
244+ 
245+```text
246+请编写部署脚本 deploy.py(为每个函数执行 npm install --omit=dev 并打包成 tar.gz 上传),并说明 db-init 建集合与种子数据(3 个集合、58 个单词、管理员 admin@company.com / 123456)的执行方式。同时给出为每个函数配置 API_KEY、DATABASE_ID 环境变量与 execute=["any"] 的要点。
247+```
248+ 
187**操作**:249**操作**:
188 250 
1891. 选择一条路线:**手动**在控制台逐项创建,或**自动**用 Python 脚本(见 SKILL 的「部署与打包」)。2511. 选择一条路线:**手动**在控制台逐项创建,或**自动**用 Python 脚本(见 SKILL 的「部署与打包」)。
@@ -201,6 +263,12 @@ hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
201 263 
202**为什么这样做**:端侧通过 `HttpUtil.ets` 指向 Appwrite 执行端点;SDK 版本、工具链路径等环境问题会阻塞编译。264**为什么这样做**:端侧通过 `HttpUtil.ets` 指向 Appwrite 执行端点;SDK 版本、工具链路径等环境问题会阻塞编译。
203 265 
266+**推荐指令**:
267+ 
268+```text
269+请实现端侧 ArkTS 工程:在 HttpUtil.ets 统一配置 APPWRITE_HOST(http:// 协议)与 PROJECT_ID,并确认 functionId 映射与部署一致;4 个页面(登录、首页、闪卡、测试)通过函数执行端点调用云侧。注意配置 ohos.permission.INTERNET 权限;编译前核对 SDK 版本与 DEVECO_SDK_HOME,遇报错先定位根因再做最小修改。
270+```
271+ 
204**操作**:272**操作**:
205 273 
2061. 在 `HttpUtil.ets` 填入 `APPWRITE_HOST`(`http://` 协议)和 `PROJECT_ID`,确认 functionId 映射与部署一致。2741. 在 `HttpUtil.ets` 填入 `APPWRITE_HOST`(`http://` 协议)和 `PROJECT_ID`,确认 functionId 映射与部署一致。
@@ -217,6 +285,12 @@ hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap
217 285 
218**为什么这样做**:这是验证「命令提交成功 ≠ 部署完成」的关键一步,只有实际调用通过才算完成。286**为什么这样做**:这是验证「命令提交成功 ≠ 部署完成」的关键一步,只有实际调用通过才算完成。
219 287 
288+**推荐指令**:
289+ 
290+```text
291+请给我一份端云联调验收清单:逐项列出注册/登录、查看今日单词、闪卡翻转、看词选义测试、打卡状态与连续天数等操作与预期结果。并在模拟器/真机上执行一轮自动测试,逐项记录结果;发现问题先定位相关代码,修复后做针对性回归。
292+```
293+ 
220**操作**:按第 5 章的业务验收表逐项执行。294**操作**:按第 5 章的业务验收表逐项执行。
221 295 
222**完成标志**:第 5 章验收项全部通过,打卡与进度数据正确。296**完成标志**:第 5 章验收项全部通过,打卡与进度数据正确。
@@ -107,7 +107,7 @@ X-Appwrite-Project: {project_id}
107| 3 | **打包格式错误** | `storage_file_type_unsupported` (400) | 传了 `.zip` | 用 Python `tarfile` 打 `.tar.gz` |107| 3 | **打包格式错误** | `storage_file_type_unsupported` (400) | 传了 `.zip` | 用 Python `tarfile` 打 `.tar.gz` |
108| 4 | **依赖未打包** | `Cannot find package 'node-appwrite'` | v1.9.0 不自动 npm install | 部署前 `npm install --omit=dev` |108| 4 | **依赖未打包** | `Cannot find package 'node-appwrite'` | v1.9.0 不自动 npm install | 部署前 `npm install --omit=dev` |
109| 5 | **API Key 权限不足** | `missing scopes (["projects.read"])` | Application 级 Key 无 projects.read | 用 `GET /v1/functions` 验证连通性 |109| 5 | **API Key 权限不足** | `missing scopes (["projects.read"])` | Application 级 Key 无 projects.read | 用 `GET /v1/functions` 验证连通性 |
110-| 6 | **HTTPS 不可用** | 443 超时 | 自托管只开 80 端口 | URL 改用 `http://` |110+| 6 | **HTTPS 不可用** | 443 超时 | 自托管只开 80 端口 | APPWRITE_HOST 改用 `http://` |
111| 7 | **未授权 401** | 前端调用 401 | `execute` 默认不允许匿名 | 显式 `execute=["any"]` |111| 7 | **未授权 401** | 前端调用 401 | `execute` 默认不允许匿名 | 显式 `execute=["any"]` |
112| 8 | **functionId 位置错** | `Param "functionId" is not optional` | 放到了 URL 路径 | 放在创建请求的 body 里 |112| 8 | **functionId 位置错** | `Param "functionId" is not optional` | 放到了 URL 路径 | 放在创建请求的 body 里 |
113| 9 | **responseBody 为空** | 前端拿到空串 | 函数未调用 `res.json()` | 业务结束时 `return res.json(...)` |113| 9 | **responseBody 为空** | 前端拿到空串 | 函数未调用 `res.json()` | 业务结束时 `return res.json(...)` |
@@ -316,7 +316,7 @@ const url = APPWRITE_HOST + '/v1/functions/' + functionId + '/executions';
316## 8. 安全加固316## 8. 安全加固
317 317 
3181. **密码 PBKDF2-SHA256 加盐哈希**(已实现):`register` 存 `password: hashPassword(password, salt)` + `salt`;`login` 用 `user.salt` 重算比对;`db-init` 管理员密码同样哈希。3181. **密码 PBKDF2-SHA256 加盐哈希**(已实现):`register` 存 `password: hashPassword(password, salt)` + `salt`;`login` 用 `user.salt` 重算比对;`db-init` 管理员密码同样哈希。
319-2. **凭据与代码分离**:`.env.example` 只放占位符,真实 API Key / URL / PROJECT_ID 放 git 忽略的 `.env`。319+2. **凭据与代码分离**:`.env.example` 只放占位符,真实 API Key / APPWRITE_HOST / PROJECT_ID 放 git 忽略的 `.env`。
3203. **`execute=["any"]` 是无鉴权公开访问**:`db-init` 也公开可调,任何人可清库重建。生产应改为 `execute=["users"]` 或加应用层鉴权。3203. **`execute=["any"]` 是无鉴权公开访问**:`db-init` 也公开可调,任何人可清库重建。生产应改为 `execute=["users"]` 或加应用层鉴权。
3214. **HTTP 明文传输**:自托管只开 80 端口时,API Key、密码、用户数据都明文传输;生产必须配 HTTPS(TLS 反代)。3214. **HTTP 明文传输**:自托管只开 80 端口时,API Key、密码、用户数据都明文传输;生产必须配 HTTPS(TLS 反代)。
3225. **API Key 泄漏要轮换**:真实 Key 一旦进入过仓库/文档/日志,必须在控制台吊销重发。3225. **API Key 泄漏要轮换**:真实 Key 一旦进入过仓库/文档/日志,必须在控制台吊销重发。
@@ -329,7 +329,7 @@ const url = APPWRITE_HOST + '/v1/functions/' + functionId + '/executions';
329| `Cannot find package 'node-appwrite'` | 云函数 | 依赖未打包 | 部署前 `npm install --omit=dev` |329| `Cannot find package 'node-appwrite'` | 云函数 | 依赖未打包 | 部署前 `npm install --omit=dev` |
330| `storage_file_type_unsupported` (400) | 部署 | 传了 `.zip` | 打 `.tar.gz` |330| `storage_file_type_unsupported` (400) | 部署 | 传了 `.zip` | 打 `.tar.gz` |
331| `missing scopes (["projects.read"])` (401) | 部署 | API Key 权限不足 | 用 `GET /v1/functions` 验证 |331| `missing scopes (["projects.read"])` (401) | 部署 | API Key 权限不足 | 用 `GET /v1/functions` 验证 |
332-| 443 超时 | 网络 | 只开 80 端口 | URL 用 `http://` |332+| 443 超时 | 网络 | 只开 80 端口 | APPWRITE_HOST 用 `http://` |
333| `Param "functionId" is not optional` (400) | 部署 | functionId 放 URL 了 | 放到 body |333| `Param "functionId" is not optional` (400) | 部署 | functionId 放 URL 了 | 放到 body |
334| EBADENGINE / npm 安装失败 | 打包 | Node 16 不兼容 node-appwrite v14 | 降级 `node-appwrite@^11.0.0` |334| EBADENGINE / npm 安装失败 | 打包 | Node 16 不兼容 node-appwrite v14 | 降级 `node-appwrite@^11.0.0` |
335| `export 'Client' not found` | 云函数 | 命名导入不兼容 v11 | 默认导入 `import sdk from 'node-appwrite'` |335| `export 'Client' not found` | 云函数 | 命名导入不兼容 v11 | 默认导入 `import sdk from 'node-appwrite'` |
@@ -0,0 +1,27 @@
1+<svg xmlns="http://www.w3.org/2000/svg" width="2080" height="820" viewBox="0 0 2080 820" role="img" aria-labelledby="title desc">
2+<title id="title">单词打卡学习:端云一体化架构</title><desc id="desc">端侧 ArkUI 页面经 Appwrite Functions 执行端点调用云函数,云函数用 Server SDK 读写 Appwrite Database,端侧不直连数据库。</desc>
3+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="#688f7e"/></marker></defs>
4+<rect width="2080" height="820" rx="28" fill="#f1f6ef"/><g font-family="Microsoft YaHei, Noto Sans SC, sans-serif">
5+<text x="80" y="86" font-size="44" font-weight="700" fill="#243c36">单词打卡学习 · 端云一体化架构</text>
6+<text x="80" y="137" font-size="26" fill="#5b7266">Appwrite 内建 HTTP 路由 + 文档型 NoSQL,省去独立网关层,端侧不直连数据库。</text>
7+<rect x="80" y="230" width="400" height="270" rx="24" fill="#ffffff" stroke="#a6beaa" stroke-width="2"/><rect x="80" y="230" width="400" height="70" rx="24" fill="#355a4b"/><text x="104" y="277" font-size="29" font-weight="700" fill="#fff0ce">端侧 ArkUI</text>
8+<text x="104" y="350" font-size="22" fill="#35564b">登录 / 首页(打卡状态+单词列表)</text>
9+<text x="104" y="402" font-size="22" fill="#35564b">闪卡(翻转查看释义)</text>
10+<text x="104" y="454" font-size="22" fill="#35564b">测试(看词选义+进度条)</text>
11+<path d="M485 367 H535" stroke="#688f7e" stroke-width="4" marker-end="url(#arrow)"/>
12+<rect x="545" y="230" width="400" height="270" rx="24" fill="#ffffff" stroke="#a6beaa" stroke-width="2"/><rect x="545" y="230" width="400" height="70" rx="24" fill="#355a4b"/><text x="569" y="277" font-size="29" font-weight="700" fill="#fff0ce">执行端点</text>
13+<text x="569" y="350" font-size="22" fill="#35564b">POST /v1/functions/{id}/executions</text>
14+<text x="569" y="402" font-size="22" fill="#35564b">execute=["any"] 公开执行</text>
15+<text x="569" y="454" font-size="22" fill="#35564b">responseBody 二次解析</text>
16+<path d="M950 367 H1000" stroke="#688f7e" stroke-width="4" marker-end="url(#arrow)"/>
17+<rect x="1010" y="230" width="400" height="270" rx="24" fill="#ffffff" stroke="#a6beaa" stroke-width="2"/><rect x="1010" y="230" width="400" height="70" rx="24" fill="#355a4b"/><text x="1034" y="277" font-size="29" font-weight="700" fill="#fff0ce">Appwrite Functions</text>
18+<text x="1034" y="350" font-size="22" fill="#35564b">6 个云函数(Node.js 16)</text>
19+<text x="1034" y="402" font-size="22" fill="#35564b">ESM 默认导出 + Server SDK</text>
20+<text x="1034" y="454" font-size="22" fill="#35564b">API Key 读写数据库</text>
21+<path d="M1415 367 H1465" stroke="#688f7e" stroke-width="4" marker-end="url(#arrow)"/>
22+<rect x="1475" y="230" width="400" height="270" rx="24" fill="#ffffff" stroke="#a6beaa" stroke-width="2"/><rect x="1475" y="230" width="400" height="70" rx="24" fill="#355a4b"/><text x="1499" y="277" font-size="29" font-weight="700" fill="#fff0ce">Appwrite Database</text>
23+<text x="1499" y="350" font-size="22" fill="#35564b">3 个集合 / 文档型 NoSQL</text>
24+<text x="1499" y="402" font-size="22" fill="#35564b">users_col / words_col</text>
25+<text x="1499" y="454" font-size="22" fill="#35564b">learn_records_col / 58 词词库</text>
26+<rect x="80" y="583" width="920" height="166" rx="24" fill="#e2ecd9"/><text x="106" y="630" font-size="29" font-weight="700" fill="#35564b">云函数规范输入</text><text x="106" y="682" font-size="26" fill="#35564b">ESM 默认导出 / node-appwrite@^11.0.0 / 统一 {code,data,msg} 返回</text><text x="106" y="723" font-size="26" fill="#35564b">tar.gz 打包上传(根目录含 main.js + node_modules)</text>
27+<rect x="1020" y="583" width="855" height="166" rx="24" fill="#f3ead5"/><text x="1046" y="630" font-size="29" font-weight="700" fill="#665b3c">关键约束</text><text x="1046" y="682" font-size="26" fill="#665b3c">端侧不持有数据库凭据 / 执行端点是唯一入口</text><text x="1046" y="723" font-size="26" fill="#665b3c">自托管无独立网关层 / 命令成功 ≠ 部署完成</text></g></svg>
Acases/case.json+300-0File content is under review, please try again later
@@ -0,0 +1,105 @@
1+ 
2+<h2>快速体验(约 10 分钟)</h2>
3+<blockquote>这条路线面向「先把现成案例跑起来」的读者,目标是约 1–2 小时(含一次性云环境准备)内看到第一个成功结果。原理和完整搭建过程见完整实践。</blockquote>
4+<h3>0)用 AI 辅助配置云环境(可选)</h3>
5+<p>想跳过下面的手动步骤?把本仓库 <code>README.md</code> 与 <code>SKILL.md</code> 交给 AI 编程助手(码道 / CodeArts、Cursor 等),让它读完自动配置并部署云环境:</p>
6+<pre><code>请阅读本仓库 README.md 与 SKILL.md,帮我自动配置并部署「单词打卡」云环境:
7+1. 按第 2 章「配置与敏感信息」列出需要我填写的占位符(Appwrite 地址、Project ID、API Key),等我填好 harmony_cloud/.env;
8+2. 运行 deploy/deploy.py 部署 6 个云函数(自动 npm install 并打包 tar.gz);
9+3. 调用 db-init 建集合与种子数据;
10+4. 把服务器地址与 Project ID 填入 HttpUtil.ets,编译并安装端侧;
11+5. 按第 5 章验收表逐项联调。
12+每完成一步报告结果;报错时贴完整日志并定位根因;API Key 只写本地 .env,不写入代码、不提交仓库。</code></pre>
13+<blockquote><strong>注意</strong>:AI 只能操作你授权的环境。API Key 等敏感信息请只放在本地 <code>.env</code>(已被 <code>.gitignore</code> 忽略),不要让 AI 把凭据写进代码或提交。部署完成后,仍建议按下面各步骤的「完成标志」人工复核一遍。</blockquote>
14+<h3>1)获取已验证版本</h3>
15+<pre><code>git clone https://gitcode.com/harmony-practice-center/word-check-in.git
16+cd word-check-in</code></pre>
17+<p><strong>完成标志</strong>:根目录存在 <code>README.md</code>、<code>harmony_app/</code> 和 <code>harmony_cloud/</code>。</p>
18+<h3>2)准备最小配置</h3>
19+<pre><code>cp harmony_cloud/.env.example harmony_cloud/.env</code></pre>
20+<ol><li>将 <code>.env</code> 中的 API Key、APPWRITE_HOST、Project ID 替换为第 2 章收集的值。</li><li>在 <code>harmony_app/entry/src/main/ets/utils/HttpUtil.ets</code> 填入 <code>APPWRITE_HOST</code> 和 <code>PROJECT_ID</code>。</li></ol>
21+<p><strong>完成标志</strong>:没有未替换占位符;敏感配置不会出现在 <code>git status</code> 中。</p>
22+<h3>3)启动云侧</h3>
23+<pre><code>cd harmony_cloud
24+python deploy/deploy.py
25+curl -X POST http://&lt;host&gt;/v1/functions/db-init/executions \
26+ -H "Content-Type: application/json" \
27+ -H "X-Appwrite-Project: &lt;project_id&gt;" \
28+ -d '{"body":"{}","async":false}'</code></pre>
29+<blockquote><code>deploy.py</code> 会为每个函数自动执行 <code>npm install --omit=dev</code> 并打包依赖,无需手动安装 <code>node-appwrite</code>。</blockquote>
30+<p><strong>完成标志</strong>:<code>db-init</code> 执行后,<code>word_db</code> 下 3 个集合、58 个单词和管理员 <code>admin@company.com</code> / <code>123456</code> 已创建。</p>
31+<h3>4)构建并运行端侧</h3>
32+<blockquote>首次编译前,先用 DevEco Studio 打开 <code>harmony_app</code> 目录,让它自动生成 <code>local.properties</code>(填入 <code>sdk.dir</code>);命令行编译还需设置环境变量 <code>DEVECO_SDK_HOME</code>。缺失会报 <code>00303217</code>,<code>sdk.dir</code> 被改写会报 <code>00308018</code>,路径含空格会报 <code>Space is not supported in HVIGOR_USER_HOME</code>。详见 SKILL.md 的「全量故障速查表」。</blockquote>
33+<pre><code>Set-Location 'harmony_app'
34+ohpm install
35+hvigorw assembleHap --mode module -p module=entry -p product=default -p buildMode=debug --no-daemon
36+hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap</code></pre>
37+<p><strong>完成标志</strong>:生成 HAP 并安装到设备,应用能启动到登录页并完成一次登录。</p>
38+<h2>完整实践</h2>
39+ 
40+<p>目标:复现一款 HarmonyOS 端侧 + Appwrite 自托管 Serverless 云侧的端云一体化单词打卡应用,理解闪卡学习、连续打卡与 NoSQL 文档数据库的核心实现。预计约 120 分钟,不含环境安装、首次下载与签名配置。</p>
41+<h3>1. 确认 Appwrite 服务器与收集信息(约 15 分钟)</h3>
42+<p>访问 /v1/health 确认服务器返回 pass。在控制台创建项目并记录 Project ID,创建含 functions.write/read、databases.write/read 权限的 API Key。调用 GET /v1/functions/runtimes 确认 node-16.0 可用。</p>
43+<p>从 <a href="https://gitcode.com/harmony-practice-center/word-check-in">单词打卡公开仓库</a>获取源码:</p>
44+<pre><code>git clone https://gitcode.com/harmony-practice-center/word-check-in.git
45+cd word-check-in</code></pre>
46+<p>敏感信息只放在本地 .env(已被 .gitignore 忽略),不写入代码、不提交仓库。客户端不得包含 API Key;函数用 Server SDK 在服务端持有。</p>
47+<p><strong>验收:</strong>信息清单填齐,APPWRITE_HOST / Project ID / API Key 均可用;GET /v1/functions 正常返回。</p>
48+<h3>2. 编写并打包 6 个云函数(约 25 分钟)</h3>
49+<p>按 Appwrite Functions 编写规范实现 6 个函数:register、login、getDailyWords、learnWord、getProgress、db-init。</p>
50+<details><summary>查看 Appwrite Functions 编写规范要点</summary><pre><code>// 1. ESM 默认导出:export default async ({ req, res, log, error }) => { ... }
51+// 2. node-appwrite@^11.0.0(Node 16 兼容,v14 要求 Node 18+)
52+// 3. Server SDK 用 API Key 读写数据库:
53+// const client = new Client().setEndpoint(HOST).setProject(PROJECT).setKey(API_KEY)
54+// const db = new Databases(client)
55+// 4. execute=["any"] 允许公开执行(学习演示配置)
56+// 5. 统一返回结构:{ code: 0, data: ..., msg: '...' }
57+// 6. 打包格式:tar.gz(不是 zip),根目录含 main.js + node_modules</code></pre></details>
58+<p>每个函数目录执行 npm install --omit=dev 安装依赖。Appwrite v1.9.0 不会自动安装依赖,必须手动打包进 tar.gz。</p>
59+<p><strong>验收:</strong>6 个函数目录都含 main.js、package.json 和 node_modules/node-appwrite。</p>
60+<h3>3. 部署云侧(约 25 分钟)</h3>
61+<p>运行 deploy.py 为每个函数自动执行 npm install --omit=dev 并打包 tar.gz 上传。为每个函数配置 API_KEY、DATABASE_ID 环境变量并设 execute=["any"]。调用 db-init 建集合与种子数据。</p>
62+<pre><code>cd harmony_cloud
63+python deploy/deploy.py
64+curl -X POST http://<host>/v1/functions/db-init/executions \
65+ -H "Content-Type: application/json" \
66+ -H "X-Appwrite-Project: <project_id>" \
67+ -d '{"body":"{}","async":false}'</code></pre>
68+<p>db-init 执行后创建 3 个集合(users_col / words_col / learn_records_col)、58 个单词和管理员 admin@company.com / 123456。</p>
69+<p>关键理念:"命令提交成功 ≠ 部署完成"。deploy.py 执行成功后需实际调用函数验证返回 code:0。</p>
70+<p><strong>验收:</strong>6 个函数调用全部返回 code:0;word_db 下 3 个集合与 58 个单词就绪;管理员可登录。</p>
71+<h3>4. 配置、编译并安装端侧(约 20 分钟)</h3>
72+<p>在 HttpUtil.ets 填入 APPWRITE_HOST(http:// 协议)和 PROJECT_ID,确认 functionId 映射与部署一致。配置 ohos.permission.INTERNET 权限。</p>
73+<pre><code>cd harmony_app
74+ohpm install
75+hvigorw assembleHap --mode module -p module=entry -p product=default -p buildMode=debug --no-daemon</code></pre>
76+<p>推荐在 DevEco Studio 直接点 Run(自动签名、安装、启动)。命令行需先签名,再用 hdc 安装:</p>
77+<pre><code>hdc install &lt;签名后 HAP&gt;
78+hdc shell aa start -a EntryAbility -b com.example.word_check_in</code></pre>
79+<p><strong>验收:</strong>应用启动后显示登录页,无白屏;用 admin@company.com / 123456 可成功登录。</p>
80+<h3>5. 端云联调验收(约 25 分钟)</h3>
81+<p>按业务验收表逐项执行:</p>
82+<ul>
83+<li>登录 → 进入首页,显示今日打卡状态与连续天数</li>
84+<li>查看今日单词列表 → 首页展示 10 个未学单词</li>
85+<li>闪卡翻转 → 点击卡片翻转查看释义</li>
86+<li>看词选义测试 → 答对计入学习进度,进度条更新</li>
87+<li>学完一个单词 → 打卡状态变为已完成,连续天数累加</li>
88+<li>重启应用 → 进度与打卡数据保留(云端持久化)</li>
89+</ul>
90+<p>重点验证从 responseBody 二次解析的进度与打卡数据正确。端侧调用返回的 JSON 包在 responseBody 字段内,需二次解析才能获取实际数据。</p>
91+<p><strong>验收:</strong>所有业务验收项通过,进度与打卡数据正确,端云链路完整。</p>
92+<h3>6. 关键算法固定样例复核(约 10 分钟)</h3>
93+<p>连续打卡(streak)累加逻辑、学习进度计算等核心业务规则均可复现。用固定输入验证连续天数递增与重置逻辑、学习进度计算是否符合预期。</p>
94+<p>固定样例见 docs/quickstart.md"关键算法固定样例"章节。截图只能证明界面状态,不能替代云函数逻辑与数据库验证;后者由固定样例与端云联调步骤验证。</p>
95+<p><strong>验收:</strong>固定样例的输入输出与预期一致;连续打卡与进度计算逻辑可复现。</p>
96+<h2>高频问题排查</h2><table><thead><tr><th>问题</th><th>优先检查</th><th>解决方向</th></tr></thead><tbody>
97+<tr><td>Runtime "node-18.0" is not supported</td><td>服务器可用运行时列表</td><td>改为 node-16.0,先查 GET /v1/functions/runtimes。</td></tr>
98+<tr><td>Cannot find package 'node-appwrite'</td><td>依赖是否打进 tar.gz</td><td>npm install --omit=dev 后重新打包 tar.gz。</td></tr>
99+<tr><td>storage_file_type_unsupported</td><td>上传格式是否为 tar.gz</td><td>打成 .tar.gz 格式上传,不支持 .zip。</td></tr>
100+<tr><td>前端调用 401</td><td>execute 是否为 ["any"]</td><td>将函数 execute 设为 ["any"] 允许公开执行。</td></tr>
101+<tr><td>missing scopes</td><td>API Key 权限是否完整</td><td>重新创建含 functions/databases 权限的 API Key。</td></tr>
102+<tr><td>EBADENGINE</td><td>node-appwrite 版本是否兼容 Node 16</td><td>降级到 node-appwrite@^11.0.0。</td></tr>
103+</tbody></table>
104+<h2>可选拓展</h2><p>为 execute 接入正式鉴权(改为 ["users"] + 用户会话);为服务器配置 HTTPS 反代(Nginx/Caddy + TLS);db-init 改为幂等可重复执行。以上拓展不包含在基础成果声明中,完成后重新验证功能与安全性。</p>
105+<h2>交付与授权</h2><p>交付可运行工程、6 个云函数 tar.gz、端云联调验收记录与关键算法固定样例复核结果。应用代码按 MIT 许可;第三方依赖按各自许可处理。本案例聚焦自托管 Serverless 学习,基础实现不包含正式鉴权、限流或 HTTPS 配置。</p>
@@ -5,8 +5,9 @@
5 {5 {
6 "name": "default",6 "name": "default",
7 "signingConfig": "default",7 "signingConfig": "default",
8- "targetSdkVersion": "6.1.1(24)",8+ "compileSdkVersion": "6.1.1(24)",
9- "compatibleSdkVersion": "6.1.0(23)",9+ "targetSdkVersion": "6.1.0(23)",
10+ "compatibleSdkVersion": "6.0.0(20)",
10 "runtimeOS": "HarmonyOS",11 "runtimeOS": "HarmonyOS",
11 "buildOption": {12 "buildOption": {
12 "strictMode": {13 "strictMode": {
@@ -1,3 +1,3 @@
1API_KEY=<your_appwrite_api_key>1API_KEY=<your_appwrite_api_key>
2-URL=http://<your_appwrite_host>2+APPWRITE_HOST=http://<your_appwrite_host>
3PROJECT_ID=<your_project_id>3PROJECT_ID=<your_project_id>
@@ -1,4 +1,6 @@
1-# demo007 部署指南(Appwrite Functions 方案)1+# word-check-in 部署指南(Appwrite Functions 方案)
2+ 
3+> **本文为辅助文档,一切以主 [README.md](../README.md) 为准**。若与主 README 冲突,以主 README 为准;本文仅补充手动/自动部署的操作细节。
2 4 
3## 架构5## 架构
4 6 
@@ -31,7 +33,7 @@
31 33 
32### 步骤 1:进入 Appwrite 控制台34### 步骤 1:进入 Appwrite 控制台
33 35 
34-浏览器打开 `https://XXX.XXX.XXX.XXX`,登录进入你的 Project。36+浏览器打开 `http://XXX.XXX.XXX.XXX`,登录进入你的 Project。
35 37 
36### 步骤 2:创建数据库和集合38### 步骤 2:创建数据库和集合
37 39 
@@ -68,37 +70,29 @@
681. **Functions** → **Create Function**701. **Functions** → **Create Function**
692. 填写:712. 填写:
70 - **Name**: 函数名(如 `register`)72 - **Name**: 函数名(如 `register`)
71- - **Runtime**: Node.js 1873+ - **Runtime**: Node.js 16.0
72 - **Execute access**: `All users` 或 `Any`(允许公开调用)74 - **Execute access**: `All users` 或 `Any`(允许公开调用)
733. 创建后,进入 **Settings** → **Environment Variables**,添加:753. 创建后,进入 **Settings** → **Environment Variables**,添加:
74 - `API_KEY` = 你的 Server API Key76 - `API_KEY` = 你的 Server API Key
75 - `DATABASE_ID` = `word_db`77 - `DATABASE_ID` = `word_db`
764. **Deployments** → **Create Deployment**784. **Deployments** → **Create Deployment**
77- - 上传 `functions/{函数名}/` 目录下的 `main.js` + `package.json` 打包的 zip79+ - 上传 `functions/{函数名}/` 目录下的 `main.js` + `package.json` 打包的 tar.gz
78 - **Entrypoint**: `main.js`80 - **Entrypoint**: `main.js`
79 - **Activate**: 勾选81 - **Activate**: 勾选
80 82 
81### 步骤 4:配置前端83### 步骤 4:配置前端
82 84 
83-部署完成后,将每个函数的 ID 填入前端:85+端侧 `harmony_app/entry/src/main/ets/utils/HttpUtil.ets` 已内置短名映射(`getFunctionId()` 直接返回 `register` / `login` / `db-init` / `getDailyWords` / `getProgress` / `learnWord`)。因此**函数的 functionId 必须与这些短名一致**:
84 86 
85-编辑 `harmony_app/entry/src/main/ets/utils/HttpUtil.ets`:87+- 自动部署脚本会以短名作为 functionId,无需额外处理。
88+- 手动在控制台创建函数时,需把函数 ID 设为对应短名;若控制台自动生成了随机 ID,则需同步修改 `HttpUtil.ets` 的 `getFunctionId()`。
86 89 
87-```typescript90+此外还需在 `HttpUtil.ets` 顶部填入 `APPWRITE_HOST`(`http://` 协议)和 `PROJECT_ID`。
88-const FN: Record<string, string> = {
89- register: 'abc123...', // ← 替换为实际 ID
90- login: 'def456...',
91- dbInit: 'ghi789...',
92- getDailyWords: 'jkl012...',
93- getProgress: 'mno345...',
94- learnWord: 'pqr678...',
95-};
96-```
97 91 
98### 步骤 5:初始化数据库92### 步骤 5:初始化数据库
99 93 
100```bash94```bash
101-curl -X POST https://XXX.XXX.XXX.XXX/v1/functions/{dbInit的函数ID}/executions \95+curl -X POST http://XXX.XXX.XXX.XXX/v1/functions/{dbInit的函数ID}/executions \
102 -H "Content-Type: application/json" \96 -H "Content-Type: application/json" \
103 -H "X-Appwrite-Project: <project_id>" \97 -H "X-Appwrite-Project: <project_id>" \
104 -d '{"body":"{}","async":false}'98 -d '{"body":"{}","async":false}'
@@ -120,11 +114,11 @@ python deploy/deploy.py # 完整部署
120python deploy/deploy.py --check # 仅检查连通性114python deploy/deploy.py --check # 仅检查连通性
121```115```
122 116 
123-**需要的环境变量**(自动从 `.env.example` 读取):117+**需要的环境变量**(优先读取 `.env`,不存在则回退 `.env.example`):
124| 变量 | 说明 |118| 变量 | 说明 |
125|------|------|119|------|------|
126| `API_KEY` | Appwrite Server API Key |120| `API_KEY` | Appwrite Server API Key |
127-| `URL` | Appwrite 服务器地址 |121+| `APPWRITE_HOST` | Appwrite 服务器地址 |
128| `PROJECT_ID` | Appwrite Project ID |122| `PROJECT_ID` | Appwrite Project ID |
129 123 
130### 方式 B: Node.js 脚本124### 方式 B: Node.js 脚本
@@ -136,21 +130,21 @@ node deploy.js # 完整部署
136node deploy.js --check # 仅检查连通性130node deploy.js --check # 仅检查连通性
137```131```
138 132 
139-需要 Node.js 18+ 环境。依赖会自动通过 `npm install` 安装。133+`deploy.js` 会为每个函数自动执行 `npm install --omit=dev` 并打包成 `.tar.gz`,函数运行时同样为 `node-16.0`;脚本本身依赖 node-appwrite v14,本地运行需 Node.js 18+。
140 134 
141### 部署成功后的输出示例135### 部署成功后的输出示例
142 136 
143```137```
144══════════════════════════════════138══════════════════════════════════
145- 函数 ID 映射 (复制到 HttpUtil.ets)139+ 函数 ID(functionId 即短名)
146══════════════════════════════════140══════════════════════════════════
147 141 
148- db-init : '6701a3b5c8f2e9d1a4b6',142+ db-init : 'db-init',
149- register : '6701a3b5c8f2e9d1a4b7',143+ register : 'register',
150- login : '6701a3b5c8f2e9d1a4b8',144+ login : 'login',
151- getDailyWords : '6701a3b5c8f2e9d1a4b9',145+ getDailyWords : 'getDailyWords',
152- getProgress : '6701a3b5c8f2e9d1a4c0',146+ getProgress : 'getProgress',
153- learnWord : '6701a3b5c8f2e9d1a4c1',147+ learnWord : 'learnWord',
154 148 
155✅ 部署完成! 6/6 个函数就绪149✅ 部署完成! 6/6 个函数就绪
156```150```
@@ -162,7 +156,7 @@ node deploy.js --check # 仅检查连通性
162所有函数通过统一的执行端点调用:156所有函数通过统一的执行端点调用:
163 157 
164```158```
165-POST https://XXX.XXX.XXX.XXX/v1/functions/{functionId}/executions159+POST http://XXX.XXX.XXX.XXX/v1/functions/{functionId}/executions
166Headers:160Headers:
167 X-Appwrite-Project: <project_id>161 X-Appwrite-Project: <project_id>
168 Content-Type: application/json162 Content-Type: application/json
@@ -193,7 +187,7 @@ Body:
193 187 
194```188```
195API_KEY=<your_api_key>189API_KEY=<your_api_key>
196-URL=http://<your_appwrite_host>190+APPWRITE_HOST=http://<your_appwrite_host>
197PROJECT_ID=<your_project_id>191PROJECT_ID=<your_project_id>
198```192```
199 193 
Mharmony_cloud/deploy/deploy.js+27-23File content is under review, please try again later
@@ -1,7 +1,7 @@
1#!/usr/bin/env python31#!/usr/bin/env python3
2# -*- coding: utf-8 -*-2# -*- coding: utf-8 -*-
3"""3"""
4-demo007 Appwrite Functions automated deployment script4+Appwrite Functions automated deployment script
5 5 
6Usage:6Usage:
7 python deploy.py # Full deployment7 python deploy.py # Full deployment
@@ -16,6 +16,8 @@ import tarfile
16import io16import io
17import urllib.request17import urllib.request
18import urllib.error18import urllib.error
19+import shutil
20+import subprocess
19from pathlib import Path21from pathlib import Path
20 22 
21ROOT = Path(__file__).resolve().parent.parent23ROOT = Path(__file__).resolve().parent.parent
@@ -54,7 +56,7 @@ def load_env(path):
54 56 
55 57 
56def api_request(env, method, path, body=None, headers=None):58def api_request(env, method, path, body=None, headers=None):
57- url = env["URL"].rstrip("/") + path59+ url = env["APPWRITE_HOST"].rstrip("/") + path
58 req_headers = {60 req_headers = {
59 "X-Appwrite-Project": env["PROJECT_ID"],61 "X-Appwrite-Project": env["PROJECT_ID"],
60 "X-Appwrite-Key": env["API_KEY"],62 "X-Appwrite-Key": env["API_KEY"],
@@ -77,7 +79,7 @@ def api_request(env, method, path, body=None, headers=None):
77 79 
78 80 
79def check_connection(env):81def check_connection(env):
80- url = env["URL"].rstrip("/")82+ url = env["APPWRITE_HOST"].rstrip("/")
81 print(f"\n[Check] Appwrite: {url}")83 print(f"\n[Check] Appwrite: {url}")
82 84 
83 # Health check (needs auth headers)85 # Health check (needs auth headers)
@@ -108,7 +110,30 @@ def check_connection(env):
108 return True110 return True
109 111 
110 112 
113+def install_dependencies(func_name):
114+ """Install production dependencies so node-appwrite is bundled into the package."""
115+ func_path = FUNC_DIR / func_name
116+ if not (func_path / "package.json").exists():
117+ return
118+ if shutil.which("npm") is None:
119+ print(f" [WARN] npm not found; dependencies will NOT be bundled")
120+ return
121+ print(f" Installing dependencies (npm install --omit=dev)...")
122+ try:
123+ subprocess.run(
124+ "npm install --omit=dev",
125+ cwd=str(func_path),
126+ shell=True,
127+ check=True,
128+ capture_output=True,
129+ text=True,
130+ )
131+ except subprocess.CalledProcessError as e:
132+ print(f" [WARN] npm install failed: {(e.stderr or e.stdout or '')[:300]}")
133+ 
134+ 
111def create_tar_gz(func_name):135def create_tar_gz(func_name):
136+ install_dependencies(func_name)
112 func_path = FUNC_DIR / func_name137 func_path = FUNC_DIR / func_name
113 tgz_path = DIST_DIR / f"{func_name}.tar.gz"138 tgz_path = DIST_DIR / f"{func_name}.tar.gz"
114 DIST_DIR.mkdir(parents=True, exist_ok=True)139 DIST_DIR.mkdir(parents=True, exist_ok=True)
@@ -167,8 +192,8 @@ def deploy_function(env, func_name, description):
167 print(f" Package: {os.path.basename(tgz_path)}")192 print(f" Package: {os.path.basename(tgz_path)}")
168 193 
169 # 4. Deploy code (multipart/form-data)194 # 4. Deploy code (multipart/form-data)
170- deploy_url = f"{env['URL'].rstrip('/')}/v1/functions/{function_id}/deployments"195+ deploy_url = f"{env['APPWRITE_HOST'].rstrip('/')}/v1/functions/{function_id}/deployments"
171- boundary = "---ZdxDeployBoundary2024"196+ boundary = "---DeployBoundary2024"
172 entrypoint = "main.js"197 entrypoint = "main.js"
173 198 
174 # Build multipart body manually (no external deps needed)199 # Build multipart body manually (no external deps needed)
@@ -219,7 +244,7 @@ def main():
219 args = parser.parse_args()244 args = parser.parse_args()
220 245 
221 print("=" * 50)246 print("=" * 50)
222- print("demo007 - Appwrite Functions Deploy")247+ print("Appwrite Functions Deploy")
223 print("=" * 50)248 print("=" * 50)
224 249 
225 if not ENV_FILE.exists():250 if not ENV_FILE.exists():
@@ -227,7 +252,7 @@ def main():
227 sys.exit(1)252 sys.exit(1)
228 253 
229 env = load_env(ENV_FILE)254 env = load_env(ENV_FILE)
230- print(f"Config: URL={env.get('URL')}, PROJECT={env.get('PROJECT_ID')}")255+ print(f"Config: APPWRITE_HOST={env.get('APPWRITE_HOST')}, PROJECT={env.get('PROJECT_ID')}")
231 256 
232 if not check_connection(env):257 if not check_connection(env):
233 print("\n[FAIL] Appwrite unreachable, aborting")258 print("\n[FAIL] Appwrite unreachable, aborting")
Mharmony_cloud/deploy/package.json+1-1File content is under review, please try again later
Mharmony_cloud/functions/db-init/main.js+13-0File content is under review, please try again later
Mharmony_cloud/functions/db-init/package-lock.json+2-2File content is under review, please try again later
Mharmony_cloud/functions/db-init/package.json+1-1File content is under review, please try again later
Mharmony_cloud/functions/getDailyWords/package-lock.json+2-2File content is under review, please try again later
Mharmony_cloud/functions/getDailyWords/package.json+1-1File content is under review, please try again later
Mharmony_cloud/functions/getProgress/package-lock.json+2-2File content is under review, please try again later
Mharmony_cloud/functions/getProgress/package.json+1-1File content is under review, please try again later
Mharmony_cloud/functions/learnWord/package-lock.json+2-2File content is under review, please try again later
Mharmony_cloud/functions/learnWord/package.json+1-1File content is under review, please try again later
Mharmony_cloud/functions/login/package-lock.json+2-2File content is under review, please try again later
Mharmony_cloud/functions/login/package.json+1-1File content is under review, please try again later
Mharmony_cloud/functions/register/package-lock.json+2-2File content is under review, please try again later
Mharmony_cloud/functions/register/package.json+1-1File content is under review, please try again later