[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NQDYRKF89279J9A2D9Q892":3,"skill-same:01M6NQDYRKF89279J9A2D9Q892":79},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":51,"linkOnly":52,"markdownContent":53,"markdownBody":54,"frontMatter":55,"refName":58,"commitSha":59,"skillDirectory":60,"forksCount":14,"repositoryHtmlUrl":61,"repositoryHomepageUrl":62,"ownerHtmlUrl":63,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":64,"install":65,"resources":78},"01M6NQDYRKF89279J9A2D9Q892","backend-integration",null,"Connect the UI to semstreams backend APIs. Covers proxy routing, fetch patterns, SSR considerations, and real-time data. Use when adding new backend integrations or debugging API issues.","C360Studio\u002Fsemteams","C360Studio","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F107274645?v=4","01M6NQ809JZG513TZ7FJX8SAKQ","Complete 360 Studio","01M6NQ80DRB447R1H9W554K7V8",0,"MIT","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fbackend-integration\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50],"backend integration","integration","backend","integrations","new","when","backend integrations","time","patterns","api endpoint","use","fetch","ssr","api","real-time","data","ui","proxy","issues","routing","connect","debugging","2026-11-10 10:12:30",false,"---\nname: backend-integration\ndescription: Connect the UI to semstreams backend APIs. Covers proxy routing, fetch patterns, SSR considerations, and real-time data. Use when adding new backend integrations or debugging API issues.\nargument-hint: [API endpoint or integration being added]\n---\n\n# Backend Integration Guide\n\n## What are you integrating?\n\n$ARGUMENTS\n\n## Architecture\n\nThe UI never talks to the backend directly. All requests go through Caddy at `localhost:3001`:\n\n```\nBrowser --> localhost:3001 (Caddy) --> backend:8080 (Docker)\n                                  --> host.docker.internal:5173 (Vite, for UI assets)\n```\n\n### Caddy Routes (from `Caddyfile.dev`)\n\n| Route            | Destination     | Purpose                 |\n| ---------------- | --------------- | ----------------------- |\n| `\u002Fcomponents\u002F*`  | backend:8080    | Component type registry |\n| `\u002Fflowbuilder\u002F*` | backend:8080    | Flow CRUD operations    |\n| `\u002Fhealth`        | backend:8080    | System health           |\n| `\u002F*`             | Vite dev server | UI assets and pages     |\n\n### SSR Fetch Transform\n\n`src\u002Fhooks.server.ts` transforms fetch URLs during SSR so that server-side rendering can reach the backend via Docker networking (not `localhost`).\n\nWhen adding new backend routes:\n\n1. Add the route to `Caddyfile.dev`\n2. Update `src\u002Fhooks.server.ts` if SSR needs to fetch from this route\n\n## Available Backend APIs\n\n### Component Types\n\n```bash\ncurl -s http:\u002F\u002Flocalhost:3001\u002Fcomponents\u002Ftypes | jq\n```\n\nReturns array of:\n\n```json\n{\n  \"id\": \"udp-input\",\n  \"name\": \"UDP Input\",\n  \"type\": \"input\",\n  \"protocol\": \"udp\",\n  \"category\": \"input\",\n  \"description\": \"Receives UDP packets\",\n  \"schema\": {}\n}\n```\n\n`type`\u002F`category` values: `input`, `processor`, `output`, `storage`, `gateway`\n\n### Flows\n\n```bash\n# List flows\ncurl http:\u002F\u002Flocalhost:3001\u002Fflowbuilder\u002Fflows\n\n# Get flow by ID\ncurl http:\u002F\u002Flocalhost:3001\u002Fflowbuilder\u002Fflows\u002F{id}\n\n# Create\u002Fupdate flow\ncurl -X POST http:\u002F\u002Flocalhost:3001\u002Fflowbuilder\u002Fflows -d '...'\n```\n\n### Health\n\n```bash\ncurl http:\u002F\u002Flocalhost:3001\u002Fhealth\n```\n\n## Fetch Patterns\n\n### From a SvelteKit Load Function (Preferred)\n\n```typescript\n\u002F\u002F src\u002Froutes\u002Fmy-page\u002F+page.ts\nimport type { PageLoad } from \".\u002F$types\";\n\nexport const load: PageLoad = async ({ fetch }) => {\n  const response = await fetch(\"\u002Fcomponents\u002Ftypes\");\n  if (!response.ok) {\n    throw error(response.status, \"Failed to load component types\");\n  }\n  const types = await response.json();\n  return { types };\n};\n```\n\nUse the `fetch` provided by SvelteKit — it handles SSR URL transforms via `hooks.server.ts`.\n\n### From a Component (Client-Side Only)\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { browser } from '$app\u002Fenvironment';\n\n  let data = $state\u003CMyType | null>(null);\n  let error = $state\u003Cstring | null>(null);\n  let loading = $state(false);\n\n  async function loadData() {\n    loading = true;\n    error = null;\n    try {\n      const response = await fetch('\u002Fflowbuilder\u002Fflows');\n      if (!response.ok) throw new Error(`HTTP ${response.status}`);\n      data = await response.json();\n    } catch (e) {\n      error = e instanceof Error ? e.message : 'Unknown error';\n    } finally {\n      loading = false;\n    }\n  }\n\n  \u002F\u002F Only fetch in browser (not SSR)\n  $effect(() => {\n    if (browser) loadData();\n  });\n\u003C\u002Fscript>\n```\n\n### Polling for Real-Time Data\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { browser } from '$app\u002Fenvironment';\n\n  let health = $state\u003CHealthData | null>(null);\n\n  $effect(() => {\n    if (!browser) return;\n\n    const fetchHealth = async () => {\n      try {\n        const res = await fetch('\u002Fhealth');\n        health = await res.json();\n      } catch { \u002F* swallow — will retry on next interval *\u002F }\n    };\n\n    fetchHealth();\n    const interval = setInterval(fetchHealth, 5000);\n    return () => clearInterval(interval);  \u002F\u002F Cleanup\n  });\n\u003C\u002Fscript>\n```\n\n## Adding a New Backend Integration\n\n### Checklist\n\n1. **Verify the endpoint exists**\n\n   ```bash\n   curl -v http:\u002F\u002Flocalhost:3001\u002Fyour\u002Fendpoint\n   ```\n\n2. **Check if Caddy routes it**\n   - Read `Caddyfile.dev` — does it match?\n   - If not, add a route\n\n3. **Check SSR needs**\n   - Will this be called in a `load` function?\n   - If yes, check `src\u002Fhooks.server.ts` handles the URL\n\n4. **Choose fetch pattern**\n   - Page-level data → SvelteKit `load`\n   - Component-level, one-time → `$effect` with `browser` guard\n   - Real-time → `$effect` with `setInterval` and cleanup\n   - User-triggered → event handler with async fetch\n\n5. **Type the response**\n\n   ```typescript\n   interface MyApiResponse {\n     items: Item[];\n     total: number;\n   }\n   ```\n\n6. **Handle states**\n   - Loading state\n   - Error state (network error, HTTP error)\n   - Empty state (valid response, no data)\n\n## Debugging API Issues\n\n```bash\n# Is the backend running?\ndocker compose -f docker-compose.dev.yml ps\n\n# Can we reach it through Caddy?\ncurl -v http:\u002F\u002Flocalhost:3001\u002Fhealth\n\n# Backend logs\ntask dev:backend:logs\n\n# Check Caddy logs\ndocker compose -f docker-compose.dev.yml logs caddy\n\n# Check SSR fetch transforms\ngrep -n \"handle\" src\u002Fhooks.server.ts\n```\n\nCommon issues:\n\n- **404**: Route not in `Caddyfile.dev`\n- **CORS error**: Hitting backend directly (use `:3001` not backend port)\n- **Empty response in SSR**: `hooks.server.ts` not transforming the URL\n- **Connection refused**: Backend not started (`task dev:backend:start`)\n","# Backend Integration Guide\n\n## What are you integrating?\n\n$ARGUMENTS\n\n## Architecture\n\nThe UI never talks to the backend directly. All requests go through Caddy at `localhost:3001`:\n\n```\nBrowser --> localhost:3001 (Caddy) --> backend:8080 (Docker)\n                                  --> host.docker.internal:5173 (Vite, for UI assets)\n```\n\n### Caddy Routes (from `Caddyfile.dev`)\n\n| Route            | Destination     | Purpose                 |\n| ---------------- | --------------- | ----------------------- |\n| `\u002Fcomponents\u002F*`  | backend:8080    | Component type registry |\n| `\u002Fflowbuilder\u002F*` | backend:8080    | Flow CRUD operations    |\n| `\u002Fhealth`        | backend:8080    | System health           |\n| `\u002F*`             | Vite dev server | UI assets and pages     |\n\n### SSR Fetch Transform\n\n`src\u002Fhooks.server.ts` transforms fetch URLs during SSR so that server-side rendering can reach the backend via Docker networking (not `localhost`).\n\nWhen adding new backend routes:\n\n1. Add the route to `Caddyfile.dev`\n2. Update `src\u002Fhooks.server.ts` if SSR needs to fetch from this route\n\n## Available Backend APIs\n\n### Component Types\n\n```bash\ncurl -s http:\u002F\u002Flocalhost:3001\u002Fcomponents\u002Ftypes | jq\n```\n\nReturns array of:\n\n```json\n{\n  \"id\": \"udp-input\",\n  \"name\": \"UDP Input\",\n  \"type\": \"input\",\n  \"protocol\": \"udp\",\n  \"category\": \"input\",\n  \"description\": \"Receives UDP packets\",\n  \"schema\": {}\n}\n```\n\n`type`\u002F`category` values: `input`, `processor`, `output`, `storage`, `gateway`\n\n### Flows\n\n```bash\n# List flows\ncurl http:\u002F\u002Flocalhost:3001\u002Fflowbuilder\u002Fflows\n\n# Get flow by ID\ncurl http:\u002F\u002Flocalhost:3001\u002Fflowbuilder\u002Fflows\u002F{id}\n\n# Create\u002Fupdate flow\ncurl -X POST http:\u002F\u002Flocalhost:3001\u002Fflowbuilder\u002Fflows -d '...'\n```\n\n### Health\n\n```bash\ncurl http:\u002F\u002Flocalhost:3001\u002Fhealth\n```\n\n## Fetch Patterns\n\n### From a SvelteKit Load Function (Preferred)\n\n```typescript\n\u002F\u002F src\u002Froutes\u002Fmy-page\u002F+page.ts\nimport type { PageLoad } from \".\u002F$types\";\n\nexport const load: PageLoad = async ({ fetch }) => {\n  const response = await fetch(\"\u002Fcomponents\u002Ftypes\");\n  if (!response.ok) {\n    throw error(response.status, \"Failed to load component types\");\n  }\n  const types = await response.json();\n  return { types };\n};\n```\n\nUse the `fetch` provided by SvelteKit — it handles SSR URL transforms via `hooks.server.ts`.\n\n### From a Component (Client-Side Only)\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { browser } from '$app\u002Fenvironment';\n\n  let data = $state\u003CMyType | null>(null);\n  let error = $state\u003Cstring | null>(null);\n  let loading = $state(false);\n\n  async function loadData() {\n    loading = true;\n    error = null;\n    try {\n      const response = await fetch('\u002Fflowbuilder\u002Fflows');\n      if (!response.ok) throw new Error(`HTTP ${response.status}`);\n      data = await response.json();\n    } catch (e) {\n      error = e instanceof Error ? e.message : 'Unknown error';\n    } finally {\n      loading = false;\n    }\n  }\n\n  \u002F\u002F Only fetch in browser (not SSR)\n  $effect(() => {\n    if (browser) loadData();\n  });\n\u003C\u002Fscript>\n```\n\n### Polling for Real-Time Data\n\n```svelte\n\u003Cscript lang=\"ts\">\n  import { browser } from '$app\u002Fenvironment';\n\n  let health = $state\u003CHealthData | null>(null);\n\n  $effect(() => {\n    if (!browser) return;\n\n    const fetchHealth = async () => {\n      try {\n        const res = await fetch('\u002Fhealth');\n        health = await res.json();\n      } catch { \u002F* swallow — will retry on next interval *\u002F }\n    };\n\n    fetchHealth();\n    const interval = setInterval(fetchHealth, 5000);\n    return () => clearInterval(interval);  \u002F\u002F Cleanup\n  });\n\u003C\u002Fscript>\n```\n\n## Adding a New Backend Integration\n\n### Checklist\n\n1. **Verify the endpoint exists**\n\n   ```bash\n   curl -v http:\u002F\u002Flocalhost:3001\u002Fyour\u002Fendpoint\n   ```\n\n2. **Check if Caddy routes it**\n   - Read `Caddyfile.dev` — does it match?\n   - If not, add a route\n\n3. **Check SSR needs**\n   - Will this be called in a `load` function?\n   - If yes, check `src\u002Fhooks.server.ts` handles the URL\n\n4. **Choose fetch pattern**\n   - Page-level data → SvelteKit `load`\n   - Component-level, one-time → `$effect` with `browser` guard\n   - Real-time → `$effect` with `setInterval` and cleanup\n   - User-triggered → event handler with async fetch\n\n5. **Type the response**\n\n   ```typescript\n   interface MyApiResponse {\n     items: Item[];\n     total: number;\n   }\n   ```\n\n6. **Handle states**\n   - Loading state\n   - Error state (network error, HTTP error)\n   - Empty state (valid response, no data)\n\n## Debugging API Issues\n\n```bash\n# Is the backend running?\ndocker compose -f docker-compose.dev.yml ps\n\n# Can we reach it through Caddy?\ncurl -v http:\u002F\u002Flocalhost:3001\u002Fhealth\n\n# Backend logs\ntask dev:backend:logs\n\n# Check Caddy logs\ndocker compose -f docker-compose.dev.yml logs caddy\n\n# Check SSR fetch transforms\ngrep -n \"handle\" src\u002Fhooks.server.ts\n```\n\nCommon issues:\n\n- **404**: Route not in `Caddyfile.dev`\n- **CORS error**: Hitting backend directly (use `:3001` not backend port)\n- **Empty response in SSR**: `hooks.server.ts` not transforming the URL\n- **Connection refused**: Backend not started (`task dev:backend:start`)\n",{"name":5,"description":7,"argument-hint":56},[57],"API endpoint or integration being added","main","9b1ec2f24adbbc9121f3d9322f9d414fdc16e016","ui\u002F.claude\u002Fskills\u002Fbackend-integration","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams","https:\u002F\u002Fc360studio.github.io","https:\u002F\u002Fgithub.com\u002FC360Studio","2026-11-11 01:13:46",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":77},[67,70,73],{"tool":68,"command":69},"npx","npx skills add C360Studio\u002Fsemteams --skill backend-integration",{"tool":71,"command":72},"bunx","bunx skills add C360Studio\u002Fsemteams --skill backend-integration",{"tool":74,"command":75},"pnpm","pnpm dlx skills add C360Studio\u002Fsemteams --skill backend-integration","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fbackend-integration\u002FSKILL.md",true,[],[80,103,120,131,150,157],{"skillNo":81,"name":82,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":86,"publishedAt":51},"01M6NQEE3V8S4HEVMFVFW7SEQ4","store-pattern","Choose the right state management approach for a use case. Decide between component-local state, derived state, runes-based stores, SvelteKit load, or URL state.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fstore-pattern\u002FSKILL.md",[],[87,88,89,90,91,92,93,94,95,96,39,97,98,99,100,101,102],"store pattern","store","pattern","decide","component","state management","state","sveltekit","choose","management","local","case","URL","load","for","managed",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":51},"01M6NQE4Z802R8B8PBE23JRR5W","new-component","Step-by-step checklist for adding a new Svelte 5 component with proper patterns, tests, and TypeScript types. Use when creating new UI components.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002Fui\u002F.claude\u002Fskills\u002Fnew-component\u002FSKILL.md",[],[91,33,110,111,112,113,101,34,114,115,116,45,39,117,118,37,119],"new component","ui components","types","with","tests","typescript","components","svelte 5","checklist","svelte",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":126,"publishedAt":51},"01M6NQDW39CHJMCCQZA696N1Y7","review-pr","Adapter for review-pr.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Freview-pr\u002FSKILL.md",[],[127,128,129,130,101,122],"pr","review pr","review","adapter",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":140,"publishedAt":51},"01M6NQD8CX3BCRHN8BRFTVJJ01","query-pattern","Choose the right query access pattern (GraphQL, MCP, NATS Direct) for a use case. Use when designing query APIs, adding new access points, or choosing between gateway types.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fquery-pattern\u002FSKILL.md",[137],{"categoryNo":138,"categoryName":139,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[141,89,142,39,95,143,98,112,101,144,34,33,145,146,147,148,149],"query pattern","query","scenario","direct","access","GraphQL","gateway","nats","MCP",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":51},"01M6NQD73AJADQC2G9005KPNPN","preflight","Adapter for preflight.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fpreflight\u002FSKILL.md",[],[152,101,130],{"skillNo":158,"name":159,"nameZh":6,"description":160,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":161,"categories":162,"keywords":163,"publishedAt":51},"01M6NQD3GNDS4XGY991BWD9NP4","ponytail","Adapter for ponytail.","https:\u002F\u002Fgithub.com\u002FC360Studio\u002Fsemteams\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fponytail\u002FSKILL.md",[],[159,101,130]]