continuum AIDLC Docs GitHub ↗

Component Methods — continuum

Project: continuum Phase: INCEPTION — Application Design Date: 2026-05-08 Depth: Comprehensive

Note: 本ドキュメントは各コンポーネントの メソッドシグネチャ + 入出力型 + 高レベル目的 を定義する。詳細業務ルール(具体的なバリデーションロジック、エラー条件、ビジネス例外処理)は Functional Design(Construction Phase per-unit) で精緻化する。

言語: TypeScript(Frontend / Backend 共通、Monorepo + 共有型)


1. Frontend Components

C-FE-01: WebApp (PWA Shell)

class WebApp {
  // ルーティング初期化
  initializeRouter(): void;
  // Service Worker 登録
  registerServiceWorker(): Promise<ServiceWorkerRegistration>;
  // グローバル状態の初期化
  initializeGlobalState(): void;
  // 認証ステートに応じたリダイレクト
  redirectBasedOnAuth(): void;
}

C-FE-02: AuthUI

class AuthUI {
  signUp(input: { email: string; password: string; displayName: string }): Promise<{ userId: string }>;
  login(input: { email: string; password: string }): Promise<{ jwtToken: string; userId: string }>;
  logout(): Promise<void>;
  refreshToken(): Promise<{ jwtToken: string }>;
  getCurrentUser(): { userId: string; displayName: string } | null;
}

C-FE-03: InboxView

type InboxMessage = {
  messageId: string;
  contactId: string;
  contactName: string;
  receivedAt: string; // ISO 8601
  subject: string;
  body: string;
  status: 'pending' | 'responded';
  isCritical: boolean;
};

type ResponseVariation = {
  variationId: string;
  style: 'conservative' | 'pragmatic' | 'cordial';
  text: string;
};

class InboxView {
  fetchInbox(): Promise<InboxMessage[]>;
  generateResponses(messageId: string): Promise<ResponseVariation[]>;
  selectVariation(variationId: string): void;
  editVariation(text: string): void; // Lv1 限定
  sendResponse(messageId: string, variationId: string, editedText?: string): Promise<{ success: boolean }>;
  applyMaturityPhaseUI(currentPhase: 'Lv1' | 'Lv2' | 'Lv3' | 'Lv4' | 'Lv5'): void;
}

C-FE-04: OutboundReviewView

type OutboundCandidate = {
  outboundId: string;
  contactId: string;
  contactName: string;
  type: 'strategic_outreach' | 'heartbeat';
  proposedText: string;
  scheduledAt: string;
  reasoning: string; // 例: "Optimal Window 検出: 5/20-22 京都出張"
};

class OutboundReviewView {
  fetchPending(): Promise<OutboundCandidate[]>;
  approve(outboundId: string, editedText?: string): Promise<void>;
  reject(outboundId: string, reason?: string): Promise<void>;
  fetchHistory(filters: { dateRange?: [string, string]; type?: string }): Promise<OutboundCandidate[]>;
}

C-FE-05: DashboardView

type DashboardKPI = {
  responsesDelegatedThisMonth: number;
  timeReclaimedHours: number;
  delegationStreak: number;
  delegationScore: number; // 0〜100
  currentPhase: 'Lv1' | 'Lv2' | 'Lv3' | 'Lv4' | 'Lv5';
  optimalWindowHitRate: number; // 0〜1
  relationshipHealthScores: Array<{ contactId: string; score: number }>;
  engagementCoverage: number; // 0〜1
  daysInNirvana?: number; // Lv5 のみ
};

type Badge = {
  badgeId: string;
  name: string; // 例: "Adaptive Delegation Specialist"
  acquiredAt: string;
};

class DashboardView {
  fetchKPI(): Promise<DashboardKPI>;
  fetchBadges(): Promise<Badge[]>;
  fetchRecommendations(): Promise<{ recommendation: string; targetPhase?: string } | null>;
}

C-FE-06: MaturitySettingsView

class MaturitySettingsView {
  fetchCurrentPhase(): Promise<{ phase: string; lifetimeCounters: Record<string, number> }>;
  changePhase(targetPhase: 'Lv1' | 'Lv2' | 'Lv3'): Promise<void>; // Lv4 は別メソッド
  activateFullAutonomousMode(): Promise<void>; // Lv4 自己有効化
  deactivateFullAutonomousMode(): Promise<void>; // Lv4 → Lv3 へ降格
  showConfirmationModal(message: string): Promise<boolean>;
}

C-FE-07: DemoSetPieceView

type MACPNegotiationEvent = {
  timestamp: string;
  fromAgent: 'A' | 'B';
  toAgent: 'A' | 'B';
  type: 'proposal' | 'counter_proposal' | 'agreement' | 'commit';
  payload: Record<string, unknown>;
};

class DemoSetPieceView {
  startDemo(scenario: 'macp_demo'): Promise<void>;
  renderSplitScreen(userAState: unknown, userBState: unknown, negotiationLog: MACPNegotiationEvent[]): void;
  playTimeLapse(speedMultiplier: number): void;
  renderClosingNarration(message: string): void;
}

C-FE-08: WebSocketClient

type WebSocketEvent =
  | { type: 'macp.negotiation.update'; payload: MACPNegotiationEvent }
  | { type: 'inbox.new_message'; payload: InboxMessage }
  | { type: 'outbound.sent'; payload: OutboundCandidate };

class WebSocketClient {
  connect(jwtToken: string): Promise<void>;
  disconnect(): void;
  subscribe(eventType: string, handler: (event: WebSocketEvent) => void): () => void;
  send(event: WebSocketEvent): void;
}

2. Backend Components

C-BE-01: AuthHandler

type UserProfile = {
  userId: string;
  email: string;
  displayName: string;
  // defaultCommunicationStyle: 削除(2026-05-08 scope revision — US-1.3 削除に伴う)
  initialMaturityPhase: 'Lv1';
  createdAt: string;
};

class AuthHandler {
  // POST /auth/signup (Cognito の Post-Confirmation Trigger でも呼ばれる)
  handleSignUp(input: { email: string; displayName: string }): Promise<{ userId: string }>;
  // GET /me
  getProfile(userId: string): Promise<UserProfile>;
  // PUT /me
  updateProfile(userId: string, updates: Partial<Pick<UserProfile, 'displayName'>>): Promise<UserProfile>;
  // JWT 検証ミドルウェア
  verifyJwt(jwtToken: string): Promise<{ userId: string }>;
}

C-BE-02: ContactHandler

type Contact = {
  contactId: string;
  userId: string;
  name: string;
  category: 'Friend' | 'Family' | 'Colleague' | 'Supervisor';
  relationshipTier: 'Close' | 'Standard' | 'Distant';
  tonePreference: 'formal' | 'casual';
  engagementCadence: 'weekly' | 'biweekly' | 'monthly' | 'quarterly' | 'none';
  isCritical: boolean;
  createdAt: string;
};

class ContactHandler {
  // GET /contacts
  listContacts(userId: string): Promise<Contact[]>;
  // POST /contacts
  createContact(userId: string, input: Omit<Contact, 'contactId' | 'userId' | 'createdAt'>): Promise<Contact>;
  // PUT /contacts/{id}
  updateContact(userId: string, contactId: string, updates: Partial<Contact>): Promise<Contact>;
  // DELETE /contacts/{id}
  deleteContact(userId: string, contactId: string): Promise<void>;
  // 内部利用
  getContactById(contactId: string): Promise<Contact>;
  // Cadence デフォルトの推定
  inferDefaultCadence(category: string, tier: string): Contact['engagementCadence'];
}

C-BE-03: InboundResponseEngine

type GenerateResponseInput = {
  messageId: string;
  message: InboxMessage;
  contact: Contact;
  userProfile: UserProfile;
};

class InboundResponseEngine {
  // POST /inbound/{messageId}/generate
  generateThreeVariations(input: GenerateResponseInput): Promise<ResponseVariation[]>;
  // POST /inbound/{messageId}/send
  sendResponse(input: { messageId: string; variationId: string; editedText?: string }): Promise<{ sentAt: string }>;
  // 内部メソッド
  applyRelationalCalibration(prompt: string, contact: Contact): string;
  // validatePlausibilityConstraint(): 廃止(2026-05-08 scope revision — プロンプト並列生成のみ、類似度 0.7 検証は Phase 2 Must から削除)
  fetchPastInteractions(contactId: string, limit: number): Promise<unknown[]>; // AgentCore Memory から
}

C-BE-04: OutboundOrchestrator

type GenerateOutboundInput = {
  userId: string;
  contactId: string;
  type: 'strategic_outreach' | 'heartbeat';
  optimalWindow?: { start: string; end: string; confidence: number }; // strategic_outreach のみ
};

class OutboundOrchestrator {
  // 内部: SignalExtractor から Window を取得して Strategic Outreach を生成
  scheduleStrategicOutreach(userId: string): Promise<OutboundCandidate[]>;
  // 内部: Cadence 別の Heartbeat 候補を生成
  scheduleHeartbeat(userId: string, contactId: string): Promise<OutboundCandidate>;
  // GET /outbound/pending
  listPending(userId: string): Promise<OutboundCandidate[]>;
  // POST /outbound/{id}/approve
  approveAndSend(outboundId: string, editedText?: string): Promise<{ sentAt: string }>;
  // POST /outbound/{id}/reject
  reject(outboundId: string): Promise<void>;
  // 内部: Conflict Detection
  detectConflicts(candidate: OutboundCandidate, recentHistory: unknown[]): { hasConflict: boolean; reasons: string[] };
  // 内部: Plausibility Engineering
  applyPlausibilityEngineering(text: string, userProfile: UserProfile, pastSentMessages: unknown[]): string;
  // 内部: 送信時刻のランダム化
  scheduleNaturalDeliveryTime(window: { start: string; end: string }): string; // ISO 8601
}

C-BE-05: SignalExtractor

type SocialFeedItem = {
  feedItemId: string;
  contactId: string;
  platform: 'mock_x' | 'mock_instagram' | 'mock_linkedin' | 'mock_timetree';
  postedAt: string;
  content: string;
};

type AvailabilityWindow = {
  windowId: string;
  contactId: string;
  start: string;
  end: string;
  category: 'explicit' | 'implicit' | 'inferred' | 'predictive' | 'cross_source';
  eventType?: string; // 'business_trip' / 'wedding' / 'work_deadline' 等
  confidence: number; // 0〜1
  contributingFeedItemIds: string[];
};

class SignalExtractor {
  // パイプライン全体
  extractWindowsForContact(contactId: string): Promise<AvailabilityWindow[]>;
  // Step 1: Ingestion
  ingestFeed(contactId: string): Promise<SocialFeedItem[]>;
  // Step 2: Normalization
  normalize(items: SocialFeedItem[]): SocialFeedItem[];
  // Step 3: NER + 意図理解(Bedrock)
  extractSignalsWithLLM(item: SocialFeedItem): Promise<Partial<AvailabilityWindow>[]>;
  // Step 4: Confidence Scoring
  calculateConfidence(signals: Partial<AvailabilityWindow>[]): AvailabilityWindow[];
  // Step 5: Window Aggregation
  aggregateWindows(windows: AvailabilityWindow[]): AvailabilityWindow[];
  // Step 6: 永続化(DynamoDB へ)
  persistWindows(windows: AvailabilityWindow[]): Promise<void>;
  // クエリ: Confidence 閾値以上の Window
  getOptimalWindows(contactId: string, threshold?: number): Promise<AvailabilityWindow[]>;
}

C-BE-06: MaturityPhaseManager

type MaturityState = {
  userId: string;
  currentPhase: 'Lv1' | 'Lv2' | 'Lv3' | 'Lv4' | 'Lv5';
  totalResponses: number;
  consecutiveDays: number;
  lastAppOpenAt: string;
  daysInNirvana: number; // Lv5 のみ
  badges: Badge[];
};

class MaturityPhaseManager {
  // GET /maturity/status
  getStatus(userId: string): Promise<MaturityState>;
  // PUT /maturity/phase (Lv1〜Lv3 切替)
  changePhase(userId: string, targetPhase: 'Lv1' | 'Lv2' | 'Lv3'): Promise<MaturityState>;
  // POST /maturity/activate-autonomous (Lv4 自己有効化)
  activateLv4(userId: string): Promise<MaturityState>;
  /**
   * 内部: フェーズ別の挙動判定
   *
   * Phase 2: Lv1(true 常返却 = 全レビュー)/ Lv4(false 常返却 = 全自動)のみが本実装。
   *          Lv2 / Lv3 は **stub 実装**(Lv1 と同等の挙動 = 常に true 返却、確率分岐や Critical タグ判定は未実装)。
   * Phase 3 Stretch: Lv2 確率的 30% スキップ(US-5.2)/ Lv3 Critical タグ別動作(US-5.3)を本実装。
   * Phase 3 Must: Lv5 自動認定後の動作(false 返却、通知送信なし)を本実装。
   */
  shouldReviewInbound(userId: string, message: InboxMessage, contact: Contact): Promise<boolean>;
  shouldReviewOutbound(userId: string, candidate: OutboundCandidate): Promise<boolean>;
  // 内部: Recommendation 表示判定
  getRecommendation(userId: string): Promise<{ message: string; targetPhase: string } | null>;
  // 内部: Lv5 自動認定(日次バッチ)
  detectNirvanaCandidates(): Promise<string[]>; // userId[]
  promoteToLv5(userId: string): Promise<MaturityState>;
  /**
   * 内部: Lv5 → Lv4 自動降格(アプリ起動時)
   *
   * Lv5(涅槃期)状態で本メソッドが呼ばれた場合、自動的に Lv4(解脱期)へ降格し
   * `maturity.phase.changed` イベントを EventBridge へ発行する。
   * 降格時に `lifetimeDaysInNirvana` を更新し、未取得なら "Transcendence Achieved" バッジを付与する。
   *
   * 注: Lv5 自動認定ロジック自体(detectNirvanaCandidates / promoteToLv5)は Phase 3 ストレッチ。
   * Phase 2 MVP では本降格処理は stub 実装(lastAppOpenAt の更新のみ)とする。
   */
  handleAppOpen(userId: string): Promise<MaturityState>;
  // 内部: 応答件数インクリメント
  incrementResponseCount(userId: string): Promise<MaturityState>;
}

C-BE-07: MACPCoordinator

type MACPSession = {
  sessionId: string;
  initiatorUserId: string;
  counterpartUserId: string;
  status: 'discovery' | 'negotiating' | 'theatrical_active' | 'completed' | 'aborted';
  agreement?: MACPAgreement;
  theaterMessages: Array<{ scheduledAt: string; from: string; to: string; text: string; sent: boolean }>;
  startedAt: string;
  completedAt?: string;
};

type MACPAgreement = {
  mutualDeclineIntent: boolean;
  theaterTopic: string; // "飲み会" / "ランチ" / "相談" 等
  theaterDuration: number; // 何往復
  theaterCadence: number; // 平均間隔(時間)
  toneAlignment: 'formal' | 'casual';
  resolutionPattern: 'next_time' | 'circle_back' | 'undefined_future';
  privacyBoundaries: { shareReasons: false }; // 抽象的状態のみ共有
};

class MACPCoordinator {
  // メインエントリポイント: Outbound 候補に対し MACP 試行
  attemptMACP(candidate: OutboundCandidate): Promise<MACPSession | null>;
  // FR-9.2 Peer Discovery
  discoverPeer(contactEmail: string): Promise<{ isContinuumUser: boolean; tenantId?: string }>;
  // FR-9.3 Inter-Agent Negotiation (cross-tenant via AgentCore Gateway)
  negotiateAgreement(initiatorState: unknown, counterpartTenantId: string): Promise<MACPAgreement | null>;
  // FR-9.4 Theatrical Performance
  scheduleTheatricalMessages(session: MACPSession): Promise<void>;
  // EventBridge 受信ハンドラ: 各演出メッセージの送信時刻
  executeTheaterStep(input: { sessionId: string; stepIndex: number }): Promise<void>;
  // FR-9.5 Outcome Confirmation
  confirmOutcome(sessionId: string): Promise<{ badgeAwardedTo: string[] }>;
  // FR-9.7 Failure Handling
  abortSession(sessionId: string, reason: 'gateway_timeout' | 'auth_failure' | 'counterpart_unavailable' | 'mutual_intent_mismatch'): Promise<void>;
}

C-BE-08: DashboardEngine

class DashboardEngine {
  // GET /dashboard/kpi
  getKPI(userId: string): Promise<DashboardKPI>;
  // GET /dashboard/badges
  getBadges(userId: string): Promise<Badge[]>;
  // GET /dashboard/recommendations
  getRecommendations(userId: string): Promise<{ message: string; targetPhase?: string } | null>;
  // 内部: KPI 集計
  calculateResponsesDelegated(userId: string, dateRange: [string, string]): Promise<number>;
  calculateTimeReclaimed(userId: string, dateRange: [string, string]): Promise<number>; // hours
  calculateDelegationScore(userId: string): Promise<number>; // 0〜100
  calculateOptimalWindowHitRate(userId: string): Promise<number>;
  calculateRelationshipHealthScore(userId: string, contactId: string): Promise<number>;
  // バッジ付与
  awardBadge(userId: string, badge: Badge): Promise<void>;
}

C-BE-09: WebSocketBroker

type ConnectionRecord = {
  connectionId: string;
  userId: string;
  connectedAt: string;
};

class WebSocketBroker {
  // $connect ハンドラ
  handleConnect(input: { connectionId: string; jwtToken: string }): Promise<void>;
  // $disconnect ハンドラ
  handleDisconnect(connectionId: string): Promise<void>;
  // $default ハンドラ(クライアントからのメッセージ)
  handleMessage(connectionId: string, body: unknown): Promise<void>;
  // ユーザー単位のプッシュ
  pushToUser(userId: string, event: WebSocketEvent): Promise<void>;
  // 全接続クライアントへブロードキャスト(デモ用)
  broadcastDemo(event: WebSocketEvent): Promise<void>;
}

C-BE-10: MockSocialFeedSeeder

class MockSocialFeedSeeder {
  /**
   * メイン投入関数(Phase 2: 3 コンタクト × 各 2 投稿 = 合計 6 投稿)
   * Phase 2 では kobayashi / tanaka / misaki の 3 名のみ投入(Phase 3 で mom / sasaki 等を追加)
   */
  seedAll(): Promise<{ contactsSeeded: number; feedItemsSeeded: number }>;

  /**
   * 個別ペルソナのフィード投入
   *
   * 各テンプレートで投入される 2 投稿(Mock X + Mock Instagram Story)の内容:
   *
   * - **'kobayashi'** (M1 同期友人): 飲み会セット + 旅行系
   *   - Mock X: "来週は札幌出張。月曜から金曜まで不在"
   *   - Mock Instagram Story: 札幌の風景写真(位置タグ「Sapporo, Japan」)
   *
   * - **'mom'** (M2 母): Phase 3 で投入 — Phase 2 ではコンタクトプロファイルのみ作成、SNS 投稿なし
   *   - (Phase 3) Mock X: "今度の母の日、なにか送ってくれる?w"
   *   - (Phase 3) Mock Instagram Story: 父の手術付き添い系
   *
   * - **'tanaka'** (M3 上司): 経営会議系
   *   - Mock X: "来週は京都で経営会議。月曜から金曜まで不在"
   *   - Mock Instagram Story: 京都・八坂の塔(位置タグ「Kyoto, Japan」)
   *
   * - **'misaki'** (M4 同僚): 研修・産休系
   *   - Mock Instagram Story: "今週は研修で千葉合宿"(位置タグ「Chiba」)
   *   - Mock X: "出産前最後のプロジェクト終了、あとは産休へ。しばらく音信不通になります 🤰"
   *
   * - **'sasaki'** (F1 MACP 相手): Phase 3 で投入 — Phase 2 ではコンタクトプロファイルのみ作成
   *   - (Phase 3) Mock X / Mock Instagram Story: コンサル系出張投稿
   *
   * Phase 3 で Mock LinkedIn / Mock TimeTree のテンプレートを各テンプレートに追加する。
   */
  seedContactFeed(contactId: string, personaTemplate: 'kobayashi' | 'mom' | 'tanaka' | 'misaki' | 'sasaki'): Promise<number>;

  /**
   * Signal Categories 全種別を網羅するか検証
   * Phase 2 では explicit のみ true 想定(残りは Phase 3 で実装)
   */
  validateCoverage(seedResults: unknown): { explicit: boolean; implicit: boolean; inferred: boolean; predictive: boolean; crossSource: boolean };
}

3. Method Naming Conventions

  • HTTP API ハンドラ: handle{Verb}{Resource} または HTTP メソッド名そのまま
  • 内部メソッド: 動詞 + 名詞(例: extractSignals, applyRelationalCalibration
  • 判定メソッド: should{X} または is{X} または has{X}
  • 集計メソッド: calculate{X}
  • イベントハンドラ: handle{EventName} または execute{Step}

4. Cross-Cutting Concerns

  • エラーハンドリング: 各メソッドは Promise<T> を返し、例外は domain-specific Error クラス(InboundGenerationFailedError, MACPNegotiationTimeoutError 等)で統一
  • 認証: HTTP API は API Gateway の Cognito Authorizer で JWT 検証、Lambda 内では userId を context から取得
  • ロギング: 各メソッドのエントリ・終了で構造化ログ({ method, userId, timestamp, durationMs }
  • トレーシング (Phase 3): AWS X-Ray の自動 instrumentation を全 Lambda に適用

5. 詳細業務ルールは Functional Design へ

以下は 本ドキュメントでは定義しない(Functional Design で精緻化):

  • 各メソッド内の具体的なバリデーションルール
  • Bedrock Prompt Template の詳細文言
  • DynamoDB クエリの具体的な PK/SK 設計
  • エラー条件ごとのリトライポリシー
  • レート制限の閾値
  • 具体的な Plausibility Engineering アルゴリズム