# 機能設計書 55-Uid

## 概要

本ドキュメントは、Symfony Uidコンポーネントの機能設計を記述する。Uidコンポーネントは一意識別子(UUID/ULID)の生成・操作のオブジェクト指向APIを提供し、UUID v1/v3/v4/v5/v6/v7/v8およびULIDに対応する。

### 本機能の処理概要

UidコンポーネントはRFC 9562(旧RFC 4122)準拠のUUID生成と、ULID仕様に準拠したULID生成を行う。各種形式(RFC 4122、Base32、Base58、バイナリ、16進数)間の変換機能を提供し、時間ベースUIDからのタイムスタンプ抽出も可能。

**業務上の目的・背景**：分散システムやマイクロサービスアーキテクチャでは、グローバルに一意な識別子が不可欠である。特にUUID v7やULIDはタイムスタンプを含むためソート可能であり、データベースのプライマリキーとして優れた特性を持つ。Uidコンポーネントは、これらの一意識別子を統一されたAPIで生成・管理する。

**機能の利用シーン**：データベースレコードの一意識別子生成、分散システム間のメッセージID生成、ファイル名のユニーク化、API リソースのID生成、イベントトレーシング用ID生成。

**主要な処理内容**：
1. UUID v1(時間ベース+MACアドレス)の生成
2. UUID v3(MD5名前空間ベース)の生成
3. UUID v4(ランダム)の生成
4. UUID v5(SHA-1名前空間ベース)の生成
5. UUID v6(再順序化時間ベース)の生成
6. UUID v7(Unixエポックタイムスタンプ+ランダム、ミリ秒精度)の生成
7. UUID v8(カスタム)の生成
8. ULID(タイムスタンプ+ランダム、Base32エンコード)の生成
9. 各種形式間の変換(RFC 4122、Base32、Base58、バイナリ、16進数)
10. 時間ベースUID(v1, v6, v7, ULID)からのDateTimeImmutable抽出

**関連システム・外部連携**：PHP random_bytes()関数(CSPRNG)、PHP uuid拡張(オプション、uuid_compare利用)。

**権限による制御**：権限制御は実装されていない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 直接関連する画面はない。アプリケーション全体のID生成基盤として機能 |

## 機能種別

データ生成 / ユーティリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uuid | string|null | No(生成時) | UUID文字列(RFC 4122形式) | isValid()で検証。形式: `^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$` |
| ulid | string|null | No(生成時) | ULID文字列(Base32形式) | isValid()で検証。26文字のCrockford Base32 |
| namespace | Uuid | Yes(v3/v5) | 名前空間UUID | 有効なUuidインスタンス |
| name | string | Yes(v3/v5) | ハッシュ対象の名前文字列 | 任意の文字列 |
| time | DateTimeInterface|null | No | タイムスタンプ指定(v7, ULID生成時) | 正のタイムスタンプ |

### 入力データソース

PHPのCSPRNG(random_bytes)、システムクロック(microtime)。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uuid | UuidV1/V3/V4/V5/V6/V7/V8 | 生成されたUUIDオブジェクト |
| ulid | Ulid | 生成されたULIDオブジェクト |
| rfc4122 | string | RFC 4122形式文字列(36文字) |
| base32 | string | Base32形式文字列(26文字) |
| base58 | string | Base58形式文字列(22文字) |
| binary | string | バイナリ形式(16バイト) |
| hex | string | 16進数形式(0xプレフィックス付き34文字) |
| dateTime | DateTimeImmutable | 時間ベースUIDから抽出されたタイムスタンプ |

### 出力先

呼び出し元のアプリケーションコード(エンティティID、メッセージID等)。

## 処理フロー

### 処理シーケンス

```
1. UUID/ULID生成
   └─ new UuidV7() / new Ulid() / Uuid::v4() 等
2. タイムスタンプ取得(UUID v7の場合)
   └─ microtime()からミリ秒精度のタイムスタンプを取得
3. ランダム部分の生成
   └─ random_bytes()でCSPRNG乱数を生成
4. 同一ミリ秒内の単調増加保証(v7, ULID)
   └─ ランダム部分を24ビットランダム値でインクリメント
   └─ オーバーフロー時はusleep(1)で次のミリ秒まで待機
5. フォーマット適用
   └─ バージョンビット、バリアントビットの設定
6. 文字列形式への変換
   └─ toRfc4122(), toBase32(), toBase58(), toBinary(), toHex()
```

### フローチャート

```mermaid
flowchart TD
    A[UID生成要求] --> B{UUIDまたはULID?}
    B -->|UUID v7| C[microtime取得]
    B -->|ULID| D[microtime取得]
    B -->|UUID v4| E[random_bytes]
    B -->|UUID v3/v5| F[namespace + name ハッシュ]
    C --> G[ランダム部分生成]
    D --> H[ランダム部分生成]
    G --> I{同一ms内?}
    H --> J{同一ms内?}
    I -->|Yes| K[ランダム部分をインクリメント]
    I -->|No| L[新規ランダム生成]
    J -->|Yes| M[ランダム部分をインクリメント]
    J -->|No| N[新規ランダム生成]
    K --> O[フォーマット適用]
    L --> O
    M --> O
    N --> O
    E --> O
    F --> O
    O --> P[UIDオブジェクト返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-55-01 | 単調増加性 | UUID v7/ULIDは同一ミリ秒内でも単調増加することを保証する | 同一プロセス内での連続生成時 |
| BR-55-02 | マイクロ秒精度 | UUID v7はサブミリ秒(10ビット精度、約1マイクロ秒)の精度を持つ | UUID v7生成時 |
| BR-55-03 | バリアントチェック | UUID構築時にバリアントビット(19文字目が8/9/a/b)を検証する | UuidV7コンストラクタ(checkVariant=true) |
| BR-55-04 | フォーマット自動判定 | Uuid::fromString()は入力形式(RFC 4122, Base32, Base58, バイナリ)を自動判定する | fromString()呼び出し時 |
| BR-55-05 | Nil/Max UUID | 全ビットが0のNilUuidと全ビットが1のMaxUuidは特殊値として扱う | fromString()での自動検出 |

### 計算ロジック

UUID v7の同一ミリ秒内インクリメントは、sha512ハッシュベースのシード生成で24ビットランダム値を効率的に提供する(UuidV7.php 87-96行目)。21回のインクリメントごとにsha512を再計算して64バイトのエントロピーを更新する。

## データベース操作仕様

本コンポーネントはデータベース操作を行わない。ただし、生成されたUUID/ULIDはデータベースのプライマリキーや外部キーとして広く使用される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidArgumentException | 無効なUUID文字列が渡された場合 | isValid()で事前検証 |
| - | InvalidArgumentException | 無効なULID文字列が渡された場合 | isValid()で事前検証 |
| - | InvalidArgumentException | バイナリUID長が16バイトでない場合 | 正しいバイナリ長を指定 |
| - | InvalidArgumentException | 負のタイムスタンプが指定された場合 | 正のタイムスタンプを指定 |

### リトライ仕様

リトライ機構は不要。ただしUUID v7のオーバーフロー時はusleep(1)で次のミリ秒まで待機する。

## トランザクション仕様

トランザクション管理は対象外。

## パフォーマンス要件

- UUID v7はrandom_bytes()の呼び出しを最小化するため、sha512シードベースのインクリメント方式を採用(UuidV7.php 73-96行目)
- ULIDは同一ミリ秒内でランダム部分を単純インクリメントし、高速に生成
- uuid_compare()が利用可能な場合はPHP uuid拡張の比較関数を使用(Uuid.php 174行目)

## セキュリティ考慮事項

- UUID v4/v7はrandom_bytes()を使用し暗号的に安全
- UUID v1はMACアドレスを含むため、プライバシーが必要な場合はv4/v7を推奨
- UUID v3/v5は決定的であり、同一入力からは常に同一UUIDが生成される

## 備考

RFC 9562はRFC 4122の後継規格であり、UUID v6/v7/v8を追加定義している。SymfonyのUuidクラスはFORMAT_RFC_9562をFORMAT_RFC_4122のエイリアスとして定義している。

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AbstractUid.php | `src/Symfony/Component/Uid/AbstractUid.php` | UIDの基底クラス、$uidプロパティ、各形式への変換メソッド |
| 1-2 | HashableInterface.php | `src/Symfony/Component/Uid/HashableInterface.php` | ハッシュ可能インターフェース |
| 1-3 | TimeBasedUidInterface.php | `src/Symfony/Component/Uid/TimeBasedUidInterface.php` | 時間ベースUID用インターフェース(getDateTime) |
| 1-4 | BinaryUtil.php | `src/Symfony/Component/Uid/BinaryUtil.php` | バイナリ変換ユーティリティ(Base10, Base58変換) |

**読解のコツ**: AbstractUidはprotectedな `$uid` プロパティに正規形(canonical form)の文字列を保持。UuidはRFC 4122形式、ULIDはBase32形式が正規形。

#### Step 2: UUID実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Uuid.php | `src/Symfony/Component/Uid/Uuid.php` | UUID基底クラス、v1()-v8()ファクトリメソッド、fromString()の自動判定 |
| 2-2 | UuidV7.php | `src/Symfony/Component/Uid/UuidV7.php` | v7生成ロジック、タイムスタンプ+サブms精度、sha512シードインクリメント |
| 2-3 | UuidV4.php | `src/Symfony/Component/Uid/UuidV4.php` | v4ランダム生成 |

**主要処理フロー**:
- **Uuid.php 39-52行目**: コンストラクタ - RFC 4122形式のバリデーション、バージョンチェック
- **Uuid.php 54-84行目**: fromString() - 入力形式自動判定、バージョンに応じた具象クラス返却
- **Uuid.php 130-153行目**: isValid() - フォーマットマスクによる柔軟な検証
- **UuidV7.php 58-148行目**: generate() - タイムスタンプ取得、ランダム生成、単調増加インクリメント

#### Step 3: ULID実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Ulid.php | `src/Symfony/Component/Uid/Ulid.php` | ULID生成、Base32正規形、Crockford Base32エンコーディング |

**主要処理フロー**:
- **Ulid.php 187-243行目**: generate() - タイムスタンプ+80ビットランダム、単調増加、Base32変換
- **Ulid.php 165-185行目**: getDateTime() - Base32デコードしてミリ秒タイムスタンプからDateTimeImmutable生成

### プログラム呼び出し階層図

```
Uuid::v7()
    +-- new UuidV7()
            +-- UuidV7::generate()
                    +-- microtime() [タイムスタンプ]
                    +-- random_bytes() / sha512シード [ランダム]
                    +-- sprintf() [RFC 4122形式化]

Uuid::fromString($uuid)
    +-- transformToRfc9562() [形式変換]
    +-- match(int($uuid[14])) [バージョン判定]
    +-- new UuidV1/V3/V4/V5/V6/V7/V8($uuid)

new Ulid()
    +-- Ulid::generate()
            +-- microtime() [タイムスタンプ]
            +-- random_bytes() [80ビットランダム]
            +-- base_convert() + strtr() [Crockford Base32]
```

### データフロー図

```
[入力]                       [処理]                           [出力]

システムクロック ────────> タイムスタンプ取得           UuidV7/Ulid
CSPRNG ─────────────────> ランダム値生成                   |
                            |                              v
                    フォーマット適用                toRfc4122() -> "550e8400-..."
                    (バージョン/バリアント)         toBase32()  -> "01ARZ3ND..."
                                                   toBinary()  -> 16バイト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AbstractUid.php | `src/Symfony/Component/Uid/AbstractUid.php` | ソース | UID基底クラス |
| Uuid.php | `src/Symfony/Component/Uid/Uuid.php` | ソース | UUID基底クラス、ファクトリメソッド |
| UuidV1.php | `src/Symfony/Component/Uid/UuidV1.php` | ソース | UUID v1実装 |
| UuidV3.php | `src/Symfony/Component/Uid/UuidV3.php` | ソース | UUID v3実装 |
| UuidV4.php | `src/Symfony/Component/Uid/UuidV4.php` | ソース | UUID v4実装 |
| UuidV5.php | `src/Symfony/Component/Uid/UuidV5.php` | ソース | UUID v5実装 |
| UuidV6.php | `src/Symfony/Component/Uid/UuidV6.php` | ソース | UUID v6実装 |
| UuidV7.php | `src/Symfony/Component/Uid/UuidV7.php` | ソース | UUID v7実装 |
| UuidV8.php | `src/Symfony/Component/Uid/UuidV8.php` | ソース | UUID v8実装 |
| Ulid.php | `src/Symfony/Component/Uid/Ulid.php` | ソース | ULID実装 |
| NilUuid.php | `src/Symfony/Component/Uid/NilUuid.php` | ソース | Nil UUID(全ゼロ) |
| MaxUuid.php | `src/Symfony/Component/Uid/MaxUuid.php` | ソース | Max UUID(全1) |
| NilUlid.php | `src/Symfony/Component/Uid/NilUlid.php` | ソース | Nil ULID |
| MaxUlid.php | `src/Symfony/Component/Uid/MaxUlid.php` | ソース | Max ULID |
| BinaryUtil.php | `src/Symfony/Component/Uid/BinaryUtil.php` | ソース | バイナリ変換ユーティリティ |
| TimeBasedUidInterface.php | `src/Symfony/Component/Uid/TimeBasedUidInterface.php` | ソース | 時間ベースUIDインターフェース |
