Repository navigation
✨ org-accounts-foundation: Account 種別 + 組織作成 + メンバーシップ 3段階ロール (#55) - #56
Conversation
…on in roundtrip test (#55) Postgres timestamptz stores microsecond precision; comparing the nanosecond-precision local expectation made the entity equality flaky (CI coverage run 33505931615 failed on a sub-microsecond mismatch).
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #56 +/- ##
==========================================
- Coverage 76.28% 75.68% -0.61%
==========================================
Files 200 209 +9
Lines 23200 24496 +1296
==========================================
+ Hits 17698 18539 +841
- Misses 5502 5957 +455 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Review: request-update (org-accounts-foundation review)Semantic review 結果、request-update です。AC1-10 の実装本体は packet 設計に整合していますが、AC11 と既存 surface への副作用で 2 件の修正が必要です。worktree read-only 参照 + diff 精査で確認済み (head 8ad26ed)。 Blocking1. AC11 単体テスト不足 (作成・ロール変更成功・除名成功が未検証)
"作成・招待フロー・ロール変更・除名・脱退・権限拒否が検証される" のうち 作成/ロール変更/除名 の成功系を 2. 既存
|
Lock active owner rows, count owners, and mutate membership in one transaction for owner demotion and leave paths. Non-member self-leave remains NotFound: the requested membership row does not exist. PermissionDenied remains the contract for managing another account's membership without organization membership.
org-accounts-foundation: Account kind 判別 + 組織作成 + メンバーシップ 3段階ロール
Summary
組織 Account 基盤を実装する。Account に personal/organization の kind 判別を導入し、
organization_membersテーブル + CRUD repository + 組織作成/招待/承諾/ロール変更/除名/脱退/所属組織一覧の client REST API を新設した。
Changes
accounts.kind TEXT NOT NULL DEFAULT 'personal'(+ CHECK)、既存レコードは'personal' backfill /
organization_members (org_account_id, member_account_id, role, status, invited_by, created_at, PK(org,member), FK→accounts ON DELETE CASCADE)AccountKind { Personal, Organization }(#[serde(default)]で旧 Created event は Personalに後方互換)、
Accountに kind フィールド、Account::create_organization新設(personal→organization 変換経路は存在しない)
OrganizationMembershipエンティティ (OrgRole: Owner/Admin/Member, status: pending/active)kernel/src/repository/organization_membership.rs) + Query facade(
kernel/src/read_model/organization_membership.rs)、impl_database_delegation!追加PostgresOrganizationMembershipRepository(CRUD + owner count)、account projection/read model が kind を読み書き、組織 Account では Keto owner relation を
作成しない (組織ロール判定は organization_members 直接クエリ。Keto Organization namespace
は新設しない)
service/organization/pending)、accept (本人のみ pending→active)、change role (Owner のみ、最後の Owner の降格
は Rejected)、remove (Owner/Admin、Owner は除名不可)、leave (本人、最後の Owner は
Rejected)、list my organizations
OrgAccountApifacade +OrgAccountRouterPOST /api/v1/organizations、GET /api/v1/me/organizations、GET /api/v1/organizations/{org}/members(pending 含む)、POST .../invites、POST .../invites/{account_id}/accept、PUT .../members/{account_id}/role、DELETE .../members/{account_id}(self = leave)ErrorStatus規約: PermissionDenied→403, NotFound→404,Rejected→422, 不正入力→400
openapi.json再生成Acceptance criteria 対応
20260901000001_add_account_kind.sql#[serde(default)]+ 既存 legacy regression test 維持Account::create_organizationのみ kind=Organization を生成Verification
cargo fmt --all -- --check: passcargo clippy --workspace --all-features -- -D warnings: passcargo test --workspace --lib: 228 passed / 0 failed / 150 ignored(kernel 96, application 87, driver 45。ignored はすべて
DATABASE_URL不在による既存 self-skip)
除名・脱退・権限拒否・last-owner guard を網羅
DATABASE_URLgated で整備済み(本 CI 環境では skip)
Out of scope (packet 通り)
認証コンテキスト切替 (org-accounts-auth-context)、Profile 移管、AP 連合、課金、
Warning イベント、Keto Organization namespace、組織解散フロー (既存 Account 削除に準ずる)。
Closes #55
Review round 1 (request-update) 対応
Blocking 1 (AC11 success-path tests):
organization/tests.rsに追加create_organization_persists_organization_owner_and_auth_link— kind=Organization + 作成者 Active Owner membership + auth link 呼び出しを assertowner_changes_active_member_role_to_admin— member→admin 変更の永続化owner_removes_active_member— active member 除名後に membership 削除Blocking 2 (GET /api/v1/accounts への組織混入):
account/read.rsget_all_accountsにAccountKind::Personalfilter を追加 (他のfind_by_auth_id呼び出しは不変更)。回帰テストget_all_accounts_excludes_organization_accounts追加。組織一覧は AC7 の/me/organizationsのみが担う。Advisory 対応
lock_active_owner_rows(SELECT ... FOR UPDATEon active owner rows) を追加し、owner demotion / owner leave の両方で lock→count→mutation を単一 transaction 化。invited_by: 修正。member 一覧で nanoid を返す (schema description/example + openapi.json 再生成済み)。