Skip to content

Instantly share code, notes, and snippets.

@m-mizutani
Created January 4, 2026 00:18
Show Gist options
  • Select an option

  • Save m-mizutani/16e2fb7a562ed95e8ba42a191ba1c38a to your computer and use it in GitHub Desktop.

Select an option

Save m-mizutani/16e2fb7a562ed95e8ba42a191ba1c38a to your computer and use it in GitHub Desktop.

Firestore スキャンリポジトリ実装 Specification

1. 要件定義 (Requirements)

概要

GitHub リポジトリのスキャン結果を Firestore に保存するためのリポジトリ層を実装する。定期スキャンの実装に向けて、リポジトリの基本情報とブランチごとのスキャン結果を階層的に管理する。

機能要件

  • Firestore に以下のコレクション構造でデータを保存:
    • repo/{repoID}: リポジトリの基本情報(デフォルトブランチ、インストールID等)
    • repo/{repoID}/branch/{branchName}: 各ブランチの最新スキャン結果、スキャンID等
    • repo/{repoID}/branch/{branchName}/target/{targetID}: スキャン対象(Trivyの Result.Target に対応)
    • repo/{repoID}/branch/{branchName}/target/{targetID}/vulnerability/{vulnID}: 各脆弱性の詳細情報
  • リポジトリ情報の CRUD 操作
    • リポジトリ基本情報の作成・読取・更新・削除
    • ブランチスキャン結果の作成・読取・更新・削除
    • 脆弱性情報の作成・読取・更新・削除
  • 脆弱性情報の保存
    • Trivyの脆弱性情報をほぼ完全な形で保存
    • Description、References、CVSS(元の構造を保持)、PublishedDate/LastModifiedDate を含む
    • 各脆弱性を個別ドキュメントとして保存(Firestoreの1MB制限を回避)
  • 脆弱性ステータス管理
    • Active: 最新スキャンで検出された脆弱性
    • Fixed: 過去に検出されたが最新スキャンで検出されなくなった脆弱性
    • 既存脆弱性は削除せず、ステータス更新で履歴を保持
  • バッチ操作のサポート
    • 複数の脆弱性を一括で読み込み
    • 複数の脆弱性を一括で書き込み(Firestoreのバッチ書き込みを活用)
    • 複数の脆弱性ステータスを一括更新
  • メモリ実装とFirestore実装の両方を提供(テスト用途と本番用途)
  • モック生成に対応したインターフェース設計
  • CLI統合
    • scan コマンド: Firestoreへの保存をオプショナルに対応
    • serve コマンド: webhook処理でFirestoreへの保存をオプショナルに対応
    • Firestore設定がない場合でも正常動作(BigQueryのみに保存)

非機能要件

  • パフォーマンス要件
    • Firestore の読み書き操作は適切にタイムアウト設定を行う
    • バッチ操作を活用して効率的な更新を実現(最大500件/バッチ)
    • 大量の脆弱性読み込み時はページネーションを考慮
  • セキュリティ要件
    • Firestore への接続は適切な認証を使用
    • サービスアカウントの impersonate をサポート
  • テスタビリティ
    • インターフェースベースの設計でモック化を容易に
    • メモリ実装による高速なユニットテスト実行

制約事項

  • 既存の tmp/hecatoncheires/pkg/repository と同様の設計パターンを踏襲
  • 既存のドメインモデルとの整合性を保つ
  • goerr v2 を使用したエラーハンドリング
  • gt を使用したテストフレームワーク
  • Firestore 制限:
    • 1ドキュメントあたり最大1MB(脆弱性を個別ドキュメント化することで回避)
    • バッチ書き込みは最大500件まで
    • トランザクションは最大500ドキュメントまで

2. 設計 (Design)

アーキテクチャ概要

クリーンアーキテクチャに基づき、以下の層構造で実装:

  • pkg/domain/interfaces/: リポジトリインターフェース定義
  • pkg/domain/model/: ドメインモデル定義(Scan、Repository、Branch)
  • pkg/repository/: リポジトリ実装(memory、firestore)
  • pkg/domain/mock/: モック生成

コンポーネント設計

型定義

// types.CommitSHA: Gitコミットハッシュ
type CommitSHA string

// types.ScanStatus: スキャンステータス
type ScanStatus string

const (
    ScanStatusSuccess ScanStatus = "success"
    ScanStatusFailure ScanStatus = "failure"
    ScanStatusPending ScanStatus = "pending"
)

// types.VulnStatus: 脆弱性ステータス
type VulnStatus string

const (
    VulnStatusActive VulnStatus = "active"
    VulnStatusFixed  VulnStatus = "fixed"
)

ドメインモデル

// Repository: GitHub リポジトリの基本情報
type Repository struct {
    ID              types.GitHubRepoID // "{owner}/{name}" 形式
    Owner           string
    Name            string
    DefaultBranch   types.BranchName
    InstallationID  int64
    CreatedAt       time.Time
    UpdatedAt       time.Time
}

// Branch: ブランチのスキャン情報
type Branch struct {
    Name          types.BranchName
    LastScanID    types.ScanID
    LastScanAt    time.Time
    LastCommitSHA types.CommitSHA
    Status        types.ScanStatus
    CreatedAt     time.Time
    UpdatedAt     time.Time
}

// Target: スキャン対象の情報(Trivyの Result に対応)
type Target struct {
    ID        types.TargetID // Target文字列をハッシュ化したID
    Target    string         // Trivyの Result.Target(例: "go.mod", "package-lock.json", "alpine:3.14")
    Class     string         // Trivyの Result.Class(例: "os-pkgs", "lang-pkgs")
    Type      string         // Trivyの Result.Type(例: "alpine", "gomod", "npm")
    CreatedAt time.Time
    UpdatedAt time.Time
}

// Vulnerability: Firestoreに保存する脆弱性の詳細情報
// Trivyの DetectedVulnerability をベースに、Firestoreに保存する情報を定義
type Vulnerability struct {
    ID               string           // VulnerabilityID (例: CVE-2021-1234)
    PkgName          string           // パッケージ名
    PkgPath          string           // パッケージパス
    InstalledVersion string           // インストール済みバージョン
    FixedVersion     string           // 修正バージョン
    Severity         string           // CRITICAL, HIGH, MEDIUM, LOW, UNKNOWN
    Title            string           // 脆弱性タイトル
    Description      string           // 脆弱性の説明
    References       []string         // 参照URL一覧
    PrimaryURL       string           // 主要URL
    CweIDs           []string         // CWE IDs
    CVSS             map[string]CVSS  // CVSS情報(元の構造を保持)
    PublishedDate    string           // 公開日
    LastModifiedDate string           // 最終更新日
    Status           types.VulnStatus // active, fixed, ignored
    CreatedAt        time.Time
    UpdatedAt        time.Time
}

// CVSS: Trivyと同じ構造
type CVSS struct {
    V2Vector string
    V3Vector string
    V2Score  float64
    V3Score  float64
}

インターフェース設計

// ScanRepository: スキャン情報のリポジトリインターフェース
type ScanRepository interface {
    // Repository operations
    CreateRepository(ctx context.Context, repo *Repository) error
    GetRepository(ctx context.Context, repoID types.GitHubRepoID) (*Repository, error)
    UpdateRepository(ctx context.Context, repo *Repository) error
    ListRepositories(ctx context.Context, installationID int64) ([]*Repository, error)

    // Branch operations
    CreateOrUpdateBranch(ctx context.Context, repoID types.GitHubRepoID, branch *Branch) error
    GetBranch(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName) (*Branch, error)
    ListBranches(ctx context.Context, repoID types.GitHubRepoID) ([]*Branch, error)

    // Target operations
    CreateOrUpdateTarget(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName, target *Target) error
    GetTarget(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName, targetID types.TargetID) (*Target, error)
    ListTargets(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName) ([]*Target, error)

    // Vulnerability operations (batch only)
    ListVulnerabilities(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName, targetID types.TargetID) ([]*Vulnerability, error)
    BatchCreateVulnerabilities(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName, targetID types.TargetID, vulns []*Vulnerability) error
    BatchUpdateVulnerabilityStatus(ctx context.Context, repoID types.GitHubRepoID, branchName types.BranchName, targetID types.TargetID, updates map[string]types.VulnStatus) error
}

// ヘルパー関数: Trivyの脆弱性からVulnerabilityモデルを生成
func NewVulnerability(detected *trivy.DetectedVulnerability) *Vulnerability {
    now := time.Now()

    // CVSS情報を元の構造のまま変換
    cvss := make(map[string]CVSS)
    for sourceID, vendorCVSS := range detected.CVSS {
        cvss[string(sourceID)] = CVSS{
            V2Vector: vendorCVSS.V2Vector,
            V3Vector: vendorCVSS.V3Vector,
            V2Score:  vendorCVSS.V2Score,
            V3Score:  vendorCVSS.V3Score,
        }
    }

    return &Vulnerability{
        ID:               detected.VulnerabilityID,
        PkgName:          detected.PkgName,
        PkgPath:          detected.PkgPath,
        InstalledVersion: detected.InstalledVersion,
        FixedVersion:     detected.FixedVersion,
        Severity:         detected.Severity,
        Title:            detected.Title,
        Description:      detected.Description,
        References:       detected.References,
        PrimaryURL:       detected.PrimaryURL,
        CweIDs:           detected.CweIDs,
        CVSS:             cvss, // 元の構造を保持
        PublishedDate:    detected.PublishedDate,
        LastModifiedDate: detected.LastModifiedDate,
        Status:           types.VulnStatusActive, // 新規検出時はactive
        CreatedAt:        now,
        UpdatedAt:        now,
    }
}

// ToFirestoreID: owner と repo から Firestore のドキュメントIDを生成
// Firestoreのドキュメント制約: スラッシュは使用不可のためコロンで結合
//
// 一意性の根拠:
// - GitHubのowner名(ユーザー名/組織名)は英数字とハイフン(-)のみ使用可能
// - コロン(:)は使用不可(GitHubの仕様)
// - したがって owner と repo をコロンで結合すれば一意性が保証され、視認性も良い
//
// 例: ("m-mizutani", "octovy") → "m-mizutani:octovy"
func ToFirestoreID(owner, repo string) (string, error) {
    // バリデーション: owner と repo が空でないこと
    if owner == "" || repo == "" {
        return "", goerr.New("owner or repo is empty",
            goerr.V("owner", owner),
            goerr.V("repo", repo),
        )
    }

    // バリデーション: ":"が含まれていないこと(念のため)
    if strings.Contains(owner, ":") || strings.Contains(repo, ":") {
        return "", goerr.New("owner or repo contains invalid character ':'",
            goerr.V("owner", owner),
            goerr.V("repo", repo),
        )
    }

    return owner + ":" + repo, nil
}

データフロー

スキャン結果の保存と脆弱性ステータス更新

  1. GitHub Webhook 受信 → UseCase が Trivy スキャン実行
  2. スキャン結果を BigQuery に保存(詳細な脆弱性情報を含む全データ)
  3. ScanRepository 呼び出し: a. リポジトリ基本情報の確認・作成(なければ作成) b. Trivy の Results を反復処理(各 Result が Target に対応):
    • Target 情報を作成・更新(CreateOrUpdateTarget)
    • Target.ID は Target 文字列の SHA256 ハッシュ c. 各 Target に対して:
    • 既存の脆弱性リストを取得(ListVulnerabilities)
    • 新規スキャン結果と既存脆弱性を比較:
      • 新規検出: 既存にない脆弱性 → Status: Active で新規作成
      • 継続検出: 既存にある脆弱性 → ステータス維持(既存が Fixed なら Active に戻す)
      • 修正済み: 既存にあるが新規スキャンにない → Status: Fixed に更新
    • バッチ操作で効率的に処理:
      • 新規脆弱性をバッチ作成(BatchCreateVulnerabilities、500件ずつ)
      • 修正済み脆弱性をバッチステータス更新(BatchUpdateVulnerabilityStatus) d. Branch ドキュメントを更新(LastScanID、LastScanAt、LastCommitSHA、Status等)
  4. 定期スキャン時は Firestore から Branch 情報を取得して最新状態を確認
  5. UI等で脆弱性一覧表示時:
    • ListTargets でブランチの全 Target を取得
    • 各 Target に対して ListVulnerabilities で脆弱性を取得(ステータスでフィルタ可能)

ステータス遷移

┌─────────┐  新規検出  ┌────────┐
│ (なし)  │ ────────> │ Active │
└─────────┘            └────────┘
                           │ │
                修正確認    │ │ 再検出
                           │ │
                           ▼ │
                       ┌───────┐
                       │ Fixed │
                       └───────┘

Firestore コレクション設計

octovy/
├── repo/
│   ├── {firestoreRepoID}/                          # Document: Repository基本情報
│   │   │                                            # firestoreRepoID = owner:repo (例: "m-mizutani:octovy")
│   │   │                                            # - id (元の "{owner}/{repo}" 形式を保持)
│   │   │                                            # - owner, name, defaultBranch, installationID
│   │   │                                            # - createdAt, updatedAt
│   │   ├── branch/                                  # Subcollection
│   │   │   ├── {branchName}/                       # Document: Branch情報
│   │   │   │   │                                    # - name, lastScanID, lastScanAt, lastCommitSHA (types.CommitSHA)
│   │   │   │   │                                    # - status (types.ScanStatus: success/failure/pending)
│   │   │   │   │                                    # - createdAt, updatedAt
│   │   │   │   ├── target/                          # Subcollection
│   │   │   │   │   ├── {targetID}/                 # Document: Target情報(Trivyの Result に対応)
│   │   │   │   │   │   │                            # - id (Target文字列のハッシュ)
│   │   │   │   │   │   │                            # - target (例: "go.mod", "alpine:3.14")
│   │   │   │   │   │   │                            # - class (例: "os-pkgs", "lang-pkgs")
│   │   │   │   │   │   │                            # - type (例: "alpine", "gomod", "npm")
│   │   │   │   │   │   │                            # - createdAt, updatedAt
│   │   │   │   │   │   ├── vulnerability/           # Subcollection
│   │   │   │   │   │   │   ├── {vulnID}            # Document: Vulnerability詳細
│   │   │   │   │   │   │   │                        # - id (CVE-2021-1234等)
│   │   │   │   │   │   │   │                        # - pkgName, installedVersion, fixedVersion
│   │   │   │   │   │   │   │                        # - severity, title, description
│   │   │   │   │   │   │   │                        # - references[], primaryURL, cweIDs[]
│   │   │   │   │   │   │   │                        # - cvss (map[string]CVSS)
│   │   │   │   │   │   │   │                        # - publishedDate, lastModifiedDate
│   │   │   │   │   │   │   │                        # - status (Active/Fixed)
│   │   │   │   │   │   │   │                        # - createdAt, updatedAt

注記:

  • repoID は内部的に {owner}/{repo} 形式だが、Firestore のドキュメントIDとしては owner:repo に変換
    • 一意性保証: GitHubのowner名はコロン使用不可(英数字とハイフンのみ)のため、/:に変換すれば衝突しない
    • 視認性: コロンは区切り文字として視認性が高く、owner:repoの形式は理解しやすい
    • 例: m-mizutani/octovym-mizutani:octovy
  • targetID は Target 文字列(例: "go.mod", "alpine:3.14")を SHA256 ハッシュ化したもの
    • Firestore のドキュメントIDとして安全な文字列を使用
    • 衝突の可能性は事実上ゼロ
  • 各脆弱性は個別ドキュメントとして保存(1MB制限を回避)
  • 脆弱性は削除せず、ステータス更新で履歴管理(Active/Fixedの遷移を追跡可能)
  • Target層を追加することで、Trivyのスキャン結果の構造を正確に反映
    • 1つのブランチに複数のTarget(go.mod, package-lock.json等)が存在
    • 各Targetに対して個別に脆弱性を管理
  • スキャン結果の完全な詳細はBigQueryにも保存(バックアップと高度な分析用)
  • Firestoreには定期スキャンとUI表示に必要な情報を保存

エラーハンドリング

  • goerr v2 を使用した構造化エラー
  • NotFound、AlreadyExists、ValidationError などのドメイン固有エラー
  • Firestore のネットワークエラーは適切にラップ

3. 実装計画 (Implementation Plan)

影響を受けるファイル

  • 新規作成:
    • pkg/domain/types/vuln_status.go - VulnStatus 型定義(Active, Fixed)
    • pkg/domain/types/github.go - GitHubRepoID, BranchName 型定義を追加
    • pkg/domain/interfaces/scan_repository.go - リポジトリインターフェース
    • pkg/domain/model/repository.go - Repository モデル
    • pkg/domain/model/branch.go - Branch モデル
    • pkg/domain/model/target.go - Target モデル
    • pkg/domain/model/vulnerability.go - Vulnerability モデルと CVSS 構造体
    • pkg/repository/errors.go - 共通エラー定義
    • pkg/repository/memory/memory.go - メモリ実装のエントリポイント
    • pkg/repository/memory/scan.go - メモリ実装のスキャンリポジトリ
    • pkg/repository/firestore/firestore.go - Firestore実装のエントリポイント
    • pkg/repository/firestore/scan.go - Firestore実装のスキャンリポジトリ
    • pkg/repository/memory/scan_test.go - メモリ実装のテスト
    • pkg/repository/firestore/scan_test.go - Firestore実装のテスト
    • pkg/domain/mock/scan_repository_mock.go - モック(自動生成)
  • 修正: なし(既存コードへの影響を最小化)

実装ステップ

  • Step 1: ドメインモデルとインターフェース定義
    • pkg/domain/types/vuln_status.go を作成(VulnStatus型: Active, Fixed)
    • pkg/domain/types/github.go に GitHubRepoID, BranchName, TargetID 型を追加
    • pkg/domain/model/repository.go を作成(Repository構造体、タグなし
    • pkg/domain/model/branch.go を作成(Branch構造体、タグなし
    • pkg/domain/model/target.go を作成(Target構造体、タグなし
    • pkg/domain/model/vulnerability.go を作成(Vulnerability、CVSS構造体、ヘルパー関数、タグなし
    • pkg/domain/interfaces/scan_repository.go を作成(ScanRepositoryインターフェース)
    • pkg/repository/errors.go を作成(共通エラー定義)
  • Step 2: 共通テストヘルパーの作成
    • pkg/repository/testhelper/scan_repository_test.go を作成
    • Memory/Firestore両実装で使用する共通テスト関数を定義
  • Step 3: メモリ実装の作成
    • pkg/repository/memory/memory.go を作成(エントリポイント)
    • pkg/repository/memory/scan.go でScanRepository実装
      • map ベースのインメモリストレージ
      • Repository: map[types.GitHubRepoID]*model.Repository
      • Branch: map[types.GitHubRepoID]map[types.BranchName]*model.Branch
      • Target: map[types.GitHubRepoID]map[types.BranchName]map[types.TargetID]*model.Target
      • Vulnerability: map[types.GitHubRepoID]map[types.BranchName]map[types.TargetID]map[string]*model.Vulnerability
      • バッチステータス更新メソッドの実装
    • pkg/repository/memory/scan_test.go でユニットテスト実装
      • 共通テストヘルパーを使用
  • Step 4: Firestore実装の作成
    • pkg/repository/firestore/firestore.go を作成(エントリポイント)
    • pkg/repository/firestore/scan.go でScanRepository実装
      • コレクション: repo/{firestoreRepoID}/branch/{branchName}/target/{targetID}/vulnerability/{vulnID}
      • バッチ書き込み実装(500件ずつ)
      • バッチステータス更新実装
      • ToFirestoreID によるID変換(owner, repo → owner:repo)
    • pkg/repository/firestore/scan_test.go で統合テスト実装
      • 環境変数チェック(TEST_FIRESTORE_PROJECT_ID, TEST_FIRESTORE_DATABASE_ID)
      • 共通テストヘルパーを使用(Memory実装と同じテスト)
  • Step 5: モック生成とテスト完成
    • //go:generate moq ディレクティブを追加
    • task gen でモックを生成
    • すべてのテストを実行して動作確認
  • Step 6: CLI統合(オプショナル対応)
    • pkg/cli/scan.go を修正
      • Firestore関連のフラグを追加(project-id, database-id, collection-prefix等)
      • フラグが設定されている場合のみFirestore接続を初期化
      • 設定がない場合はBigQueryのみに保存
    • pkg/cli/serve.go を修正
      • Firestore関連のフラグを追加(project-id, database-id, collection-prefix等)
      • フラグが設定されている場合のみFirestore接続を初期化
      • webhook処理でFirestore保存をスキップ可能に
    • UseCase層の修正
      • pkg/usecase/scan_github_repo.go にFirestore保存処理を追加
      • ScanRepositoryがnilの場合はスキップするロジックを追加
    • 環境変数のドキュメント更新
      • OCTOVY_FIRESTORE_PROJECT_ID: Firestore project ID(オプショナル)
      • OCTOVY_FIRESTORE_DATABASE_ID: Firestore database ID(オプショナル)
      • OCTOVY_FIRESTORE_COLLECTION_PREFIX: Collection prefix(オプショナル、デフォルト: "")

テスト計画

テスト実装方針

  • 共通テストの原則: Memory実装とFirestore実装は必ず同じテストケースを実行
  • テストヘルパー関数: 共通のテストロジックを関数化し、両実装で再利用
  • 環境変数による実Firestore接続:
    • TEST_FIRESTORE_PROJECT_IDTEST_FIRESTORE_DATABASE_IDが設定されている場合のみ実Firestoreに接続
    • 未設定の場合はFirestoreテストをスキップ(Memory実装のみテスト)
    • CI環境では環境変数を設定して実Firestoreでテスト実行

テストケース

  • 共通テストヘルパーの作成

    • pkg/repository/testhelper/scan_repository_test.go に共通テスト関数を定義
    • TestRepositoryCRUD(t *testing.T, repo ScanRepository) - Repository操作テスト
    • TestBranchCRUD(t *testing.T, repo ScanRepository) - Branch操作テスト
    • TestVulnerabilityBatchOps(t *testing.T, repo ScanRepository) - Vulnerability操作テスト
    • TestVulnerabilityStatusUpdate(t *testing.T, repo ScanRepository) - ステータス更新テスト
  • Memory実装のテスト

    • pkg/repository/memory/scan_test.go
    • 共通テストヘルパーをMemory実装に適用
    • 並行アクセス時の動作確認(Memory固有)
  • Firestore実装のテスト

    • pkg/repository/firestore/scan_test.go
    • 環境変数チェック: TEST_FIRESTORE_PROJECT_IDTEST_FIRESTORE_DATABASE_ID
    • 未設定時はt.Skip("Firestore credentials not configured")
    • 設定時のみ共通テストヘルパーをFirestore実装に適用
    • ID変換テスト(ToFirestoreID/FromFirestoreID)
    • バッチ書き込み500件制限の確認
    • クリーンアップ処理(テスト後のデータ削除)
  • 統合テスト

    • NewVulnerability関数のテスト
      • Trivyの DetectedVulnerability から正しく変換
      • CVSS情報を元の構造(map[string]CVSS)で保持
      • Status初期値が Active であることを確認
      • 必須フィールドの検証
    • スキャン結果処理のシナリオテスト
      • 新規検出 → Active
      • 継続検出 → ステータス維持
      • Fixed → Active への再検出
      • 修正済み → Fixed への遷移

テスト例

// pkg/repository/memory/scan_test.go
func TestMemoryScanRepository(t *testing.T) {
    repo := New()
    testhelper.TestRepositoryCRUD(t, repo)
    testhelper.TestBranchCRUD(t, repo)
    testhelper.TestVulnerabilityBatchOps(t, repo)
    testhelper.TestVulnerabilityStatusUpdate(t, repo)
}

// pkg/repository/firestore/scan_test.go
func TestFirestoreScanRepository(t *testing.T) {
    projectID := os.Getenv("TEST_FIRESTORE_PROJECT_ID")
    databaseID := os.Getenv("TEST_FIRESTORE_DATABASE_ID")

    if projectID == "" || databaseID == "" {
        t.Skip("Firestore credentials not configured (TEST_FIRESTORE_PROJECT_ID, TEST_FIRESTORE_DATABASE_ID)")
    }

    repo, err := New(context.Background(), projectID, databaseID)
    gt.NoError(t, err)
    defer repo.Close()

    // Memory実装と同じテストを実行
    testhelper.TestRepositoryCRUD(t, repo)
    testhelper.TestBranchCRUD(t, repo)
    testhelper.TestVulnerabilityBatchOps(t, repo)
    testhelper.TestVulnerabilityStatusUpdate(t, repo)
}

リリース準備

  • 環境変数の追加
    • 本番環境:
      • OCTOVY_FIRESTORE_PROJECT_ID - Firestore プロジェクトID
      • OCTOVY_FIRESTORE_DATABASE_ID - Firestore データベースID(デフォルト: (default)
  • ドキュメントの更新
    • CLAUDE.md に新しいリポジトリ層の説明を追加
    • CLAUDE.md にFirestoreテストのパターンを追加
  • CI/CDパイプラインの確認 (要:CI環境での設定作業)
    • TEST_FIRESTORE_PROJECT_IDTEST_FIRESTORE_DATABASE_IDを設定して実Firestoreでテスト
    • テスト用Firestore環境の準備
    • 注記: コード実装は完了。CI環境でのFirestore認証情報設定が必要
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment