diff --git a/config/.claude/skills/cloud-functions/SKILL.md b/config/.claude/skills/cloud-functions/SKILL.md index 85a09b70..30e9a2ef 100644 --- a/config/.claude/skills/cloud-functions/SKILL.md +++ b/config/.claude/skills/cloud-functions/SKILL.md @@ -50,6 +50,8 @@ Keep local `references/...` paths for files that ship with the current skill dir - Confusing official CloudBase API client work with building your own HTTP function. - Mixing Event Function code shape (`exports.main(event, context)`) with HTTP Function code shape (`req` / `res` on port `9000`). - Treating HTTP Access as the implementation model for HTTP Functions. HTTP Access is a gateway configuration for Event Functions, not the HTTP Function runtime model. +- Assuming an HTTP Function automatically gets a browser/public URL path, or assuming that path is always `/{functionName}`. +- Writing gateway prefixes such as `/api/httpDemo` into the function router itself. Public gateway path and in-function route path are different layers. - Forgetting that runtime cannot be changed after creation. - Using cloud functions as the first answer for Web login. - Forgetting that HTTP Functions must ship `scf_bootstrap`, listen on port `9000`, and include dependencies. @@ -199,6 +201,8 @@ server.listen(9000); - `manageGateway(action="createAccess")` - If gateway operations need raw cloud API fallback, read `./references/operations-and-config.md` first +When a user says they need browser/public access, do not assume creation already exposed the function. HTTP Function runtime routes still live inside the function, while gateway access adds an external path prefix separately. + ## Related skills - `cloudrun-development` -> container services, long-lived runtimes, Agent hosting diff --git a/config/.claude/skills/cloud-functions/references/http-functions.md b/config/.claude/skills/cloud-functions/references/http-functions.md index 690e33c7..1e26093a 100644 --- a/config/.claude/skills/cloud-functions/references/http-functions.md +++ b/config/.claude/skills/cloud-functions/references/http-functions.md @@ -143,6 +143,29 @@ manageGateway({ }); ``` +### Path mapping model + +Keep the public gateway path and the in-function router path as two different layers. + +- `manageGateway(..., path: "/api/hello")` creates the **external** access prefix. +- Your HTTP Function still matches its own internal routes such as `/`, `/health`, `/users`. +- Do **not** rewrite the function router to include the gateway prefix. + +Example mapping: + +| External URL | Route your HTTP Function should handle | +| --- | --- | +| `https://{domain}/api/hello` | `/` | +| `https://{domain}/api/hello/health` | `/health` | +| `https://{domain}/api/hello/users` | `/users` | + +For example, if you expose `path: "/api/httpDemo"`, the function code should normally keep handlers like `app.get("/")` and `app.get("/health")`. Do not change them to `app.get("/api/httpDemo")` or `app.get("/api/httpDemo/health")`. + +If the external caller reports a 404, verify these two layers separately: + +1. Use `queryGateway(action="getAccess")` to confirm which public path is actually exposed. +2. Check the HTTP Function router to confirm it handles the internal path after the gateway prefix. + Before enabling anonymous access, confirm both of these: 1. The access path exists. diff --git a/config/source/guideline/cloudbase/SKILL.md b/config/source/guideline/cloudbase/SKILL.md index 83428212..54a4d2d6 100644 --- a/config/source/guideline/cloudbase/SKILL.md +++ b/config/source/guideline/cloudbase/SKILL.md @@ -36,6 +36,11 @@ If a skill points to its own `references/...` files, keep following those relati - If the same implementation path fails 2-3 times, stop retrying and reroute. Re-check the selected platform skill, runtime, auth domain, permission model, and SDK boundary before editing more code. - Always specify `EnvId` explicitly in code, configuration, and command examples when initializing CloudBase clients or manager operations. Do not rely on the current CLI-selected environment, implicit defaults, or copied local state. +- For HTTP Functions, keep the public gateway path and the in-function router path as separate layers. Do not write gateway prefixes such as `/api/httpDemo` into the function router itself. +- Creating an HTTP Function does not guarantee a browser/public URL exists. If the task needs external access, create gateway access only when required and confirm the actual exposed path with `queryGateway(action="getAccess")` instead of assuming it is `/{functionName}`. +- If the task explicitly says no HTTP access service is needed, do not create gateway access just to mirror the function name. Keep direct function invocation and gateway routing as separate delivery choices. +- When a gateway path is created later, keep the path mapping separate: a public prefix such as `/api/httpDemo` should still map to in-function routes like `/`, `/health`, and `/users` instead of rewriting handlers to `/api/httpDemo/...`. +- If an external HTTP invocation may be anonymous, or the caller reports `EXCEED_AUTHORITY`, inspect the function permission rule first and only widen access when the product requirement really needs anonymous callers. - Keep scenario-specific pitfall lists in the matching child skills instead of expanding this entry file. ### High-priority routing diff --git a/config/source/skills/SKILL.md b/config/source/skills/SKILL.md index 5b839264..aa67ba93 100644 --- a/config/source/skills/SKILL.md +++ b/config/source/skills/SKILL.md @@ -31,6 +31,7 @@ alwaysApply: true - Web app execution -> `./web-development/SKILL.md` - Web auth provider readiness -> `./auth-tool/SKILL.md` - Web auth implementation -> `./auth-web/SKILL.md` +- Cloud Functions, including HTTP Functions and browser-facing endpoints -> `./cloud-functions/SKILL.md` - Browser-side document database CRUD -> `./no-sql-web-sdk/SKILL.md` - Browser-side file upload -> `./cloud-storage-web/SKILL.md` - Platform overview only when capability selection is still unclear -> `./cloudbase-platform/SKILL.md` @@ -39,6 +40,10 @@ alwaysApply: true - If the same path fails 2-3 times, stop retrying and reroute. Check platform skill, auth domain, runtime, and permission model before editing more code. - Always specify `EnvId` explicitly in code, configuration, and command examples when initializing CloudBase clients or manager operations. Do not rely on the current CLI-selected environment or implicit defaults. +- For HTTP Functions, keep the public gateway path and the in-function router path as separate layers. Do not write prefixes such as `/api/httpDemo` into the router itself; create gateway access separately only when the task actually needs an external path, and verify function permissions before treating the URL as usable. +- HTTP Function path mapping rule: if the public gateway path is `/api/httpDemo`, the function router should still handle `/`, `/health`, `/users` inside the service. Do not rewrite those handlers to `/api/httpDemo`, `/api/httpDemo/health`, or other gateway-prefixed paths. +- HTTP Function delivery rule: creating the function does not guarantee a browser/public URL exists. Confirm the actual exposed path with `queryGateway(action="getAccess")` after creating access, and if the task explicitly says no HTTP access service is needed, do not create gateway access just to mirror the function name. +- HTTP Function permission rule: when the caller may be anonymous, or when external invocation reports `EXCEED_AUTHORITY`, inspect the function rule first and only widen access when the product requirement really needs anonymous callers. ### Do NOT use this as diff --git a/config/source/skills/cloud-functions/SKILL.md b/config/source/skills/cloud-functions/SKILL.md index 85a09b70..30e9a2ef 100644 --- a/config/source/skills/cloud-functions/SKILL.md +++ b/config/source/skills/cloud-functions/SKILL.md @@ -50,6 +50,8 @@ Keep local `references/...` paths for files that ship with the current skill dir - Confusing official CloudBase API client work with building your own HTTP function. - Mixing Event Function code shape (`exports.main(event, context)`) with HTTP Function code shape (`req` / `res` on port `9000`). - Treating HTTP Access as the implementation model for HTTP Functions. HTTP Access is a gateway configuration for Event Functions, not the HTTP Function runtime model. +- Assuming an HTTP Function automatically gets a browser/public URL path, or assuming that path is always `/{functionName}`. +- Writing gateway prefixes such as `/api/httpDemo` into the function router itself. Public gateway path and in-function route path are different layers. - Forgetting that runtime cannot be changed after creation. - Using cloud functions as the first answer for Web login. - Forgetting that HTTP Functions must ship `scf_bootstrap`, listen on port `9000`, and include dependencies. @@ -199,6 +201,8 @@ server.listen(9000); - `manageGateway(action="createAccess")` - If gateway operations need raw cloud API fallback, read `./references/operations-and-config.md` first +When a user says they need browser/public access, do not assume creation already exposed the function. HTTP Function runtime routes still live inside the function, while gateway access adds an external path prefix separately. + ## Related skills - `cloudrun-development` -> container services, long-lived runtimes, Agent hosting diff --git a/config/source/skills/cloud-functions/references/http-functions.md b/config/source/skills/cloud-functions/references/http-functions.md index 690e33c7..1e26093a 100644 --- a/config/source/skills/cloud-functions/references/http-functions.md +++ b/config/source/skills/cloud-functions/references/http-functions.md @@ -143,6 +143,29 @@ manageGateway({ }); ``` +### Path mapping model + +Keep the public gateway path and the in-function router path as two different layers. + +- `manageGateway(..., path: "/api/hello")` creates the **external** access prefix. +- Your HTTP Function still matches its own internal routes such as `/`, `/health`, `/users`. +- Do **not** rewrite the function router to include the gateway prefix. + +Example mapping: + +| External URL | Route your HTTP Function should handle | +| --- | --- | +| `https://{domain}/api/hello` | `/` | +| `https://{domain}/api/hello/health` | `/health` | +| `https://{domain}/api/hello/users` | `/users` | + +For example, if you expose `path: "/api/httpDemo"`, the function code should normally keep handlers like `app.get("/")` and `app.get("/health")`. Do not change them to `app.get("/api/httpDemo")` or `app.get("/api/httpDemo/health")`. + +If the external caller reports a 404, verify these two layers separately: + +1. Use `queryGateway(action="getAccess")` to confirm which public path is actually exposed. +2. Check the HTTP Function router to confirm it handles the internal path after the gateway prefix. + Before enabling anonymous access, confirm both of these: 1. The access path exists. diff --git a/scripts/skills-repo-template/cloudbase-guidelines/SKILL.md b/scripts/skills-repo-template/cloudbase-guidelines/SKILL.md index 049503a3..f346f1df 100644 --- a/scripts/skills-repo-template/cloudbase-guidelines/SKILL.md +++ b/scripts/skills-repo-template/cloudbase-guidelines/SKILL.md @@ -27,6 +27,11 @@ If a skill points to its own `references/...` files, keep following those relati - Use MCP or mcporter first for CloudBase management tasks, and inspect tool schemas before execution. - If the task includes UI, read `ui-design` first and output the design specification before interface code. - If the task includes login, registration, or auth configuration, read `auth-tool` first and enable required providers before frontend implementation. +- For HTTP Functions, keep the public gateway path and the in-function router path as separate layers. Do not write gateway prefixes such as `/api/httpDemo` into the function router itself. +- Creating an HTTP Function does not guarantee a browser/public URL exists. If the task needs external access, create gateway access only when required and confirm the actual exposed path with `queryGateway(action="getAccess")` instead of assuming it is `/{functionName}`. +- If the task explicitly says no HTTP access service is needed, do not create gateway access just to mirror the function name. Keep direct function invocation and gateway routing as separate delivery choices. +- When a gateway path is created later, keep the path mapping separate: a public prefix such as `/api/httpDemo` should still map to in-function routes like `/`, `/health`, and `/users` instead of rewriting handlers to `/api/httpDemo/...`. +- If an external HTTP invocation may be anonymous, or the caller reports `EXCEED_AUTHORITY`, inspect the function permission rule first and only widen access when the product requirement really needs anonymous callers. ### High-priority routing diff --git a/tests/build-allinone-skill.test.js b/tests/build-allinone-skill.test.js index b185b616..fc4d6de8 100644 --- a/tests/build-allinone-skill.test.js +++ b/tests/build-allinone-skill.test.js @@ -92,6 +92,8 @@ test.skipIf(!hasNode24ViaNvm())( expect(mainSkill).toContain('references/auth-web/SKILL.md'); expect(mainSkill).toContain('## Activation Contract'); expect(mainSkill).toContain('Provider status and publishable key'); + expect(mainSkill).toContain('do not create gateway access just to mirror the function name'); + expect(mainSkill).toContain('should still map to in-function routes like `/`, `/health`, and `/users`'); }, ); diff --git a/tests/build-skills-repo.test.js b/tests/build-skills-repo.test.js index 3cfe09cb..de787d2d 100644 --- a/tests/build-skills-repo.test.js +++ b/tests/build-skills-repo.test.js @@ -31,4 +31,11 @@ test('build-skills-repo publishes skills and guideline from minimal sources', () const readme = fs.readFileSync(path.join(OUTPUT_DIR, 'README.md'), 'utf8'); expect(readme).toContain('cloudbase-guidelines'); expect(readme).toContain('auth-web'); + + const guideline = fs.readFileSync( + path.join(OUTPUT_DIR, 'skills', 'cloudbase-guidelines', 'SKILL.md'), + 'utf8', + ); + expect(guideline).toContain('do not create gateway access just to mirror the function name'); + expect(guideline).toContain('should still map to in-function routes like `/`, `/health`, and `/users`'); });