ワンクリックで
cross-context
處理跨 Bounded Context 的依賴關係。當需求涉及多個限界上下文(如權限管理、付款、通知)時觸發,設計 Anti-Corruption Layer 和 Context Mapping。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
處理跨 Bounded Context 的依賴關係。當需求涉及多個限界上下文(如權限管理、付款、通知)時觸發,設計 Anti-Corruption Layer 和 Context Mapping。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Automated code review that checks code quality, Clean Architecture compliance, DDD patterns, coding standards, and spec traceability.
從規格目錄的 acceptance.yaml 生成/維護 BDD/ezSpec 測試。使用類似 Gherkin 語法,AI 自動產生 step definition(開發人員不需要手寫),驗收測試規格即為 Executable Specification。
在單元測試通過後觸發。透過引入人工錯誤(Mutants)來「測試你的測試」,確保測試案例具有足夠的錯誤偵測能力,建立對驗證機制的信任(Trust the Verification)。
驗證規格檔案的完整性與一致性,確保所有必要的規格元素都已定義且符合標準格式。
Replace with description of the skill and when Claude should use it.
協調多個 AI 模型(ChatGPT、Gemini、Codex、QWEN、Claude)進行三角驗證,確保「Specification == Program == Test」一致性。過濾假警報後輸出報告,大幅減少人工介入時間。
| name | cross-context |
| description | 處理跨 Bounded Context 的依賴關係。當需求涉及多個限界上下文(如權限管理、付款、通知)時觸發,設計 Anti-Corruption Layer 和 Context Mapping。 |
cross_context_dependencies 時| 模式 | 說明 | 適用場景 |
|---|---|---|
| Customer-Supplier | 下游需求驅動上游開發 | 緊密合作的團隊 |
| Conformist | 下游完全遵循上游模型 | 無法影響上游時 |
| Anti-Corruption Layer | 下游建立隔離層 | 保護自身模型 |
| Open Host Service | 上游提供標準化 API | 多下游消費者 |
| Published Language | 共享交換格式 | 跨組織整合 |
| 模式 | 說明 | 適用場景 |
|---|---|---|
| Shared Kernel | 共享部分模型 | 高度協作 |
| Partnership | 雙方共同演進 | 緊密合作 |
| Separate Ways | 完全獨立 | 無需整合 |
# 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 與權限相關
// 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';
// 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];
}
}
// 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)
}
// 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]
}
// 在 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,
};
}
}
| 場景 | Source BC | Pattern | 說明 |
|---|---|---|---|
| 權限檢查 | AccessControl | ACL | 檢查操作權限 |
| 用戶資訊 | UserManagement | ACL | 取得用戶詳情 |
| 付款處理 | Payment | ACL + Saga | 處理付款流程 |
| 通知發送 | Notification | Open Host | 發送通知 |
| 審計日誌 | Audit | Published Language | 記錄操作 |
analyze-frame
│
├── 識別 cross_context_dependencies
│
└── cross-context (本 Skill)
│
├── 設計 ACL 規格
│
├── 連結到 arch-guard (確保層次正確)
│
└── 連結到 command-sub-agent / query-sub-agent
└── 在 Use Case 中整合 ACL