cross-context

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cross-Context Skill

跨上下文技能

觸發時機

触发时机

  • analyze-frame 識別出
    cross_context_dependencies
  • 需求涉及多個 Bounded Context 的協作
  • 設計 Anti-Corruption Layer (ACL) 時
  • 定義 Context Mapping 策略時
  • 当analyze-frame识别出
    cross_context_dependencies
  • 需求涉及多个Bounded Context的协作
  • 设计Anti-Corruption Layer (ACL)时
  • 定义Context Mapping策略时

核心任務

核心任务

  1. 識別跨 BC 依賴的類型與方向
  2. 設計適當的整合模式 (ACL, Open Host, Shared Kernel, etc.)
  3. 定義跨 BC 的契約規格
  4. 確保當前 BC 不被外部 BC 污染

  1. 识别跨BC依赖的类型与方向
  2. 设计合适的整合模式 (ACL, Open Host, Shared Kernel, etc.)
  3. 定义跨BC的契约规格
  4. 确保当前BC不被外部BC污染

Context Mapping 模式

Context Mapping 模式

上游/下游關係

上游/下游关系

模式說明適用場景
Customer-Supplier下游需求驅動上游開發緊密合作的團隊
Conformist下游完全遵循上游模型無法影響上游時
Anti-Corruption Layer下游建立隔離層保護自身模型
Open Host Service上游提供標準化 API多下游消費者
Published Language共享交換格式跨組織整合
模式说明适用场景
Customer-Supplier下游需求驱动上游开发紧密合作的团队
Conformist下游完全遵循上游模型无法影响上游时
Anti-Corruption Layer下游建立隔离层保护自身模型
Open Host Service上游提供标准化API多下游消费者
Published Language共享交换格式跨组织整合

對等關係

对等关系

模式說明適用場景
Shared Kernel共享部分模型高度協作
Partnership雙方共同演進緊密合作
Separate Ways完全獨立無需整合

模式说明适用场景
Shared Kernel共享部分模型高度协作
Partnership双方共同演进紧密合作
Separate Ways完全独立无需整合

cross-context/{context-name}.yaml 格式

cross-context/{context-name}.yaml 格式

yaml
undefined
yaml
undefined

docs/specs/{feature-name}/cross-context/{context-name}.yaml

docs/specs/{feature-name}/cross-context/{context-name}.yaml

cross_context: id: XC1 name: "Authorization"

---------------------------------------------------------------------------

Context 關係

---------------------------------------------------------------------------

relationship: source_context: "AccessControl" # 提供服務的 BC target_context: "WorkflowManagement" # 當前 BC direction: "upstream-downstream" # | symmetric | separate pattern: "AntiCorruptionLayer" # | Conformist | OpenHostService | SharedKernel

---------------------------------------------------------------------------

介面契約(需求層:只描述「需要什麼」)

---------------------------------------------------------------------------

required_capability: name: "AuthorizationCheck" description: | Check if the operator has permission to perform the action on the resource.
# 這是「需求」,不是「實作」
operations:
  - name: "canExecute"
    input:
      - name: "operatorId"
        type: "string"
        description: "The ID of the operator"
      - name: "action"
        type: "string"
        description: "The action to perform (e.g., 'create', 'update', 'delete')"
      - name: "resourceType"
        type: "string"
        description: "The type of resource (e.g., 'Workflow', 'Board')"
      - name: "resourceId"
        type: "string"
        description: "The ID of the resource"
    output:
      type: "boolean"
      description: "true if authorized, false otherwise"
    
    # Design by Contract
    pre_conditions:
      - "operatorId must not be empty"
      - "action must be a valid action type"
    post_conditions:
      - "returns true or false, never throws for authorization check"
    
    # 異常情況
    errors:
      - name: "OperatorNotFoundError"
        when: "operatorId does not exist"

---------------------------------------------------------------------------

ACL 設計(實作層)

---------------------------------------------------------------------------

acl_design: adapter_interface: name: "AuthorizationService" location: "src/domain/services/"
adapter_implementation:
  name: "AccessControlAuthorizationAdapter"
  location: "src/infrastructure/acl/"
  
# 模型轉換
translation:
  - source_model: "AccessControl.Permission"
    target_model: "WorkflowManagement.AuthorizationResult"
    mapping: |
      Permission.isGranted → AuthorizationResult.authorized
      Permission.denialReason → AuthorizationResult.reason

---------------------------------------------------------------------------

容錯策略

---------------------------------------------------------------------------

fault_tolerance: timeout: "3s" retry: max_attempts: 3 backoff: "exponential" fallback: strategy: "deny-by-default" # | allow-by-default | cached description: "If authorization service is unavailable, deny the request" circuit_breaker: enabled: true failure_threshold: 5 reset_timeout: "30s"

---------------------------------------------------------------------------

可追溯性

---------------------------------------------------------------------------

satisfied_by: - machine/controller.yaml#authorization_check - "src/infrastructure/acl/AccessControlAuthorizationAdapter.ts"
validates_concerns: - FC1 # 若有 Frame Concern 與權限相關

---
cross_context: id: XC1 name: "Authorization"

---------------------------------------------------------------------------

Context 关系

---------------------------------------------------------------------------

relationship: source_context: "AccessControl" # 提供服务的BC target_context: "WorkflowManagement" # 当前BC direction: "upstream-downstream" # | symmetric | separate pattern: "AntiCorruptionLayer" # | Conformist | OpenHostService | SharedKernel

---------------------------------------------------------------------------

接口契约(需求层:只描述「需要什么」)

---------------------------------------------------------------------------

required_capability: name: "AuthorizationCheck" description: | Check if the operator has permission to perform the action on the resource.
# 这是「需求」,不是「实现」
operations:
  - name: "canExecute"
    input:
      - name: "operatorId"
        type: "string"
        description: "The ID of the operator"
      - name: "action"
        type: "string"
        description: "The action to perform (e.g., 'create', 'update', 'delete')"
      - name: "resourceType"
        type: "string"
        description: "The type of resource (e.g., 'Workflow', 'Board')"
      - name: "resourceId"
        type: "string"
        description: "The ID of the resource"
    output:
      type: "boolean"
      description: "true if authorized, false otherwise"
    
    # Design by Contract
    pre_conditions:
      - "operatorId must not be empty"
      - "action must be a valid action type"
    post_conditions:
      - "returns true or false, never throws for authorization check"
    
    # 异常情况
    errors:
      - name: "OperatorNotFoundError"
        when: "operatorId does not exist"

---------------------------------------------------------------------------

ACL 设计(实现层)

---------------------------------------------------------------------------

acl_design: adapter_interface: name: "AuthorizationService" location: "src/domain/services/"
adapter_implementation:
  name: "AccessControlAuthorizationAdapter"
  location: "src/infrastructure/acl/"
  
# 模型转换
translation:
  - source_model: "AccessControl.Permission"
    target_model: "WorkflowManagement.AuthorizationResult"
    mapping: |
      Permission.isGranted → AuthorizationResult.authorized
      Permission.denialReason → AuthorizationResult.reason

---------------------------------------------------------------------------

容错策略

---------------------------------------------------------------------------

fault_tolerance: timeout: "3s" retry: max_attempts: 3 backoff: "exponential" fallback: strategy: "deny-by-default" # | allow-by-default | cached description: "If authorization service is unavailable, deny the request" circuit_breaker: enabled: true failure_threshold: 5 reset_timeout: "30s"

---------------------------------------------------------------------------

可追溯性

---------------------------------------------------------------------------

satisfied_by: - machine/controller.yaml#authorization_check - "src/infrastructure/acl/AccessControlAuthorizationAdapter.ts"
validates_concerns: - FC1 # 若有Frame Concern与权限相关

---

TypeScript 範例

TypeScript 示例

Domain Service Interface (在 Domain 層)

领域服务接口(Domain层)

typescript
// src/domain/services/AuthorizationService.ts

/**
 * Authorization Service Interface
 * 
 * 這是 Domain 層的介面,不依賴任何外部實作
 * Anti-Corruption Layer 的入口點
 */
export interface AuthorizationService {
  /**
   * Check if the operator can execute the action
   * 
   * @pre operatorId must not be empty
   * @pre action must be a valid action type
   * @post returns AuthorizationResult, never throws for check
   */
  canExecute(
    operatorId: string,
    action: ActionType,
    resourceType: ResourceType,
    resourceId: string
  ): Promise<AuthorizationResult>;
}

export interface AuthorizationResult {
  readonly authorized: boolean;
  readonly reason?: string;
}

export type ActionType = 'create' | 'read' | 'update' | 'delete';
export type ResourceType = 'Workflow' | 'Board' | 'Stage' | 'SwimLane';
typescript
// src/domain/services/AuthorizationService.ts

/**
 * Authorization Service Interface
 * 
 * 这是Domain层的接口,不依赖任何外部实现
 * Anti-Corruption Layer的入口点
 */
export interface AuthorizationService {
  /**
   * Check if the operator can execute the action
   * 
   * @pre operatorId must not be empty
   * @pre action must be a valid action type
   * @post returns AuthorizationResult, never throws for check
   */
  canExecute(
    operatorId: string,
    action: ActionType,
    resourceType: ResourceType,
    resourceId: string
  ): Promise<AuthorizationResult>;
}

export interface AuthorizationResult {
  readonly authorized: boolean;
  readonly reason?: string;
}

export type ActionType = 'create' | 'read' | 'update' | 'delete';
export type ResourceType = 'Workflow' | 'Board' | 'Stage' | 'SwimLane';

ACL Adapter (在 Infrastructure 層)

ACL适配器(Infrastructure层)

typescript
// src/infrastructure/acl/AccessControlAuthorizationAdapter.ts

import { AuthorizationService, AuthorizationResult, ActionType, ResourceType } 
  from '../../domain/services/AuthorizationService';
import { AccessControlClient } from '../clients/AccessControlClient';
import { CircuitBreaker } from '../resilience/CircuitBreaker';

/**
 * Anti-Corruption Layer Adapter
 * 
 * 將 AccessControl BC 的模型轉換為當前 BC 的模型
 * 包含容錯策略:timeout, retry, circuit breaker
 */
export class AccessControlAuthorizationAdapter implements AuthorizationService {
  constructor(
    private readonly client: AccessControlClient,
    private readonly circuitBreaker: CircuitBreaker,
  ) {}

  async canExecute(
    operatorId: string,
    action: ActionType,
    resourceType: ResourceType,
    resourceId: string
  ): Promise<AuthorizationResult> {
    // ===== Pre-conditions =====
    if (!operatorId) {
      throw new Error('operatorId must not be empty');
    }

    try {
      // 透過 Circuit Breaker 呼叫外部服務
      const permission = await this.circuitBreaker.execute(
        () => this.client.checkPermission({
          userId: operatorId,
          action: this.mapAction(action),
          resource: `${resourceType}:${resourceId}`,
        }),
        {
          timeout: 3000,
          fallback: () => ({ isGranted: false, denialReason: 'Service unavailable' }),
        }
      );

      // ===== Model Translation (ACL 核心) =====
      return this.translateToAuthorizationResult(permission);

    } catch (error) {
      // Fallback: deny by default
      return {
        authorized: false,
        reason: 'Authorization service unavailable',
      };
    }
  }

  /**
   * 模型轉換:將外部 BC 的 Permission 轉換為當前 BC 的 AuthorizationResult
   */
  private translateToAuthorizationResult(
    permission: ExternalPermission
  ): AuthorizationResult {
    return {
      authorized: permission.isGranted,
      reason: permission.denialReason,
    };
  }

  private mapAction(action: ActionType): string {
    // 若外部 BC 使用不同的 action 命名,在此轉換
    const mapping: Record<ActionType, string> = {
      create: 'CREATE',
      read: 'READ',
      update: 'UPDATE',
      delete: 'DELETE',
    };
    return mapping[action];
  }
}

typescript
// src/infrastructure/acl/AccessControlAuthorizationAdapter.ts

import { AuthorizationService, AuthorizationResult, ActionType, ResourceType } 
  from '../../domain/services/AuthorizationService';
import { AccessControlClient } from '../clients/AccessControlClient';
import { CircuitBreaker } from '../resilience/CircuitBreaker';

/**
 * Anti-Corruption Layer Adapter
 * 
 * 将AccessControl BC的模型转换为当前BC的模型
 * 包含容错策略:timeout, retry, circuit breaker
 */
export class AccessControlAuthorizationAdapter implements AuthorizationService {
  constructor(
    private readonly client: AccessControlClient,
    private readonly circuitBreaker: CircuitBreaker,
  ) {}

  async canExecute(
    operatorId: string,
    action: ActionType,
    resourceType: ResourceType,
    resourceId: string
  ): Promise<AuthorizationResult> {
    // ===== 前置条件 =====
    if (!operatorId) {
      throw new Error('operatorId must not be empty');
    }

    try {
      // 通过Circuit Breaker调用外部服务
      const permission = await this.circuitBreaker.execute(
        () => this.client.checkPermission({
          userId: operatorId,
          action: this.mapAction(action),
          resource: `${resourceType}:${resourceId}`,
        }),
        {
          timeout: 3000,
          fallback: () => ({ isGranted: false, denialReason: 'Service unavailable' }),
        }
      );

      // ===== 模型转换(ACL核心)=====
      return this.translateToAuthorizationResult(permission);

    } catch (error) {
      // 降级策略:默认拒绝
      return {
        authorized: false,
        reason: 'Authorization service unavailable',
      };
    }
  }

  /**
   * 模型转换:将外部BC的Permission转换为当前BC的AuthorizationResult
   */
  private translateToAuthorizationResult(
    permission: ExternalPermission
  ): AuthorizationResult {
    return {
      authorized: permission.isGranted,
      reason: permission.denialReason,
    };
  }

  private mapAction(action: ActionType): string {
    // 若外部BC使用不同的action命名,在此转换
    const mapping: Record<ActionType, string> = {
      create: 'CREATE',
      read: 'READ',
      update: 'UPDATE',
      delete: 'DELETE',
    };
    return mapping[action];
  }
}

Go 範例

Go 示例

Domain Service Interface

领域服务接口

go
// domain/services/authorization.go
package services

type ActionType string
type ResourceType string

const (
    ActionCreate ActionType = "create"
    ActionRead   ActionType = "read"
    ActionUpdate ActionType = "update"
    ActionDelete ActionType = "delete"
)

type AuthorizationResult struct {
    Authorized bool
    Reason     string
}

// AuthorizationService - Domain layer interface
// This is the Anti-Corruption Layer entry point
type AuthorizationService interface {
    // CanExecute checks if the operator can perform the action
    // @pre operatorId must not be empty
    // @post returns AuthorizationResult, never returns error for check
    CanExecute(
        ctx context.Context,
        operatorID string,
        action ActionType,
        resourceType ResourceType,
        resourceID string,
    ) (*AuthorizationResult, error)
}
go
// domain/services/authorization.go
package services

type ActionType string
type ResourceType string

const (
    ActionCreate ActionType = "create"
    ActionRead   ActionType = "read"
    ActionUpdate ActionType = "update"
    ActionDelete ActionType = "delete"
)

type AuthorizationResult struct {
    Authorized bool
    Reason     string
}

// AuthorizationService - Domain layer interface
// This is the Anti-Corruption Layer entry point
type AuthorizationService interface {
    // CanExecute checks if the operator can perform the action
    // @pre operatorId must not be empty
    // @post returns AuthorizationResult, never returns error for check
    CanExecute(
        ctx context.Context,
        operatorID string,
        action ActionType,
        resourceType ResourceType,
        resourceID string,
    ) (*AuthorizationResult, error)
}

ACL Adapter

ACL适配器

go
// infrastructure/acl/access_control_adapter.go
package acl

import (
    "context"
    "time"
    
    "myapp/domain/services"
    "myapp/infrastructure/clients"
    "myapp/infrastructure/resilience"
)

type AccessControlAuthorizationAdapter struct {
    client         *clients.AccessControlClient
    circuitBreaker *resilience.CircuitBreaker
    timeout        time.Duration
}

func NewAccessControlAuthorizationAdapter(
    client *clients.AccessControlClient,
    cb *resilience.CircuitBreaker,
) *AccessControlAuthorizationAdapter {
    return &AccessControlAuthorizationAdapter{
        client:         client,
        circuitBreaker: cb,
        timeout:        3 * time.Second,
    }
}

func (a *AccessControlAuthorizationAdapter) CanExecute(
    ctx context.Context,
    operatorID string,
    action services.ActionType,
    resourceType services.ResourceType,
    resourceID string,
) (*services.AuthorizationResult, error) {
    // ===== Pre-conditions =====
    if operatorID == "" {
        return nil, errors.New("operatorId must not be empty")
    }

    // Context with timeout
    ctx, cancel := context.WithTimeout(ctx, a.timeout)
    defer cancel()

    // Execute through circuit breaker
    result, err := a.circuitBreaker.Execute(ctx, func() (interface{}, error) {
        return a.client.CheckPermission(ctx, &clients.PermissionRequest{
            UserID:   operatorID,
            Action:   a.mapAction(action),
            Resource: fmt.Sprintf("%s:%s", resourceType, resourceID),
        })
    })

    if err != nil {
        // Fallback: deny by default
        return &services.AuthorizationResult{
            Authorized: false,
            Reason:     "Authorization service unavailable",
        }, nil
    }

    // ===== Model Translation (ACL 核心) =====
    permission := result.(*clients.Permission)
    return a.translateToAuthorizationResult(permission), nil
}

func (a *AccessControlAuthorizationAdapter) translateToAuthorizationResult(
    permission *clients.Permission,
) *services.AuthorizationResult {
    return &services.AuthorizationResult{
        Authorized: permission.IsGranted,
        Reason:     permission.DenialReason,
    }
}

func (a *AccessControlAuthorizationAdapter) mapAction(action services.ActionType) string {
    mapping := map[services.ActionType]string{
        services.ActionCreate: "CREATE",
        services.ActionRead:   "READ",
        services.ActionUpdate: "UPDATE",
        services.ActionDelete: "DELETE",
    }
    return mapping[action]
}

go
// infrastructure/acl/access_control_adapter.go
package acl

import (
    "context"
    "time"
    
    "myapp/domain/services"
    "myapp/infrastructure/clients"
    "myapp/infrastructure/resilience"
)

type AccessControlAuthorizationAdapter struct {
    client         *clients.AccessControlClient
    circuitBreaker *resilience.CircuitBreaker
    timeout        time.Duration
}

func NewAccessControlAuthorizationAdapter(
    client *clients.AccessControlClient,
    cb *resilience.CircuitBreaker,
) *AccessControlAuthorizationAdapter {
    return &AccessControlAuthorizationAdapter{
        client:         client,
        circuitBreaker: cb,
        timeout:        3 * time.Second,
    }
}

func (a *AccessControlAuthorizationAdapter) CanExecute(
    ctx context.Context,
    operatorID string,
    action services.ActionType,
    resourceType services.ResourceType,
    resourceID string,
) (*services.AuthorizationResult, error) {
    // ===== 前置条件 =====
    if operatorID == "" {
        return nil, errors.New("operatorId must not be empty")
    }

    // 带超时的上下文
    ctx, cancel := context.WithTimeout(ctx, a.timeout)
    defer cancel()

    // 通过熔断器执行
    result, err := a.circuitBreaker.Execute(ctx, func() (interface{}, error) {
        return a.client.CheckPermission(ctx, &clients.PermissionRequest{
            UserID:   operatorID,
            Action:   a.mapAction(action),
            Resource: fmt.Sprintf("%s:%s", resourceType, resourceID),
        })
    })

    if err != nil {
        // 降级策略:默认拒绝
        return &services.AuthorizationResult{
            Authorized: false,
            Reason:     "Authorization service unavailable",
        }, nil
    }

    // ===== 模型转换(ACL核心)=====
    permission := result.(*clients.Permission)
    return a.translateToAuthorizationResult(permission), nil
}

func (a *AccessControlAuthorizationAdapter) translateToAuthorizationResult(
    permission *clients.Permission,
) *services.AuthorizationResult {
    return &services.AuthorizationResult{
        Authorized: permission.IsGranted,
        Reason:     permission.DenialReason,
    }
}

func (a *AccessControlAuthorizationAdapter) mapAction(action services.ActionType) string {
    mapping := map[services.ActionType]string{
        services.ActionCreate: "CREATE",
        services.ActionRead:   "READ",
        services.ActionUpdate: "UPDATE",
        services.ActionDelete: "DELETE",
    }
    return mapping[action]
}

Use Case 整合範例

用例整合示例

typescript
// 在 Use Case 中使用 AuthorizationService

export class CreateWorkflowUseCase {
  constructor(
    private readonly authorizationService: AuthorizationService,
    private readonly workflowRepository: WorkflowRepository,
    private readonly eventPublisher: EventPublisher,
  ) {}

  async execute(input: CreateWorkflowInput): Promise<CreateWorkflowOutput> {
    // ===== Cross-Context: Authorization Check =====
    const authResult = await this.authorizationService.canExecute(
      input.operatorId,
      'create',
      'Workflow',
      input.boardId,
    );

    if (!authResult.authorized) {
      throw new UnauthorizedError(
        `Not authorized to create workflow: ${authResult.reason}`
      );
    }

    // ===== Domain Logic =====
    const workflow = Workflow.create({
      boardId: new BoardId(input.boardId),
      name: input.name,
      createdBy: new UserId(input.operatorId),
    });

    await this.workflowRepository.save(workflow);
    await this.eventPublisher.publish(new WorkflowCreatedEvent(workflow));

    return {
      workflowId: workflow.id.value,
      status: workflow.status,
      createdAt: workflow.createdAt,
    };
  }
}

typescript
// 在Use Case中使用AuthorizationService

export class CreateWorkflowUseCase {
  constructor(
    private readonly authorizationService: AuthorizationService,
    private readonly workflowRepository: WorkflowRepository,
    private readonly eventPublisher: EventPublisher,
  ) {}

  async execute(input: CreateWorkflowInput): Promise<CreateWorkflowOutput> {
    // ===== 跨上下文:权限检查 =====
    const authResult = await this.authorizationService.canExecute(
      input.operatorId,
      'create',
      'Workflow',
      input.boardId,
    );

    if (!authResult.authorized) {
      throw new UnauthorizedError(
        `Not authorized to create workflow: ${authResult.reason}`
      );
    }

    // ===== 领域逻辑 =====
    const workflow = Workflow.create({
      boardId: new BoardId(input.boardId),
      name: input.name,
      createdBy: new UserId(input.operatorId),
    });

    await this.workflowRepository.save(workflow);
    await this.eventPublisher.publish(new WorkflowCreatedEvent(workflow));

    return {
      workflowId: workflow.id.value,
      status: workflow.status,
      createdAt: workflow.createdAt,
    };
  }
}

常見的跨 BC 場景

常见的跨BC场景

場景Source BCPattern說明
權限檢查AccessControlACL檢查操作權限
用戶資訊UserManagementACL取得用戶詳情
付款處理PaymentACL + Saga處理付款流程
通知發送NotificationOpen Host發送通知
審計日誌AuditPublished Language記錄操作

场景Source BCPattern说明
权限检查AccessControlACL检查操作权限
用户信息UserManagementACL获取用户详情
付款处理PaymentACL + Saga处理付款流程
通知发送NotificationOpen Host发送通知
审计日志AuditPublished Language记录操作

品質檢查清單

质量检查清单

  • 是否明確識別上下游關係?
  • ACL 是否在 Infrastructure 層,介面在 Domain 層?
  • 模型轉換是否完整,不洩漏外部 BC 概念?
  • 是否有適當的容錯策略(timeout, retry, circuit breaker)?
  • Fallback 策略是否符合業務需求?
  • 是否有明確的 pre/post-conditions?
  • 是否可追溯到 Frame Concerns?

  • 是否明确识别上下游关系?
  • ACL是否在Infrastructure层,接口在Domain层?
  • 模型转换是否完整,不泄露外部BC概念?
  • 是否有适当的容错策略(timeout, retry, circuit breaker)?
  • Fallback策略是否符合业务需求?
  • 是否有明确的前置/后置条件?
  • 是否可追溯到Frame Concerns?

與其他 Skills 的協作

与其他Skills的协作

analyze-frame
    ├── 識別 cross_context_dependencies
    └── cross-context (本 Skill)
        ├── 設計 ACL 規格
        ├── 連結到 arch-guard (確保層次正確)
        └── 連結到 command-sub-agent / query-sub-agent
            └── 在 Use Case 中整合 ACL
analyze-frame
    ├── 识别cross_context_dependencies
    └── cross-context(本Skill)
        ├── 设计ACL规格
        ├── 关联到arch-guard(确保层次正确)
        └── 关联到command-sub-agent / query-sub-agent
            └── 在Use Case中整合ACL