feat: Shared Kernel に Affiliation(所属) を追加#81
Conversation
f84d664 to
7d0867c
Compare
## Summary - 学籍番号(StudentId)の値オブジェクトをSharedKernelとして追加 - 旧形式(8桁数字)と新形式(3桁数字+英字+4桁数字)の両方に対応 - `fromString` ファクトリメソッドで小文字→大文字正規化・空白トリムを実施 - private constructorにより直接インスタンス化を防止 - 12件のユニットテストを追加 ## Test plan - [x] 旧形式・新形式の正常系テスト - [x] 大文字正規化・空白トリムのテスト - [x] 桁数不正・英字のみ・英字位置不正・空文字等の異常系テスト - [x] equalsメソッドの等価性テスト - [x] lint, typecheck, test全てパス ## Related - PR #81 から StudentId 部分を分割したPR - マージ後、PR #81 をリベースしてAffiliation部分のみにする 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/su-its/core/pull/87" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
静岡大学の全学部・研究科の組織構造を型レベルで表現し、 ValueObject<T> パターンでランタイムバリデーション付きの Affiliation クラス群を実装。 - UndergraduateAffiliation / MasterAffiliation / DoctoralAffiliation / ProfessionalAffiliation - 学部ごとに異なる分類子(学科・課程・専攻・コース・専修)を discriminated union で表現 - StudentId 値オブジェクト(旧形式8桁 / 新形式3桁+英字+4桁) - 関連するドメイン例外を追加 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
型レベルの判別共用体で制約が保証されるため、 ランタイムバリデーションはValueObjectの責務ではなくシステム境界の責務とする。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
各学部・研究科の型定義に日本語名のJSDocコメントと 公式組織構成ページへの@seeリンクを追加。 バリデーター削除で不要になった例外クラスも削除。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
05fb324 to
0bb3aba
Compare
KinjiKawaguchi
left a comment
There was a problem hiding this comment.
ユビキタス言語との対応といった意味でJsDocでフィールドについてそれなりに記述しておくべきだと思うがそういった取り組みが見られない
型レベルで安全性を保証する設計のため不要だったInvalidAffiliationExceptionを削除。 universityStructure.tsのフィールドにユビキタス言語との対応を示すJSDocを追加。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
教育学部のURLは EducationFacultyValue の型JSDocに既にあるため重複を解消。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
📝 Info: ValueObject.equals() uses JSON.stringify which is key-order-dependent for these complex objects
The base ValueObject.equals() at src/domain/base/ValueObject.ts:16 compares values via JSON.stringify(this.value) === JSON.stringify(vo.value). For the new Affiliation value types — which are plain objects with multiple keys — this comparison is sensitive to property insertion order. Two semantically identical affiliation objects constructed with properties in different orders would be considered unequal. This is a pre-existing design characteristic of ValueObject, not introduced by this PR, but it becomes more relevant now that ValueObject is being used with multi-field objects rather than primitives or simple types.
Was this helpful? React with 👍 or 👎 to provide feedback.
KikyoNanakusa
left a comment
There was a problem hiding this comment.
一旦いいと思うけど、大学の学部や学科区分は不変ではないことに今後は注意してね
| // ── 年次 ── | ||
|
|
||
| export type UndergraduateYear = 1 | 2 | 3 | 4; | ||
| export type MasterYear = 1 | 2; |
There was a problem hiding this comment.
それはM2何じゃないか、進級という概念があるんだろうか?...
| import type { | ||
| DoctoralAffiliationValue, | ||
| MasterAffiliationValue, | ||
| ProfessionalAffiliationValue, |
There was a problem hiding this comment.
https://www.shizuoka.ac.jp/subject/
を見ると博士課程以外に専門職学位課程というのがあるらしいのでそれ。ただ英訳については疑義あり
## Summary - `Event.removeExhibitMemberId`のボディが空で、展示からのメンバー削除がno-opだった問題を修正 - 該当Exhibitからメンバーを削除し、他のExhibitにも所属していなければEvent.memberIdsからも削除する - PR #81 のレビューで指摘された pre-existing issue への対応 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/su-its/core/pull/85" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - 学籍番号(StudentId)の値オブジェクトをSharedKernelとして追加 - 旧形式(8桁数字)と新形式(3桁数字+英字+4桁数字)の両方に対応 - `fromString` ファクトリメソッドで小文字→大文字正規化・空白トリムを実施 - private constructorにより直接インスタンス化を防止 - 12件のユニットテストを追加 ## Test plan - [x] 旧形式・新形式の正常系テスト - [x] 大文字正規化・空白トリムのテスト - [x] 桁数不正・英字のみ・英字位置不正・空文字等の異常系テスト - [x] equalsメソッドの等価性テスト - [x] lint, typecheck, test全てパス ## Related - PR #81 から StudentId 部分を分割したPR - マージ後、PR #81 をリベースしてAffiliation部分のみにする 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/su-its/core/pull/87" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - `Event.removeExhibitMemberId`のボディが空で、展示からのメンバー削除がno-opだった問題を修正 - 該当Exhibitからメンバーを削除し、他のExhibitにも所属していなければEvent.memberIdsからも削除する - PR #81 のレビューで指摘された pre-existing issue への対応 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/su-its/core/pull/85" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - 値オブジェクトを所属する集約ディレクトリに移動し、`domain/base` に `ValueObject` を配置 - Shared Kernel として `Affiliation`(学部・修士・博士・専門職)と `StudentId` 値オブジェクトを追加 - 静岡大学の全組織構造を型レベルの判別共用体で表現(学部ごとに異なる階層構造を正確にモデル化) - Affiliation のバリデーションは型制約で保証し、ランタイム検証はシステム境界の責務とする設計 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/su-its/core/pull/81" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
domain/baseにValueObjectを配置Affiliation(学部・修士・博士・専門職)とStudentId値オブジェクトを追加🤖 Generated with Claude Code