docs: update documentation to use CustomFieldValue/CustomField instead of Property/PropertyType

This commit is contained in:
Moritz 2026-01-06 19:52:58 +01:00
parent 3a0fb4e84f
commit 19a20635a7
Signed by: moritz
GPG key ID: 1020A035E5DD0824
3 changed files with 130 additions and 130 deletions

View file

@ -53,7 +53,7 @@ This document defines the implementation plan for the **MVP (Phase 1)** of the R
Hardcoded in `Mv.Authorization.PermissionSets` module:
1. **own_data** - User can only access their own data (default for "Mitglied")
2. **read_only** - Read access to all members/properties (for "Vorstand", "Buchhaltung")
2. **read_only** - Read access to all members/custom field values (for "Vorstand", "Buchhaltung")
3. **normal_user** - Create/Read/Update members (no delete), full CRUD on properties (for "Kassenwart")
4. **admin** - Unrestricted access including user/role management (for "Admin")
@ -77,7 +77,7 @@ Stored in database `roles` table, each referencing a `permission_set_name`:
- ✅ Hardcoded PermissionSets module with 4 permission sets
- ✅ Role database table and CRUD interface
- ✅ Custom Ash Policy Check (`HasPermission`) that reads from PermissionSets
- ✅ Policies on all resources (Member, User, Property, PropertyType, Role)
- ✅ Policies on all resources (Member, User, CustomFieldValue, CustomField, Role)
- ✅ Page-level permissions via Phoenix Plug
- ✅ UI authorization helpers for conditional rendering
- ✅ Special case: Member email validation for linked users
@ -228,32 +228,32 @@ Create the core `PermissionSets` module that defines all four permission sets wi
- Resources:
- User: read/update :own
- Member: read/update :linked
- Property: read/update :linked
- PropertyType: read :all
- CustomFieldValue: read/update :linked
- CustomField: read :all
- Pages: `["/", "/profile", "/members/:id"]`
**2. read_only (Vorstand, Buchhaltung):**
- Resources:
- User: read :own, update :own
- Member: read :all
- Property: read :all
- PropertyType: read :all
- Pages: `["/", "/members", "/members/:id", "/properties"]`
- CustomFieldValue: read :all
- CustomField: read :all
- Pages: `["/", "/members", "/members/:id", "/custom_field_values"]`
**3. normal_user (Kassenwart):**
- Resources:
- User: read/update :own
- Member: read/create/update :all (no destroy for safety)
- Property: read/create/update/destroy :all
- PropertyType: read :all
- Pages: `["/", "/members", "/members/new", "/members/:id", "/members/:id/edit", "/properties", "/properties/new", "/properties/:id/edit"]`
- CustomFieldValue: read/create/update/destroy :all
- CustomField: read :all
- Pages: `["/", "/members", "/members/new", "/members/:id", "/members/:id/edit", "/custom_field_values", "/custom_field_values/new", "/custom_field_values/:id/edit"]`
**4. admin:**
- Resources:
- User: read/update/destroy :all
- Member: read/create/update/destroy :all
- Property: read/create/update/destroy :all
- PropertyType: read/create/update/destroy :all
- CustomFieldValue: read/create/update/destroy :all
- CustomField: read/create/update/destroy :all
- Role: read/create/update/destroy :all
- Pages: `["*"]` (wildcard = all pages)
@ -276,10 +276,10 @@ Create the core `PermissionSets` module that defines all four permission sets wi
**Permission Content Tests:**
- `:own_data` allows User read/update with scope :own
- `:own_data` allows Member/Property read/update with scope :linked
- `:read_only` allows Member/Property read with scope :all
- `:read_only` does NOT allow Member/Property create/update/destroy
- `:normal_user` allows Member/Property full CRUD with scope :all
- `:own_data` allows Member/CustomFieldValue read/update with scope :linked
- `:read_only` allows Member/CustomFieldValue read with scope :all
- `:read_only` does NOT allow Member/CustomFieldValue create/update/destroy
- `:normal_user` allows Member/CustomFieldValue full CRUD with scope :all
- `:admin` allows everything with scope :all
- `:admin` has wildcard page permission "*"
@ -387,7 +387,7 @@ Create the core custom Ash Policy Check that reads permissions from the `Permiss
- `:own``{:filter, expr(id == ^actor.id)}`
- `:linked` → resource-specific logic:
- Member: `{:filter, expr(user_id == ^actor.id)}`
- Property: `{:filter, expr(member.user_id == ^actor.id)}` (traverse relationship!)
- CustomFieldValue: `{:filter, expr(member.user_id == ^actor.id)}` (traverse relationship!)
6. Handle errors gracefully:
- No actor → `{:error, :no_actor}`
- No role → `{:error, :no_role}`
@ -401,7 +401,7 @@ Create the core custom Ash Policy Check that reads permissions from the `Permiss
- [ ] Check module implements `Ash.Policy.Check` behavior
- [ ] `match?/3` correctly evaluates permissions from PermissionSets
- [ ] Scope filters work correctly (:all, :own, :linked)
- [ ] `:linked` scope handles Member and Property differently
- [ ] `:linked` scope handles Member and CustomFieldValue differently
- [ ] Errors are handled gracefully (no crashes)
- [ ] Authorization failures are logged
- [ ] Module is well-documented
@ -425,7 +425,7 @@ Create the core custom Ash Policy Check that reads permissions from the `Permiss
**Scope Application Tests - :linked:**
- Actor with scope :linked can access Member where member.user_id == actor.id
- Actor with scope :linked can access Property where property.member.user_id == actor.id (relationship traversal!)
- Actor with scope :linked can access CustomFieldValue where custom_field_value.member.user_id == actor.id (relationship traversal!)
- Actor with scope :linked cannot access unlinked member
- Query correctly filters based on user_id relationship
@ -581,7 +581,7 @@ Add authorization policies to the User resource. Special case: Users can always
---
#### Issue #9: Property Resource Policies
#### Issue #9: CustomFieldValue Resource Policies
**Size:** M (2 days)
**Dependencies:** #6 (HasPermission check)
@ -590,20 +590,20 @@ Add authorization policies to the User resource. Special case: Users can always
**Description:**
Add authorization policies to the Property resource. Properties are linked to members, which are linked to users.
Add authorization policies to the CustomFieldValue resource. CustomFieldValues are linked to members, which are linked to users.
**Tasks:**
1. Open `lib/mv/membership/property.ex`
1. Open `lib/mv/membership/custom_field_value.ex`
2. Add `policies` block
3. Add special policy: Allow user to read/update properties of their linked member
3. Add special policy: Allow user to read/update custom field values of their linked member
```elixir
policy action_type([:read, :update]) do
authorize_if expr(member.user_id == ^actor(:id))
end
```
4. Add general policy: Check HasPermission
5. Ensure Property preloads :member relationship for scope checks
5. Ensure CustomFieldValue preloads :member relationship for scope checks
6. Preload :role relationship for actor
**Policy Order:**
@ -620,27 +620,27 @@ Add authorization policies to the Property resource. Properties are linked to me
**Test Strategy (TDD):**
**Linked Properties Tests (:own_data):**
- User can read properties of their linked member
- User can update properties of their linked member
- User cannot read properties of unlinked members
- Verify relationship traversal works (property.member.user_id)
**Linked CustomFieldValues Tests (:own_data):**
- User can read custom field values of their linked member
- User can update custom field values of their linked member
- User cannot read custom field values of unlinked members
- Verify relationship traversal works (custom_field_value.member.user_id)
**Read-Only Tests:**
- User with :read_only can read all properties
- User with :read_only cannot create/update properties
- User with :read_only can read all custom field values
- User with :read_only cannot create/update custom field values
**Normal User Tests:**
- User with :normal_user can CRUD properties
- User with :normal_user can CRUD custom field values
**Admin Tests:**
- Admin can perform all operations
**Test File:** `test/mv/membership/property_policies_test.exs`
**Test File:** `test/mv/membership/custom_field_value_policies_test.exs`
---
#### Issue #10: PropertyType Resource Policies
#### Issue #10: CustomField Resource Policies
**Size:** S (1 day)
**Dependencies:** #6 (HasPermission check)
@ -649,11 +649,11 @@ Add authorization policies to the Property resource. Properties are linked to me
**Description:**
Add authorization policies to the PropertyType resource. PropertyTypes are admin-managed, but readable by all.
Add authorization policies to the CustomField resource. CustomFields are admin-managed, but readable by all.
**Tasks:**
1. Open `lib/mv/membership/property_type.ex`
1. Open `lib/mv/membership/custom_field.ex`
2. Add `policies` block
3. Add read policy: All authenticated users can read (scope :all)
4. Add write policies: Only admin can create/update/destroy
@ -661,27 +661,27 @@ Add authorization policies to the PropertyType resource. PropertyTypes are admin
**Acceptance Criteria:**
- [ ] All users can read property types
- [ ] Only admin can create/update/destroy property types
- [ ] All users can read custom fields
- [ ] Only admin can create/update/destroy custom fields
- [ ] Policies tested
**Test Strategy (TDD):**
**Read Access (All Roles):**
- User with :own_data can read all property types
- User with :read_only can read all property types
- User with :normal_user can read all property types
- User with :admin can read all property types
- User with :own_data can read all custom fields
- User with :read_only can read all custom fields
- User with :normal_user can read all custom fields
- User with :admin can read all custom fields
**Write Access (Admin Only):**
- Non-admin cannot create property type (Forbidden)
- Non-admin cannot update property type (Forbidden)
- Non-admin cannot destroy property type (Forbidden)
- Admin can create property type
- Admin can update property type
- Admin can destroy property type
- Non-admin cannot create custom field (Forbidden)
- Non-admin cannot update custom field (Forbidden)
- Non-admin cannot destroy custom field (Forbidden)
- Admin can create custom field
- Admin can update custom field
- Admin can destroy custom field
**Test File:** `test/mv/membership/property_type_policies_test.exs`
**Test File:** `test/mv/membership/custom_field_policies_test.exs`
---
@ -924,7 +924,7 @@ Create helper functions for UI-level authorization checks. These will be used in
```
5. All functions use `PermissionSets.get_permissions/1` (same logic as HasPermission)
6. All functions handle nil user gracefully (return false)
7. Implement resource-specific scope checking (Member vs Property for :linked)
7. Implement resource-specific scope checking (Member vs CustomFieldValue for :linked)
8. Add comprehensive `@doc` with template examples
9. Import helper in `mv_web.ex` `html_helpers` section
@ -957,9 +957,9 @@ Create helper functions for UI-level authorization checks. These will be used in
**can?/3 with Record Struct - Scope :linked:**
- User can update linked Member (member.user_id == user.id)
- User cannot update unlinked Member
- User can update Property of linked Member (property.member.user_id == user.id)
- User cannot update Property of unlinked Member
- Scope checking is resource-specific (Member vs Property)
- User can update CustomFieldValue of linked Member (custom_field_value.member.user_id == user.id)
- User cannot update CustomFieldValue of unlinked Member
- Scope checking is resource-specific (Member vs CustomFieldValue)
**can_access_page?/2:**
- User with page in list can access (returns true)
@ -1046,7 +1046,7 @@ Update Role management LiveViews to use authorization helpers for conditional re
**Description:**
Update all existing LiveViews (Member, User, Property, PropertyType) to use authorization helpers for conditional rendering.
Update all existing LiveViews (Member, User, CustomFieldValue, CustomField) to use authorization helpers for conditional rendering.
**Tasks:**
@ -1061,10 +1061,10 @@ Update all existing LiveViews (Member, User, Property, PropertyType) to use auth
- Show: Only show other users if admin, always show own profile
- Edit: Only allow editing own profile or admin editing anyone
3. **Property LiveViews:**
3. **CustomFieldValue LiveViews:**
- Similar to Member (hide create/edit/delete based on permissions)
4. **PropertyType LiveViews:**
4. **CustomField LiveViews:**
- All users can view
- Only admin can create/edit/delete
@ -1110,13 +1110,13 @@ Update all existing LiveViews (Member, User, Property, PropertyType) to use auth
- Vorstand: Sees "Home", "Members" (read-only), "Profile"
- Kassenwart: Sees "Home", "Members", "Properties", "Profile"
- Buchhaltung: Sees "Home", "Members" (read-only), "Profile"
- Admin: Sees "Home", "Members", "Properties", "Property Types", "Admin", "Profile"
- Admin: Sees "Home", "Members", "Custom Field Values", "Custom Fields", "Admin", "Profile"
**Test Files:**
- `test/mv_web/live/member_live_authorization_test.exs`
- `test/mv_web/live/user_live_authorization_test.exs`
- `test/mv_web/live/property_live_authorization_test.exs`
- `test/mv_web/live/property_type_live_authorization_test.exs`
- `test/mv_web/live/custom_field_value_live_authorization_test.exs`
- `test/mv_web/live/custom_field_live_authorization_test.exs`
- `test/mv_web/components/navbar_authorization_test.exs`
---
@ -1192,7 +1192,7 @@ Write comprehensive integration tests that follow complete user journeys for eac
4. Can edit any member (except email if linked - see special case)
5. Cannot delete member
6. Can manage properties
7. Cannot manage property types (read-only)
7. Cannot manage custom fields (read-only)
8. Cannot access /admin/roles
**Buchhaltung Journey:**
@ -1266,7 +1266,7 @@ Write comprehensive integration tests that follow complete user journeys for eac
│ │ │
┌────▼─────┐ ┌──────▼──────┐ │
│ Issue #9 │ │ Issue #10 │ │
Property │ │ PropType │ │
CustomFieldValue │ │ CustomField │ │
│ Policies │ │ Policies │ │
└────┬─────┘ └──────┬──────┘ │
│ │ │
@ -1384,8 +1384,8 @@ test/
├── mv/membership/
│ ├── member_policies_test.exs # Issue #7
│ ├── member_email_validation_test.exs # Issue #12
│ ├── property_policies_test.exs # Issue #9
│ └── property_type_policies_test.exs # Issue #10
│ ├── custom_field_value_policies_test.exs # Issue #9
│ └── custom_field_policies_test.exs # Issue #10
├── mv_web/
│ ├── authorization_test.exs # Issue #14
│ ├── plugs/
@ -1395,8 +1395,8 @@ test/
│ ├── role_live_authorization_test.exs # Issue #15
│ ├── member_live_authorization_test.exs # Issue #16
│ ├── user_live_authorization_test.exs # Issue #16
│ ├── property_live_authorization_test.exs # Issue #16
│ └── property_type_live_authorization_test.exs # Issue #16
│ ├── custom_field_value_live_authorization_test.exs # Issue #16
│ └── custom_field_live_authorization_test.exs # Issue #16
├── integration/
│ ├── mitglied_journey_test.exs # Issue #17
│ ├── vorstand_journey_test.exs # Issue #17