{
  "schemaVersion": "1.0",
  "item": {
    "slug": "service-layer-architecture",
    "name": "Service Layer Architecture",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/wpank/service-layer-architecture",
    "canonicalUrl": "https://clawhub.ai/wpank/service-layer-architecture",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/service-layer-architecture",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=service-layer-architecture",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/service-layer-architecture"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/service-layer-architecture",
    "agentPageUrl": "https://openagent3.xyz/skills/service-layer-architecture/agent",
    "manifestUrl": "https://openagent3.xyz/skills/service-layer-architecture/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/service-layer-architecture/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Service Layer Architecture",
        "body": "Clean, performant API layers with proper separation of concerns and parallel data fetching."
      },
      {
        "title": "When to Use",
        "body": "Building REST APIs with complex data aggregation\nGraphQL resolvers needing data from multiple sources\nAny API where responses combine data from multiple queries\nSystems needing testable, maintainable code"
      },
      {
        "title": "Three-Layer Architecture",
        "body": "┌─────────────────────────────────────────────────────┐\n│  Controllers   │  HTTP handling, validation        │\n├─────────────────────────────────────────────────────┤\n│  Services      │  Business logic, data enrichment  │\n├─────────────────────────────────────────────────────┤\n│  Queries       │  Database access, raw data fetch  │\n└─────────────────────────────────────────────────────┘"
      },
      {
        "title": "Layer 1: Controllers (HTTP Only)",
        "body": "// controllers/Entity.ts\nimport { getEntity, getEntities } from \"../services/Entity\";\n\nconst router = new Router();\n\nrouter.get(\"/entity/:entityId\", async (ctx) => {\n  const { entityId } = ctx.params;\n\n  if (!entityId) {\n    ctx.status = 400;\n    ctx.body = { error: \"Invalid entity ID\" };\n    return;\n  }\n\n  const entity = await getEntity(entityId);\n  \n  if (!entity) {\n    ctx.status = 404;\n    ctx.body = { error: \"Entity not found\" };\n    return;\n  }\n  \n  ctx.status = 200;\n  ctx.body = entity;\n});"
      },
      {
        "title": "Layer 2: Services (Business Logic)",
        "body": "// services/Entity.ts\nimport { queries } from \"@common\";\n\nexport const getEntityData = async (entity: RawEntity): Promise<EnrichedEntity> => {\n  // Parallel fetch all related data\n  const [metadata, score, activity, location] = await Promise.all([\n    queries.getMetadata(),\n    queries.getLatestScore(entity.id),\n    queries.getActivity(entity.id),\n    queries.getLocation(entity.slotId),\n  ]);\n\n  // Transform and combine\n  return {\n    ...entity,\n    bonded: entity.bonded / Math.pow(10, metadata.decimals),\n    total: score?.total ?? 0,\n    location: location?.city,\n    activity: {\n      activeCount: activity?.active?.length ?? 0,\n      inactiveCount: activity?.inactive?.length ?? 0,\n    },\n  };\n};\n\nexport const getEntity = async (entityId: string): Promise<EnrichedEntity | null> => {\n  const entity = await queries.getEntityById(entityId);\n  if (!entity) return null;\n  return getEntityData(entity);\n};\n\nexport const getEntities = async (): Promise<EnrichedEntity[]> => {\n  const all = await queries.allEntities();\n  const enriched = await Promise.all(all.map(getEntityData));\n  return enriched.sort((a, b) => b.total - a.total);\n};"
      },
      {
        "title": "Layer 3: Queries (Database Access)",
        "body": "// queries/Entities.ts\nimport { EntityModel } from \"../models\";\n\nexport const allEntities = async () => {\n  return EntityModel.find({}).lean();  // Always use .lean()\n};\n\nexport const getEntityById = async (id: string) => {\n  return EntityModel.findOne({ id }).lean();\n};\n\nexport const validEntities = async () => {\n  return EntityModel.find({ valid: true }).lean();\n};"
      },
      {
        "title": "Parallel Data Fetching",
        "body": "// BAD: Sequential (slow)\nconst metadata = await queries.getMetadata();\nconst score = await queries.getScore(id);\nconst location = await queries.getLocation(id);\n// Time: sum of all queries\n\n// GOOD: Parallel (fast)\nconst [metadata, score, location] = await Promise.all([\n  queries.getMetadata(),\n  queries.getScore(id),\n  queries.getLocation(id),\n]);\n// Time: max of all queries"
      },
      {
        "title": "Layer Responsibilities",
        "body": "TaskLayerParse request paramsControllerValidate inputControllerSet HTTP statusControllerCombine multiple queriesServiceTransform dataServiceSort/filter resultsServiceRun database queryQuery"
      },
      {
        "title": "Related Skills",
        "body": "Related: postgres-job-queue — Background job processing\nRelated: realtime/websocket-hub-patterns — Real-time updates from services"
      },
      {
        "title": "NEVER Do",
        "body": "NEVER put database queries in controllers — Violates separation\nNEVER put HTTP concerns in services — Services must be reusable\nNEVER fetch related data sequentially — Use Promise.all\nNEVER skip .lean() on read queries — 5-10x faster\nNEVER expose raw database errors — Transform to user-friendly messages"
      }
    ],
    "body": "Service Layer Architecture\n\nClean, performant API layers with proper separation of concerns and parallel data fetching.\n\nWhen to Use\nBuilding REST APIs with complex data aggregation\nGraphQL resolvers needing data from multiple sources\nAny API where responses combine data from multiple queries\nSystems needing testable, maintainable code\nThree-Layer Architecture\n┌─────────────────────────────────────────────────────┐\n│  Controllers   │  HTTP handling, validation        │\n├─────────────────────────────────────────────────────┤\n│  Services      │  Business logic, data enrichment  │\n├─────────────────────────────────────────────────────┤\n│  Queries       │  Database access, raw data fetch  │\n└─────────────────────────────────────────────────────┘\n\nLayer 1: Controllers (HTTP Only)\n// controllers/Entity.ts\nimport { getEntity, getEntities } from \"../services/Entity\";\n\nconst router = new Router();\n\nrouter.get(\"/entity/:entityId\", async (ctx) => {\n  const { entityId } = ctx.params;\n\n  if (!entityId) {\n    ctx.status = 400;\n    ctx.body = { error: \"Invalid entity ID\" };\n    return;\n  }\n\n  const entity = await getEntity(entityId);\n  \n  if (!entity) {\n    ctx.status = 404;\n    ctx.body = { error: \"Entity not found\" };\n    return;\n  }\n  \n  ctx.status = 200;\n  ctx.body = entity;\n});\n\nLayer 2: Services (Business Logic)\n// services/Entity.ts\nimport { queries } from \"@common\";\n\nexport const getEntityData = async (entity: RawEntity): Promise<EnrichedEntity> => {\n  // Parallel fetch all related data\n  const [metadata, score, activity, location] = await Promise.all([\n    queries.getMetadata(),\n    queries.getLatestScore(entity.id),\n    queries.getActivity(entity.id),\n    queries.getLocation(entity.slotId),\n  ]);\n\n  // Transform and combine\n  return {\n    ...entity,\n    bonded: entity.bonded / Math.pow(10, metadata.decimals),\n    total: score?.total ?? 0,\n    location: location?.city,\n    activity: {\n      activeCount: activity?.active?.length ?? 0,\n      inactiveCount: activity?.inactive?.length ?? 0,\n    },\n  };\n};\n\nexport const getEntity = async (entityId: string): Promise<EnrichedEntity | null> => {\n  const entity = await queries.getEntityById(entityId);\n  if (!entity) return null;\n  return getEntityData(entity);\n};\n\nexport const getEntities = async (): Promise<EnrichedEntity[]> => {\n  const all = await queries.allEntities();\n  const enriched = await Promise.all(all.map(getEntityData));\n  return enriched.sort((a, b) => b.total - a.total);\n};\n\nLayer 3: Queries (Database Access)\n// queries/Entities.ts\nimport { EntityModel } from \"../models\";\n\nexport const allEntities = async () => {\n  return EntityModel.find({}).lean();  // Always use .lean()\n};\n\nexport const getEntityById = async (id: string) => {\n  return EntityModel.findOne({ id }).lean();\n};\n\nexport const validEntities = async () => {\n  return EntityModel.find({ valid: true }).lean();\n};\n\nParallel Data Fetching\n// BAD: Sequential (slow)\nconst metadata = await queries.getMetadata();\nconst score = await queries.getScore(id);\nconst location = await queries.getLocation(id);\n// Time: sum of all queries\n\n// GOOD: Parallel (fast)\nconst [metadata, score, location] = await Promise.all([\n  queries.getMetadata(),\n  queries.getScore(id),\n  queries.getLocation(id),\n]);\n// Time: max of all queries\n\nLayer Responsibilities\nTask\tLayer\nParse request params\tController\nValidate input\tController\nSet HTTP status\tController\nCombine multiple queries\tService\nTransform data\tService\nSort/filter results\tService\nRun database query\tQuery\nRelated Skills\nRelated: postgres-job-queue — Background job processing\nRelated: realtime/websocket-hub-patterns — Real-time updates from services\nNEVER Do\nNEVER put database queries in controllers — Violates separation\nNEVER put HTTP concerns in services — Services must be reusable\nNEVER fetch related data sequentially — Use Promise.all\nNEVER skip .lean() on read queries — 5-10x faster\nNEVER expose raw database errors — Transform to user-friendly messages"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/wpank/service-layer-architecture",
    "publisherUrl": "https://clawhub.ai/wpank/service-layer-architecture",
    "owner": "wpank",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/service-layer-architecture",
    "downloadUrl": "https://openagent3.xyz/downloads/service-layer-architecture",
    "agentUrl": "https://openagent3.xyz/skills/service-layer-architecture/agent",
    "manifestUrl": "https://openagent3.xyz/skills/service-layer-architecture/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/service-layer-architecture/agent.md"
  }
}