Token导航 LogoToken导航

Agent Skill · 前端设计

customerio-reference-architecture(客户参考架构)

customerio-reference-architecture 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

customerio-reference-architecture 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描有提醒项,按安装量在前端设计类的 10,216 个 Skill 里排第 5,967。

总安装 570周安装 24GitHub Stars 2,066下载 250核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:customerio-reference-architecture(客户参考架构)
来源仓库:https://github.com/jeremylongshore/claude-code-plugins-plus-skills
仓库路径:skills/customerio-reference-architecture
安装命令:
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill customerio-reference-architecture
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill customerio-reference-architecture

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

企业级参考架构设计,分离 Track/App API 关注点并引入事件驱动处理模型。采用服务层封装、仓库模式同步用户数据,并通过 webhook 总线解耦业务逻辑。支持基础设施即代码部署,包含 TMA 传输、共享内存管理和屏障同步细节。实施时建议按业务模块划分服务边界,并为关键路径预留降级容错能力。

customerio-reference-architecture 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/customerio-reference-architecture

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skill…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

customerio-reference-architecture 怎么安装?

在终端执行 npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

customerio-reference-architecture 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

customerio-reference-architecture 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

customerio-reference-architecture 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

customerio-reference-architecture 用的人多吗?

公开数据是累计安装 570 次,近一周安装 24 次,下载 250 次,GitHub 2,066 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

customerio-reference-architecture 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 来源仓库有 2,066 星,维护活跃度相对可查。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
customerio-reference-architecture

客户参考架构 · 本页

5702,066需要联网未明确有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Customer.io Reference Architecture

Overview

Enterprise-grade reference architecture for Customer.io: a service layer separating Track and App API concerns, event-driven processing with message queues, repository pattern for user-to-CIO sync, webhook event bus, and infrastructure as code.

Architecture Principles

  1. Two Clients, Two Concerns — TrackClient for behavioral data in, APIClient for messages out
  2. Event-Driven — Message queues decouple your app from Customer.io API availability
  3. Idempotent Operations — All writes safely retryable via content hashing
  4. Service Layer — Business logic never calls Customer.io SDK directly
  5. Observability — Every operation emits timing and error metrics

Architecture Diagram

┌─────────────┐    ┌───────────────────┐    ┌──────────────┐
│ Application │───>│ MessagingService  │───>│ Track API    │
│ Routes      │    │ (service layer)   │    │ identify()   │
└─────────────┘    │                   │    │ track()      │
                   │ - identify users  │    └──────────────┘
                   │ - track events    │
                   │ - send txn emails │    ┌──────────────┐
                   │                   │───>│ App API      │
                   └───────────────────┘    │ sendEmail()  │
                          │                 │ broadcast()  │
                          │                 └──────────────┘
                          v
                   ┌───────────────────┐
                   │ Event Queue       │    ┌──────────────┐
                   │ (Redis/Kafka)     │───>│ DLQ          │
                   │ for reliability   │    │ (failures)   │
                   └───────────────────┘    └──────────────┘

┌─────────────┐    ┌───────────────────┐    ┌──────────────┐
│ Customer.io │───>│ Webhook Handler   │───>│ BigQuery     │
│ Webhooks    │    │ HMAC verification │    │ (analytics)  │
└─────────────┘    │ Event routing     │    └──────────────┘

Instructions

Step 1: Core Service Layer

// services/messaging-service.ts
import { EventEmitter } from "events";
import { TrackClient, APIClient, SendEmailRequest, RegionUS, RegionEU } from "customerio-node";

interface MessagingConfig {
  siteId: string;
  trackApiKey: string;
  appApiKey: string;
  region: "us" | "eu";
}

export class MessagingService extends EventEmitter {
  private track: TrackClient;
  private app: APIClient;

  constructor(config: MessagingConfig) {
    super();
    const region = config.region === "eu" ? RegionEU : RegionUS;
    this.track = new TrackClient(config.siteId, config.trackApiKey, { region });
    this.app = new APIClient(config.appApiKey, { region });
  }

  async identifyUser(userId: string, attrs: Record<string, any>): Promise<void> {
    const start = Date.now();
    try {
      await this.track.identify(userId, {
        ...attrs,
        last_seen_at: Math.floor(Date.now() / 1000),
      });
      this.emit("identify", { userId, latencyMs: Date.now() - start });
    } catch (err) {
      this.emit("error", { operation: "identify", userId, err });
      throw err;
    }
  }

  async trackEvent(
    userId: string,
    name: string,
    data?: Record<string, any>
  ): Promise<void> {
    const start = Date.now();
    try {
      await this.track.track(userId, { name, data });
      this.emit("track", { userId, name, latencyMs: Date.now() - start });
    } catch (err) {
      this.emit("error", { operation: "track", userId, name, err });
      throw err;
    }
  }

  async sendTransactional(
    to: string,
    templateId: string,
    data: Record<string, any>,
    identifiers?: { id?: string; email?: string }
  ): Promise<{ delivery_id: string }> {
    const start = Date.now();
    try {
      const request = new SendEmailRequest({
        to,
        transactional_message_id: templateId,
        message_data: data,
        identifiers,
      });
      const result = await this.app.sendEmail(request);
      this.emit("transactional", { to, templateId, latencyMs: Date.now() - start });
      return result;
    } catch (err) {
      this.emit("error", { operation: "transactional", to, templateId, err });
      throw err;
    }
  }

  async triggerBroadcast(
    broadcastId: number,
    data: Record<string, any>,
    options: { segment?: { id: number }; emails?: string[]; ids?: string[] }
  ): Promise<void> {
    await this.app.triggerBroadcast(broadcastId, data, options);
    this.emit("broadcast", { broadcastId });
  }

  async suppressUser(userId: string): Promise<void> {
    await this.track.suppress(userId);
  }

  async deleteUser(userId: string): Promise<void> {
    await this.track.destroy(userId);
  }
}

Step 2: Queue-Backed Reliability Layer

// services/messaging-queue.ts
// Wraps MessagingService with queue-based reliability

import { Queue, Worker, Job } from "bullmq";
import { MessagingService } from "./messaging-service";

const REDIS_URL = process.env.REDIS_URL ?? "redis://localhost:6379";

const identifyQueue = new Queue("cio:identify", { connection: { url: REDIS_URL } });
const trackQueue = new Queue("cio:track", { connection: { url: REDIS_URL } });
const transactionalQueue = new Queue("cio:transactional", {
  connection: { url: REDIS_URL },
});

export class QueuedMessagingService {
  constructor(private messaging: MessagingService) {}

  async enqueueIdentify(
    userId: string,
    attrs: Record<string, any>
  ): Promise<void> {
    await identifyQueue.add("identify", { userId, attrs }, {
      attempts: 3,
      backoff: { type: "exponential", delay: 2000 },
    });
  }

  async enqueueTrack(
    userId: string,
    name: string,
    data?: Record<string, any>
  ): Promise<void> {
    await trackQueue.add("track", { userId, name, data }, {
      attempts: 3,
      backoff: { type: "exponential", delay: 2000 },
    });
  }

  startWorkers(): void {
    new Worker("cio:identify", async (job: Job) => {
      await this.messaging.identifyUser(job.data.userId, job.data.attrs);
    }, { connection: { url: REDIS_URL }, concurrency: 10 });

    new Worker("cio:track", async (job: Job) => {
      await this.messaging.trackEvent(
        job.data.userId,
        job.data.name,
        job.data.data
      );
    }, { connection: { url: REDIS_URL }, concurrency: 10 });

    new Worker("cio:transactional", async (job: Job) => {
      await this.messaging.sendTransactional(
        job.data.to,
        job.data.templateId,
        job.data.data,
        job.data.identifiers
      );
    }, { connection: { url: REDIS_URL }, concurrency: 5 });
  }
}

Step 3: Repository Pattern

// repositories/user-messaging-repo.ts
// Syncs your user database with Customer.io profiles

import { MessagingService } from "../services/messaging-service";

interface User {
  id: string;
  email: string;
  firstName: string;
  lastName: string;
  plan: string;
  createdAt: Date;
  preferences: { marketing: boolean; transactional: boolean };
}

export class UserMessagingRepository {
  constructor(private messaging: MessagingService) {}

  async syncUser(user: User): Promise<void> {
    if (!user.preferences.transactional && !user.preferences.marketing) {
      // User has opted out of all messaging — suppress
      await this.messaging.suppressUser(user.id);
      return;
    }

    await this.messaging.identifyUser(user.id, {
      email: user.email,
      first_name: user.firstName,
      last_name: user.lastName,
      plan: user.plan,
      created_at: Math.floor(user.createdAt.getTime() / 1000),
      marketing_opt_in: user.preferences.marketing,
      transactional_opt_in: user.preferences.transactional,
    });
  }

  async onUserDeleted(userId: string): Promise<void> {
    await this.messaging.suppressUser(userId);
    await this.messaging.deleteUser(userId);
  }
}

Step 4: Infrastructure as Code (Terraform)

# terraform/customerio.tf

# Secrets
resource "google_secret_manager_secret" "cio_site_id" {
  secret_id = "customerio-site-id"
  replication { auto {} }
}

resource "google_secret_manager_secret" "cio_track_key" {
  secret_id = "customerio-track-api-key"
  replication { auto {} }
}

resource "google_secret_manager_secret" "cio_app_key" {
  secret_id = "customerio-app-api-key"
  replication { auto {} }
}

# Cloud Run service
resource "google_cloud_run_v2_service" "cio_service" {
  name     = "customerio-service"
  location = "us-central1"

  template {
    scaling {
      min_instance_count = 1
      max_instance_count = 10
    }

    containers {
      image = "gcr.io/${var.project_id}/customerio-service:latest"

      env {
        name  = "CUSTOMERIO_REGION"
        value = "us"
      }

      env {
        name = "CUSTOMERIO_SITE_ID"
        value_source {
          secret_key_ref {
            secret  = google_secret_manager_secret.cio_site_id.secret_id
            version = "latest"
          }
        }
      }

      resources {
        limits = { cpu = "1", memory = "512Mi" }
      }
    }
  }
}

Error Handling

IssueSolution
Queue worker failureBullMQ retries with exponential backoff; check DLQ
Service layer errorEventEmitter "error" event logged + alerted
Secret rotationUpdate Secret Manager version, redeploy
Cross-service consistencyUse idempotent operations (identify is idempotent)

Resources

Next Steps

After implementing architecture, proceed to customerio-multi-env-setup for multi-environment configuration.

平台分布

Codex

33.89%
按下载量换算85

Claude

32.83%
按下载量换算82

Cursor

19.27%
按下载量换算48

Gemini CLI

9.11%
按下载量换算23

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills