+
+
+
-
- <.link navigate={~p"/members"} class="btn btn-primary">
- Members
-
+
```
@@ -1535,15 +1554,57 @@ policies do
authorize_if always()
end
- # Specific permissions
- policy action_type([:read, :update]) do
- authorize_if relates_to_actor_via(:user)
+ # Use HasPermission check for role-based authorization
+ policy action_type([:read, :update, :create, :destroy]) do
+ authorize_if Mv.Authorization.Checks.HasPermission
end
+end
+```
- policy action_type(:destroy) do
- authorize_if actor_attribute_equals(:role, :admin)
+**Actor Handling in LiveViews:**
+
+Always use the `current_actor/1` helper for consistent actor access:
+
+```elixir
+# In LiveView modules
+import MvWeb.LiveHelpers, only: [current_actor: 1, ash_actor_opts: 1, submit_form: 3]
+
+def mount(_params, _session, socket) do
+ actor = current_actor(socket)
+
+ case Ash.read(Mv.Membership.Member, ash_actor_opts(actor)) do
+ {:ok, members} ->
+ {:ok, assign(socket, :members, members)}
+ {:error, error} ->
+ {:ok, put_flash(socket, :error, "Failed to load members")}
end
end
+
+def handle_event("save", %{"member" => params}, socket) do
+ actor = current_actor(socket)
+ form = AshPhoenix.Form.for_create(Mv.Membership.Member, :create)
+
+ case submit_form(form, params, actor) do
+ {:ok, member} ->
+ {:noreply, push_navigate(socket, to: ~p"/members/#{member.id}")}
+ {:error, form} ->
+ {:noreply, assign(socket, :form, form)}
+ end
+end
+```
+
+**Never use bang calls (`Ash.read!`, `Ash.get!`) without error handling:**
+
+```elixir
+# Bad - will crash on authorization errors
+members = Ash.read!(Mv.Membership.Member, actor: actor)
+
+# Good - proper error handling
+case Ash.read(Mv.Membership.Member, actor: actor) do
+ {:ok, members} -> # success
+ {:error, %Ash.Error.Forbidden{}} -> # handle authorization error
+ {:error, error} -> # handle other errors
+end
```
### 5.2 Password Security
diff --git a/README.md b/README.md
index 6255f8d..fbaddea 100644
--- a/README.md
+++ b/README.md
@@ -40,14 +40,16 @@ Our philosophy: **software should help people spend less time on administration
## 🔑 Features
- ✅ Manage member data with ease
-- 🚧 Overview of membership fees & payment status
-- ✅ Full-text search
-- 🚧 Sorting & filtering
-- 🚧 Roles & permissions (e.g. board, treasurer)
+- ✅ Membership fees & payment status tracking
+- ✅ Full-text search with fuzzy matching
+- ✅ Sorting & filtering
+- ✅ Roles & permissions (RBAC system with 4 permission sets)
- ✅ Custom fields (flexible per club needs)
- ✅ SSO via OIDC (works with Authentik, Rauthy, Keycloak, etc.)
+- ✅ Sidebar navigation (standard-compliant, accessible)
+- ✅ Global settings management
- 🚧 Self-service & online application
-- 🚧 Accessibility, GDPR, usability improvements
+- ✅ Accessibility improvements (WCAG 2.1 AA compliant keyboard navigation)
- 🚧 Email sending
## 🚀 Quick Start (Development)
diff --git a/docs/csv-member-import-v1.md b/docs/csv-member-import-v1.md
index bc8f99f..05e4e48 100644
--- a/docs/csv-member-import-v1.md
+++ b/docs/csv-member-import-v1.md
@@ -2,7 +2,8 @@
**Version:** 1.0
**Date:** 2025-01-XX
-**Status:** Ready for Implementation
+**Last Updated:** 2026-01-13
+**Status:** Templates Created - Import Logic Pending
**Related Documents:**
- [Feature Roadmap](./feature-roadmap.md) - Overall feature planning
diff --git a/docs/database-schema-readme.md b/docs/database-schema-readme.md
index 6457db5..71f1e68 100644
--- a/docs/database-schema-readme.md
+++ b/docs/database-schema-readme.md
@@ -15,10 +15,10 @@ This document provides a comprehensive overview of the Mila Membership Managemen
| Metric | Count |
|--------|-------|
-| **Tables** | 5 |
-| **Domains** | 2 (Accounts, Membership) |
-| **Relationships** | 3 |
-| **Indexes** | 15+ |
+| **Tables** | 9 |
+| **Domains** | 4 (Accounts, Membership, MembershipFees, Authorization) |
+| **Relationships** | 7 |
+| **Indexes** | 20+ |
| **Triggers** | 1 (Full-text search) |
## Tables Overview
@@ -68,16 +68,39 @@ This document provides a comprehensive overview of the Mila Membership Managemen
- Immutable and required flags
- Centralized custom field management
+#### `settings`
+- **Purpose:** Global application settings (singleton resource)
+- **Rows (Estimated):** 1 (singleton pattern)
+- **Key Features:**
+ - Club name configuration
+ - Member field visibility settings
+ - Membership fee default settings
+ - Environment variable support for club name
+
+### Authorization Domain
+
+#### `roles`
+- **Purpose:** Role-based access control (RBAC)
+- **Rows (Estimated):** Low (typically 3-10 roles)
+- **Key Features:**
+ - Links users to permission sets
+ - System role protection
+ - Four hardcoded permission sets: own_data, read_only, normal_user, admin
+
## Key Relationships
```
User (0..1) ←→ (0..1) Member
- ↓
- Tokens (N)
+ ↓ ↓
+ Tokens (N) CustomFieldValues (N)
+ ↓ ↓
+ Role (N:1) CustomField (1)
-Member (1) → (N) Properties
+Member (1) → (N) MembershipFeeCycles
↓
- CustomField (1)
+ MembershipFeeType (1)
+
+Settings (1) → MembershipFeeType (0..1)
```
### Relationship Details
@@ -89,16 +112,39 @@ Member (1) → (N) Properties
- Email synchronization when linked (User.email is source of truth)
- `ON DELETE SET NULL` on user side (User preserved when Member deleted)
-2. **Member → Properties (1:N)**
+2. **User → Role (N:1)**
+ - Many users can be assigned to one role
+ - `ON DELETE RESTRICT` - cannot delete role if users are assigned
+ - Role links user to permission set for authorization
+
+3. **Member → CustomFieldValues (1:N)**
- One member, many custom_field_values
- `ON DELETE CASCADE` - custom_field_values deleted with member
- Composite unique constraint (member_id, custom_field_id)
-3. **CustomFieldValue → CustomField (N:1)**
- - Properties reference type definition
+4. **CustomFieldValue → CustomField (N:1)**
+ - Custom field values reference type definition
- `ON DELETE RESTRICT` - cannot delete type if in use
- Type defines data structure
+5. **Member → MembershipFeeType (N:1, optional)**
+ - Many members can be assigned to one fee type
+ - `ON DELETE RESTRICT` - cannot delete fee type if members are assigned
+ - Optional relationship (member can have no fee type)
+
+6. **Member → MembershipFeeCycles (1:N)**
+ - One member, many billing cycles
+ - `ON DELETE CASCADE` - cycles deleted when member deleted
+ - Unique constraint (member_id, cycle_start)
+
+7. **MembershipFeeCycle → MembershipFeeType (N:1)**
+ - Many cycles reference one fee type
+ - `ON DELETE RESTRICT` - cannot delete fee type if cycles exist
+
+8. **Settings → MembershipFeeType (N:1, optional)**
+ - Settings can reference a default fee type
+ - `ON DELETE SET NULL` - if fee type is deleted, setting is cleared
+
## Important Business Rules
### Email Synchronization
@@ -464,7 +510,7 @@ mix run priv/repo/seeds.exs
---
-**Last Updated:** 2025-11-13
-**Schema Version:** 1.1
+**Last Updated:** 2026-01-13
+**Schema Version:** 1.4
**Database:** PostgreSQL 17.6 (dev) / 16 (prod)
diff --git a/docs/database_schema.dbml b/docs/database_schema.dbml
index f97463e..9b546e3 100644
--- a/docs/database_schema.dbml
+++ b/docs/database_schema.dbml
@@ -6,8 +6,8 @@
// - https://dbdocs.io
// - VS Code Extensions: "DBML Language" or "dbdiagram.io"
//
-// Version: 1.3
-// Last Updated: 2025-12-11
+// Version: 1.4
+// Last Updated: 2026-01-13
Project mila_membership_management {
database_type: 'PostgreSQL'
@@ -28,6 +28,7 @@ Project mila_membership_management {
- **Accounts**: User authentication and session management
- **Membership**: Club member data and custom fields
- **MembershipFees**: Membership fee types and billing cycles
+ - **Authorization**: Role-based access control (RBAC)
## Required PostgreSQL Extensions:
- uuid-ossp (UUID generation)
@@ -500,3 +501,138 @@ TableGroup membership_fees_domain {
'''
}
+// ============================================
+// AUTHORIZATION DOMAIN
+// ============================================
+
+Table roles {
+ id uuid [pk, not null, default: `uuid_generate_v7()`, note: 'UUIDv7 primary key']
+ name text [not null, unique, note: 'Unique role name (e.g., "Vorstand", "Admin", "Mitglied")']
+ description text [null, note: 'Human-readable description of the role']
+ permission_set_name text [not null, note: 'Permission set name: "own_data", "read_only", "normal_user", or "admin"']
+ is_system_role boolean [not null, default: false, note: 'If true, role cannot be deleted (protects critical roles)']
+ inserted_at timestamp [not null, default: `now() AT TIME ZONE 'utc'`, note: 'Creation timestamp (UTC)']
+ updated_at timestamp [not null, default: `now() AT TIME ZONE 'utc'`, note: 'Last update timestamp (UTC)']
+
+ indexes {
+ name [unique, name: 'roles_unique_name_index']
+ }
+
+ Note: '''
+ **Role-Based Access Control (RBAC)**
+
+ Roles link users to permission sets. Each role references one of four hardcoded
+ permission sets defined in the application code.
+
+ **Permission Sets:**
+ - `own_data`: Users can only access their own linked member data
+ - `read_only`: Users can read all data but cannot modify
+ - `normal_user`: Users can read and modify most data (standard permissions)
+ - `admin`: Full access to all features and settings
+
+ **System Roles:**
+ - System roles (is_system_role = true) cannot be deleted
+ - Protects critical roles like "Mitglied" (member) from accidental deletion
+ - Only set via seed scripts or internal actions
+
+ **Relationships:**
+ - 1:N with users - users assigned to this role
+ - ON DELETE RESTRICT: Cannot delete role if users are assigned
+
+ **Constraints:**
+ - `name` must be unique
+ - `permission_set_name` must be a valid permission set (validated in application)
+ - System roles cannot be deleted (enforced via validation)
+ '''
+}
+
+// ============================================
+// MEMBERSHIP DOMAIN (Additional Tables)
+// ============================================
+
+Table settings {
+ id uuid [pk, not null, default: `gen_random_uuid()`, note: 'Primary identifier']
+ club_name text [not null, note: 'The name of the association/club (min length: 1)']
+ member_field_visibility jsonb [null, note: 'Visibility configuration for member fields in overview (JSONB map)']
+ include_joining_cycle boolean [not null, default: true, note: 'Whether to include the joining cycle in membership fee generation']
+ default_membership_fee_type_id uuid [null, note: 'FK to membership_fee_types - default fee type for new members']
+ inserted_at timestamp [not null, default: `now() AT TIME ZONE 'utc'`, note: 'Creation timestamp (UTC)']
+ updated_at timestamp [not null, default: `now() AT TIME ZONE 'utc'`, note: 'Last update timestamp (UTC)']
+
+ indexes {
+ default_membership_fee_type_id [name: 'settings_default_membership_fee_type_id_index', note: 'B-tree index for fee type lookups']
+ }
+
+ Note: '''
+ **Global Application Settings (Singleton Resource)**
+
+ Stores global configuration for the association/club. There should only ever
+ be one settings record in the database (singleton pattern).
+
+ **Attributes:**
+ - `club_name`: The name of the association/club (required, can be set via ASSOCIATION_NAME env var)
+ - `member_field_visibility`: JSONB map storing visibility configuration for member fields
+ (e.g., `{"street": false, "house_number": false}`). Fields not in the map default to `true`.
+ - `include_joining_cycle`: When true, members pay from their joining cycle. When false,
+ they pay from the next full cycle after joining.
+ - `default_membership_fee_type_id`: The membership fee type automatically assigned to
+ new members. Can be nil if no default is set.
+
+ **Singleton Pattern:**
+ - Only one settings record should exist
+ - Designed to be read and updated, not created/destroyed via normal CRUD
+ - Initial settings should be seeded
+
+ **Environment Variable Support:**
+ - `club_name` can be set via `ASSOCIATION_NAME` environment variable
+ - Database values always take precedence over environment variables
+
+ **Relationships:**
+ - Optional N:1 with membership_fee_types - default fee type for new members
+ - ON DELETE SET NULL: If default fee type is deleted, setting is cleared
+ '''
+}
+
+// ============================================
+// RELATIONSHIPS (Additional)
+// ============================================
+
+// User → Role (N:1)
+// - Many users can be assigned to one role
+// - ON DELETE RESTRICT: Cannot delete role if users are assigned
+Ref: users.role_id > roles.id [delete: restrict]
+
+// Settings → MembershipFeeType (N:1, optional)
+// - Settings can reference a default membership fee type
+// - ON DELETE SET NULL: If fee type is deleted, setting is cleared
+Ref: settings.default_membership_fee_type_id > membership_fee_types.id [delete: set null]
+
+// ============================================
+// TABLE GROUPS (Updated)
+// ============================================
+
+TableGroup authorization_domain {
+ roles
+
+ Note: '''
+ **Authorization Domain**
+
+ Handles role-based access control (RBAC) with hardcoded permission sets.
+ Roles link users to permission sets for authorization.
+ '''
+}
+
+TableGroup membership_domain {
+ members
+ custom_field_values
+ custom_fields
+ settings
+
+ Note: '''
+ **Membership Domain**
+
+ Core business logic for club membership management.
+ Supports flexible, extensible member data model.
+ Includes global application settings (singleton).
+ '''
+}
diff --git a/docs/development-progress-log.md b/docs/development-progress-log.md
index 629987e..5e5c43b 100644
--- a/docs/development-progress-log.md
+++ b/docs/development-progress-log.md
@@ -1570,15 +1570,19 @@ This project demonstrates a modern Phoenix application built with:
- ✅ **Flexible data model** (EAV pattern with union types)
**Key Achievements:**
-- 🎯 8 sprints completed
-- 🚀 82 pull requests merged
-- ✅ Core features implemented (CRUD, search, auth, sync)
+- 🎯 9+ sprints completed
+- 🚀 100+ pull requests merged
+- ✅ Core features implemented (CRUD, search, auth, sync, membership fees, roles & permissions)
+- ✅ Membership fees system (types, cycles, settings)
+- ✅ Role-based access control (RBAC) with 4 permission sets
+- ✅ Member field visibility settings
+- ✅ Sidebar navigation (WCAG 2.1 AA compliant)
- 📚 Comprehensive documentation
- 🔒 Security-focused (audits, validations, policies)
- 🐳 Docker-ready for self-hosting
**Next Steps:**
-- Implement roles & permissions
+- ✅ ~~Implement roles & permissions~~ - RBAC system implemented (2026-01-08)
- Add payment tracking
- ✅ ~~Improve accessibility (WCAG 2.1 AA)~~ - Keyboard navigation implemented
- Member self-service portal
@@ -1586,8 +1590,150 @@ This project demonstrates a modern Phoenix application built with:
---
-**Document Version:** 1.3
-**Last Updated:** 2025-12-02
+## Recent Updates (2025-12-02 to 2026-01-13)
+
+### Membership Fees System Implementation (2025-12-11 to 2025-12-26)
+
+**PR #283:** *Membership Fee - Database Schema & Ash Domain Foundation* (closes #275)
+- Created `Mv.MembershipFees` domain
+- Added `MembershipFeeType` resource with intervals (monthly, quarterly, half_yearly, yearly)
+- Added `MembershipFeeCycle` resource for individual billing cycles
+- Database migrations for membership fee tables
+
+**PR #284:** *Calendar Cycle Calculation Logic* (closes #276)
+- Calendar-based cycle calculation module
+- Support for different intervals
+- Cycle start/end date calculations
+- Integration with member joining dates
+
+**PR #290:** *Cycle Generation System* (closes #277)
+- Automatic cycle generation for members
+- Cycle regeneration when fee type changes
+- Integration with member lifecycle hooks
+- Actor-based authorization for cycle operations
+
+**PR #291:** *Membership Fee Type Resource & Settings* (closes #278)
+- Membership fee type CRUD operations
+- Global membership fee settings
+- Default fee type assignment
+- `include_joining_cycle` setting
+
+**PR #294:** *Cycle Management & Member Integration* (closes #279)
+- Member-fee type relationship
+- Cycle status tracking (unpaid, paid, suspended)
+- Member detail view integration
+- Cycle regeneration on fee type change
+
+**PR #304:** *Membership Fee 6 - UI Components & LiveViews* (closes #280)
+- Membership fee type management LiveViews
+- Membership fee settings LiveView
+- Cycle display in member detail view
+- Payment status indicators
+
+### Custom Fields Enhancements (2025-12-11 to 2026-01-02)
+
+**PR #266:** *Implements search for custom fields* (closes #196)
+- Custom field search in member overview
+- Integration with full-text search
+- Custom field value filtering
+
+**PR #301:** *Implements validation for required custom fields* (closes #274)
+- Required custom field validation
+- Form-level validation
+- Error messages for missing required fields
+
+**PR #313:** *Fix hidden empty custom fields* (closes #282)
+- Fixed display of empty custom fields
+- Improved custom field visibility logic
+
+### UI/UX Improvements (2025-12-03 to 2025-12-16)
+
+**PR #240:** *Implement dropdown to show/hide columns in member overview* (closes #209)
+- Field visibility dropdown
+- User-specific field selection
+- Integration with global settings
+
+**PR #247:** *Visual hierarchy for fields in member view and edit form* (closes #231)
+- Improved field grouping
+- Visual hierarchy improvements
+- Better form layout
+
+**PR #250:** *UX - Avoid opening member by clicking the checkbox* (closes #233)
+- Checkbox click handling
+- Prevented accidental navigation
+- Improved selection UX
+
+**PR #259:** *Fix small UI issues* (closes #220)
+- Various UI bug fixes
+- Accessibility improvements
+
+**PR #293:** *Small UX fixes* (closes #281)
+- Additional UX improvements
+- Polish and refinement
+
+**PR #319:** *Reduce member fields* (closes #273)
+- Removed unnecessary member fields
+- Streamlined member data model
+- Migration for field removal
+
+### Roles and Permissions System (2026-01-06 to 2026-01-08)
+- ✅ **RBAC Implementation Complete** - Member Resource Policies (#345)
+ - Four hardcoded permission sets: `own_data`, `read_only`, `normal_user`, `admin`
+ - Role-based access control with database-backed roles
+ - Member resource policies with scope filtering (`:own`, `:linked`, `:all`)
+ - Authorization checks via `Mv.Authorization.Checks.HasPermission`
+ - System role protection (cannot delete critical roles)
+ - Comprehensive test coverage
+
+### Actor Handling Refactoring (2026-01-09)
+- ✅ **Consistent Actor Access** - `current_actor/1` helper function
+ - Standardized actor access across all LiveViews
+ - `ash_actor_opts/1` helper for consistent authorization options
+ - `submit_form/3` wrapper for form submissions with actor
+ - All Ash operations now properly pass `actor` parameter
+ - Error handling improvements (replaced bang calls with proper error handling)
+
+### Internationalization Improvements (2026-01-13)
+- ✅ **Complete German Translations** - All UI strings translated
+ - CI check for empty German translations in lint task
+ - Standardized English `msgstr` entries (all empty for consistency)
+ - Corrected language headers in `.po` files
+ - Added missing translations for error messages
+
+### Code Quality Improvements (2026-01-13)
+- ✅ **Error Handling** - Replaced `Ash.read!` with proper error handling
+- ✅ **Code Complexity** - Reduced nesting depth in `UserLive.Form`
+- ✅ **Test Infrastructure** - Role tag support in `ConnCase`
+
+### CSV Import Feature (2026-01-13)
+- ✅ **CSV Templates** - Member import templates (#329)
+ - German and English CSV templates
+ - Template files in `priv/static/templates/`
+
+### Sidebar Implementation (2026-01-12)
+- ✅ **Sidebar Navigation** - Replaced navbar with sidebar (#260)
+ - Standard-compliant sidebar with comprehensive tests
+ - DaisyUI drawer pattern implementation
+ - Desktop expanded/collapsed states
+ - Mobile overlay drawer
+ - localStorage persistence for sidebar state
+ - WCAG 2.1 Level AA compliant
+
+### Member Field Settings (2026-01-12, PR #300, closes #223)
+- ✅ **Member Field Visibility Configuration** - Global settings for field visibility
+ - JSONB-based visibility configuration in Settings resource
+ - Per-field visibility toggle (show/hide in member overview)
+ - Atomic updates for single field visibility changes
+ - Integration with member list overview
+ - User-specific field selection (takes priority over global settings)
+ - Custom field visibility support
+ - Default visibility: all fields visible except `exit_date` (hidden by default)
+ - LiveComponent for managing member field visibility in settings page
+
+---
+
+**Document Version:** 1.4
+**Last Updated:** 2026-01-13
**Maintainer:** Development Team
**Status:** Living Document (update as project evolves)
diff --git a/docs/documentation-sync-todos.md b/docs/documentation-sync-todos.md
new file mode 100644
index 0000000..65c8b08
--- /dev/null
+++ b/docs/documentation-sync-todos.md
@@ -0,0 +1,128 @@
+# Documentation Sync - Code Anpassungen Todo-Liste
+
+**Erstellt:** 2026-01-13
+**Zweck:** Liste aller Code-Anpassungen, die basierend auf der Dokumentations-Synchronisation identifiziert wurden
+
+---
+
+## Entfernte Dokumentationsdateien
+
+### 1. `docs/test-status-membership-fee-ui.md`
+**Grund:** Veraltete temporäre Analyse-Dokumentation
+- Enthält nur historische Test-Status-Informationen (Datum: 2025-01-XX)
+- Status "Tests Written - Implementation Complete" ist nicht mehr relevant
+- Alle Tests sind bereits implementiert und laufen
+- Informationen sind bereits in `development-progress-log.md` dokumentiert
+- **Entfernt:** 2026-01-13
+
+### 2. `docs/test-failures-analysis.md`
+**Grund:** Veraltete temporäre Analyse-Dokumentation
+- Analysiert 5 fehlschlagende Tests, die bereits behoben wurden
+- Enthält Lösungsvorschläge für bereits gelöste Probleme
+- Informationen sind nur historisch relevant
+- Keine aktuelle Relevanz für die Codebasis
+- **Entfernt:** 2026-01-13
+
+## Als veraltet markierte Dokumentationsdateien
+
+### 3. `docs/sidebar-analysis-current-state.md`
+**Grund:** Veraltete Analyse-Dokumentation
+- Beschreibt den Zustand VOR der Sidebar-Implementierung
+- Sidebar wurde bereits implementiert (2026-01-12, PR #260)
+- Wurde durch `sidebar-requirements-v2.md` ersetzt
+- **Status:** Als veraltet markiert, aber behalten für historische Referenz
+
+### 4. `docs/umsetzung-sidebar.md`
+**Grund:** Veraltete Implementierungs-Anleitung
+- Schritt-für-Schritt-Anleitung für Sidebar-Implementierung
+- Sidebar wurde bereits implementiert (2026-01-12, PR #260)
+- Wurde durch `sidebar-requirements-v2.md` ersetzt
+- **Status:** Als veraltet markiert, aber behalten für historische Referenz
+
+---
+
+## Code-Anpassungen (Priorität: Low)
+
+### Keine kritischen Code-Anpassungen erforderlich
+
+Die Dokumentations-Synchronisation hat ergeben, dass der Code aktuell ist und mit der aktualisierten Dokumentation übereinstimmt. Alle identifizierten Unstimmigkeiten waren in der Dokumentation, nicht im Code.
+
+---
+
+## Veraltete Code-Patterns
+
+### Keine veralteten Patterns identifiziert
+
+Alle Code-Patterns entsprechen den aktuellen Best Practices und sind in `CODE_GUIDELINES.md` dokumentiert.
+
+---
+
+## Fehlende Implementierungen
+
+### Keine fehlenden Implementierungen identifiziert
+
+Alle in der Dokumentation beschriebenen Features sind implementiert.
+
+---
+
+## Inconsistente Namensgebung
+
+### Keine Inkonsistenzen identifiziert
+
+Die Terminologie ist konsistent zwischen Code und Dokumentation:
+- `CustomField` / `CustomFieldValue` (nicht mehr "Property" / "PropertyType")
+- `MembershipFeeType` / `MembershipFeeCycle` (korrekt verwendet)
+- Domains: `Accounts`, `Membership`, `MembershipFees`, `Authorization` (alle korrekt)
+
+---
+
+## Zusammenfassung
+
+**Status:** ✅ Dokumentation erfolgreich synchronisiert
+
+- **Aktualisierte Dokumentation:** 15+ Dateien
+ - database_schema.dbml (Version 1.4, +2 Tabellen: roles, settings)
+ - database-schema-readme.md (9 Tabellen, 4 Domains, aktualisierte Relationships)
+ - development-progress-log.md (Last Updated: 2026-01-13)
+ - Neue Sektion: "Recent Updates (2025-12-02 to 2026-01-13)"
+ - Membership Fees System Implementation (6 PRs dokumentiert)
+ - Custom Fields Enhancements (3 PRs dokumentiert)
+ - UI/UX Improvements (6 PRs dokumentiert)
+ - Roles and Permissions System (vollständig dokumentiert)
+ - Key Achievements aktualisiert (100+ PRs, 9+ sprints)
+ - feature-roadmap.md (Last Updated: 2026-01-13)
+ - Routes aktualisiert (alle aktuellen LiveView-Routes dokumentiert)
+ - Membership Fees Endpoints (Status: ✅ Implemented)
+ - Admin Panel Endpoints (Status aktualisiert)
+ - Custom Fields Endpoints (korrigiert: über /settings verwaltet)
+ - CHANGELOG.md (neue Features dokumentiert)
+ - CODE_GUIDELINES.md (Module-Struktur, Actor-Handling-Patterns, navbar → sidebar)
+ - roles-and-permissions-architecture.md (Status: ✅ Implemented)
+ - roles-and-permissions-overview.md (Status: ✅ Implemented)
+ - roles-and-permissions-implementation-plan.md (Status: ✅ Implemented)
+ - membership-fee-architecture.md (Status: ✅ Implemented)
+ - membership-fee-overview.md (Status: ✅ Implemented)
+ - csv-member-import-v1.md (Status: Templates Created)
+ - sidebar-requirements-v2.md (Status: ✅ Implemented)
+ - README.md (Feature-Status aktualisiert)
+- **Entfernte Dokumentation:** 2 Dateien
+ - test-status-membership-fee-ui.md
+ - test-failures-analysis.md
+- **Als veraltet markiert:** 2 Dateien
+ - sidebar-analysis-current-state.md
+ - umsetzung-sidebar.md
+- **Code-Anpassungen erforderlich:** 0
+- **Kritische Probleme:** 0
+
+**Dokumentierte Features seit 2025-12-02:**
+- Membership Fees System (6 PRs: #275, #276, #277, #278, #279, #280)
+- Custom Fields Enhancements (3 PRs: #196, #274, #282)
+- UI/UX Improvements (6 PRs: #209, #220, #231, #233, #273, #281)
+- Roles and Permissions (5 PRs: #321, #322, #323, #325, #345)
+- Sidebar Implementation (#260)
+- Member Field Settings (#223, #300)
+- CSV Import Templates (#329)
+- Actor Handling Refactoring
+- Internationalization Improvements
+
+Die Dokumentation ist jetzt vollständig mit dem aktuellen Code synchronisiert. Alle "Last Updated" Daten wurden auf 2026-01-13 aktualisiert, wo relevant. Alle Routes, Features und Implementierungen sind dokumentiert.
diff --git a/docs/feature-roadmap.md b/docs/feature-roadmap.md
index c4ecfc9..1df3eb6 100644
--- a/docs/feature-roadmap.md
+++ b/docs/feature-roadmap.md
@@ -1,8 +1,8 @@
# Feature Roadmap & Implementation Plan
**Project:** Mila - Membership Management System
-**Last Updated:** 2025-11-10
-**Status:** Planning Phase
+**Last Updated:** 2026-01-13
+**Status:** Active Development
---
@@ -37,17 +37,24 @@
- [#146](https://git.local-it.org/local-it/mitgliederverwaltung/issues/146) - Translate "or" in the login screen (Low)
- [#144](https://git.local-it.org/local-it/mitgliederverwaltung/issues/144) - Add language switch dropdown to login screen (Low)
+**Current State:**
+- ✅ **Role-based access control (RBAC)** - Implemented (2026-01-08, PR #346, closes #345)
+- ✅ **Permission system** - Four hardcoded permission sets (`own_data`, `read_only`, `normal_user`, `admin`)
+- ✅ **Database-backed roles** - Roles table with permission set references
+- ✅ **Resource policies** - Member resource policies with scope filtering
+- ✅ **Page-level authorization** - LiveView page access control
+- ✅ **System role protection** - Critical roles cannot be deleted
+
**Missing Features:**
-- ❌ Role-based access control (RBAC)
-- ❌ Permission system
- ❌ Password reset flow
- ❌ Email verification
- ❌ Two-factor authentication (future)
**Related Issues:**
-- [#191](https://git.local-it.org/local-it/mitgliederverwaltung/issues/191) - Implement Roles in Ash (M)
-- [#190](https://git.local-it.org/local-it/mitgliederverwaltung/issues/190) - Implement Permissions in Ash (M)
-- [#151](https://git.local-it.org/local-it/mitgliederverwaltung/issues/151) - Define implementation plan for roles and permissions (M) [3/7 tasks done]
+- ✅ [#345](https://git.local-it.org/local-it/mitgliederverwaltung/issues/345) - Member Resource Policies (closed 2026-01-13)
+- ✅ [#191](https://git.local-it.org/local-it/mitgliederverwaltung/issues/191) - Implement Roles in Ash (M) - Completed
+- ✅ [#190](https://git.local-it.org/local-it/mitgliederverwaltung/issues/190) - Implement Permissions in Ash (M) - Completed
+- ✅ [#151](https://git.local-it.org/local-it/mitgliederverwaltung/issues/151) - Define implementation plan for roles and permissions (M) - Completed
---
@@ -187,23 +194,27 @@
**Current State:**
- ✅ Basic "paid" boolean field on members
-- ✅ **UI Mock-ups for Membership Fee Types & Settings** (2025-12-02)
-- ⚠️ No payment tracking
+- ✅ **Membership Fee Types Management** - Full CRUD implementation
+- ✅ **Membership Fee Cycles** - Individual billing cycles per member
+- ✅ **Membership Fee Settings** - Global settings (include_joining_cycle, default_fee_type)
+- ✅ **Cycle Generation** - Automatic cycle generation for members
+- ✅ **Payment Status Tracking** - Status per cycle (unpaid, paid, suspended)
+- ✅ **Member Fee Assignment** - Members can be assigned to fee types
+- ✅ **Cycle Regeneration** - Regenerate cycles when fee type changes
+- ✅ **UI Components** - Membership fee status in member list and detail views
**Open Issues:**
- [#156](https://git.local-it.org/local-it/mitgliederverwaltung/issues/156) - Set up & document testing environment for vereinfacht.digital (L, Low priority)
-- [#226](https://git.local-it.org/local-it/mitgliederverwaltung/issues/226) - Payment/Membership Fee Mockup Pages (Preview)
+- ✅ [#226](https://git.local-it.org/local-it/mitgliederverwaltung/issues/226) - Payment/Membership Fee Mockup Pages (Preview) - Implemented
-**Mock-Up Pages (Non-Functional Preview):**
-- `/membership_fee_types` - Membership Fee Types Management
-- `/membership_fee_settings` - Global Membership Fee Settings
+**Implemented Pages:**
+- `/membership_fee_types` - Membership Fee Types Management (fully functional)
+- `/membership_fee_settings` - Global Membership Fee Settings (fully functional)
+- `/members/:id` - Member detail view with membership fee cycles
**Missing Features:**
-- ❌ Membership fee configuration
-- ❌ Payment records/transactions
-- ❌ Payment history per member
+- ❌ Payment records/transactions (external payment tracking)
- ❌ Payment reminders
-- ❌ Payment status tracking (pending, paid, overdue)
- ❌ Invoice generation
- ❌ vereinfacht.digital API integration
- ❌ SEPA direct debit support
@@ -218,17 +229,18 @@
**Current State:**
- ✅ AshAdmin integration (basic)
-- ⚠️ No user-facing admin UI
+- ✅ **Global Settings Management** - `/settings` page (singleton resource)
+- ✅ **Club/Organization profile** - Club name configuration
+- ✅ **Member Field Visibility Settings** - Configure which fields show in overview
+- ✅ **CustomFieldValue type management UI** - Full CRUD for custom fields
+- ✅ **Role Management UI** - Full CRUD for roles (`/admin/roles`)
+- ✅ **Membership Fee Settings** - Global fee settings management
**Open Issues:**
- [#186](https://git.local-it.org/local-it/mitgliederverwaltung/issues/186) - Create Architecture docs in Repo (S, Low priority)
**Missing Features:**
-- ❌ Global settings management
-- ❌ Club/Organization profile
- ❌ Email templates configuration
-- ❌ CustomFieldValue type management UI (user-facing)
-- ❌ Role and permission management UI
- ❌ System health dashboard
- ❌ Audit log viewer
- ❌ Backup/restore functionality
@@ -273,10 +285,12 @@
**Current State:**
- ✅ Seed data script
-- ⚠️ No user-facing import/export
+- ✅ **CSV Import Templates** - German and English templates (#329, 2026-01-13)
+ - Template files in `priv/static/templates/member_import_de.csv` and `member_import_en.csv`
+ - CSV specification documented in `docs/csv-member-import-v1.md`
**Missing Features:**
-- ❌ CSV import for members
+- ❌ CSV import implementation (templates ready, import logic pending)
- ❌ Excel import for members
- ❌ Import validation and preview
- ❌ Import error handling
@@ -452,6 +466,7 @@ Since this is a **Phoenix LiveView** application with **Ash Framework**, we have
| `GET` | `/auth/user/rauthy` | Initiate OIDC flow | 🔓 | - | Redirect to Rauthy |
| `GET` | `/auth/user/rauthy/callback` | Handle OIDC callback | 🔓 | `{code, state}` | Redirect + session cookie |
| `POST` | `/auth/user/sign_out` | Sign out user | 🔐 | - | Redirect to login |
+| `GET` | `/auth/link-oidc-account` | OIDC account linking (password verification) | 🔓 | - | LiveView form | ✅ Implemented |
| `GET` | `/auth/user/password/reset` | Show password reset form | 🔓 | - | HTML form |
| `POST` | `/auth/user/password/reset` | Request password reset | 🔓 | `{email}` | Success message + email sent |
| `GET` | `/auth/user/password/reset/:token` | Show reset password form | 🔓 | - | HTML form |
@@ -537,13 +552,18 @@ Since this is a **Phoenix LiveView** application with **Ash Framework**, we have
### 3. Custom Fields (CustomFieldValue System) Endpoints
-#### LiveView Endpoints
+#### LiveView Endpoints (✅ Implemented)
-| Mount | Purpose | Auth | Events |
-|-------|---------|------|--------|
-| `/custom-fields` | List custom fields | 🛡️ | `new`, `edit`, `delete` |
-| `/custom-fields/new` | Create custom field | 🛡️ | `save`, `cancel` |
-| `/custom-fields/:id/edit` | Edit custom field | 🛡️ | `save`, `cancel`, `delete` |
+| Mount | Purpose | Auth | Events | Status |
+|-------|---------|------|--------|--------|
+| `/settings` | Global settings (includes custom fields management) | 🔐 | `save`, `validate` | ✅ Implemented |
+| `/custom_field_values` | List all custom field values | 🔐 | `new`, `edit`, `delete` | ✅ Implemented |
+| `/custom_field_values/new` | Create custom field value | 🔐 | `save`, `cancel` | ✅ Implemented |
+| `/custom_field_values/:id` | Custom field value detail | 🔐 | `edit` | ✅ Implemented |
+| `/custom_field_values/:id/edit` | Edit custom field value | 🔐 | `save`, `cancel` | ✅ Implemented |
+| `/custom_field_values/:id/show/edit` | Edit from show page | 🔐 | `save`, `cancel` | ✅ Implemented |
+
+**Note:** Custom fields (definitions) are managed via LiveComponent in `/settings` page, not as separate routes.
#### Ash Resource Actions
@@ -622,63 +642,81 @@ Since this is a **Phoenix LiveView** application with **Ash Framework**, we have
### 6. Internationalization Endpoints
-#### HTTP Controller Endpoints
+#### HTTP Controller Endpoints (✅ Implemented)
-| Method | Route | Purpose | Auth | Request | Response |
-|--------|-------|---------|------|---------|----------|
-| `POST` | `/locale` | Set user locale | 🔐 | `{locale: "de"}` | Redirect with cookie |
-| `GET` | `/locales` | List available locales | 🔓 | - | `["de", "en"]` |
+| Method | Route | Purpose | Auth | Request | Response | Status |
+|--------|-------|---------|------|---------|----------|--------|
+| `POST` | `/set_locale` | Set user locale | 🔐 | `{locale: "de"}` | Redirect with cookie | ✅ Implemented |
+| `GET` | `/locales` | List available locales | 🔓 | - | `["de", "en"]` | ❌ Not implemented |
+
+**Note:** Locale is set via `/set_locale` POST endpoint and persisted in session/cookie. Supported locales: `de` (default), `en`.
---
### 7. Payment & Fees Management Endpoints
-#### LiveView Endpoints (NEW - Issue #156)
+#### LiveView Endpoints (✅ Implemented)
-| Mount | Purpose | Auth | Events |
-|-------|---------|------|--------|
-| `/payments` | Payment list | 🔐 | `new`, `record_payment`, `send_reminder` |
-| `/payments/:id` | Payment detail | 🔐 | `edit`, `delete`, `mark_paid` |
-| `/fees` | Fee configuration | 🛡️ | `create`, `edit`, `delete` |
-| `/invoices` | Invoice list | 🔐 | `generate`, `download`, `send` |
+| Mount | Purpose | Auth | Events | Status |
+|-------|---------|------|--------|--------|
+| `/membership_fee_types` | Membership fee type list | 🔐 | `new`, `edit`, `delete` | ✅ Implemented |
+| `/membership_fee_types/new` | Create membership fee type | 🔐 | `save`, `cancel` | ✅ Implemented |
+| `/membership_fee_types/:id/edit` | Edit membership fee type | 🔐 | `save`, `cancel` | ✅ Implemented |
+| `/membership_fee_settings` | Global membership fee settings | 🔐 | `save` | ✅ Implemented |
+| `/contributions/member/:id` | Member contribution periods (mock-up) | 🔐 | - | ⚠️ Mock-up only |
+| `/contribution_types` | Contribution types (mock-up) | 🔐 | - | ⚠️ Mock-up only |
-#### Ash Resource Actions (NEW)
+#### Ash Resource Actions (✅ Partially Implemented)
-| Resource | Action | Purpose | Auth | Input | Output |
-|----------|--------|---------|------|-------|--------|
-| `Fee` | `:create` | Create fee type | 🛡️ | `{name, amount, frequency}` | `{:ok, fee}` |
-| `Fee` | `:read` | List fees | 🔐 | - | `[%Fee{}]` |
-| `Payment` | `:create` | Record payment | 🔐 | `{member_id, fee_id, amount, date}` | `{:ok, payment}` |
-| `Payment` | `:list_by_member` | Member payment history | 🔐 | `{member_id}` | `[%Payment{}]` |
-| `Payment` | `:mark_paid` | Mark as paid | 🔐 | `{id}` | `{:ok, payment}` |
-| `Invoice` | `:generate` | Generate invoice | 🔐 | `{member_id, fee_id, period}` | `{:ok, invoice}` |
-| `Invoice` | `:send` | Send invoice via email | 🔐 | `{id}` | `{:ok, sent}` |
-| `Payment` | `:import_vereinfacht` | Import from vereinfacht.digital | 🛡️ | `{transactions}` | `{:ok, count}` |
+| Resource | Action | Purpose | Auth | Input | Output | Status |
+|----------|--------|---------|------|-------|--------|--------|
+| `MembershipFeeType` | `:create` | Create fee type | 🔐 | `{name, amount, interval, ...}` | `{:ok, fee_type}` | ✅ Implemented |
+| `MembershipFeeType` | `:read` | List fee types | 🔐 | - | `[%MembershipFeeType{}]` | ✅ Implemented |
+| `MembershipFeeType` | `:update` | Update fee type (name, amount, description) | 🔐 | `{id, attrs}` | `{:ok, fee_type}` | ✅ Implemented |
+| `MembershipFeeType` | `:destroy` | Delete fee type (if no cycles) | 🔐 | `{id}` | `{:ok, fee_type}` | ✅ Implemented |
+| `MembershipFeeCycle` | `:read` | List cycles for member | 🔐 | `{member_id}` | `[%MembershipFeeCycle{}]` | ✅ Implemented |
+| `MembershipFeeCycle` | `:update` | Update cycle status | 🔐 | `{id, status}` | `{:ok, cycle}` | ✅ Implemented |
+| `Payment` | `:create` | Record payment | 🔐 | `{member_id, fee_id, amount, date}` | `{:ok, payment}` | ❌ Not implemented |
+| `Payment` | `:list_by_member` | Member payment history | 🔐 | `{member_id}` | `[%Payment{}]` | ❌ Not implemented |
+| `Payment` | `:mark_paid` | Mark as paid | 🔐 | `{id}` | `{:ok, payment}` | ❌ Not implemented |
+| `Invoice` | `:generate` | Generate invoice | 🔐 | `{member_id, fee_id, period}` | `{:ok, invoice}` | ❌ Not implemented |
+| `Invoice` | `:send` | Send invoice via email | 🔐 | `{id}` | `{:ok, sent}` | ❌ Not implemented |
+| `Payment` | `:import_vereinfacht` | Import from vereinfacht.digital | 🛡️ | `{transactions}` | `{:ok, count}` | ❌ Not implemented |
---
### 8. Admin Panel & Configuration Endpoints
-#### LiveView Endpoints (NEW)
+#### LiveView Endpoints (✅ Partially Implemented)
-| Mount | Purpose | Auth | Events |
-|-------|---------|------|--------|
-| `/admin` | Admin dashboard | 🛡️ | - |
-| `/admin/settings` | Global settings | 🛡️ | `save` |
-| `/admin/organization` | Organization profile | 🛡️ | `save` |
-| `/admin/email-templates` | Email template editor | 🛡️ | `create`, `edit`, `preview` |
-| `/admin/audit-log` | System audit log | 🛡️ | `filter`, `export` |
+| Mount | Purpose | Auth | Events | Status |
+|-------|---------|------|--------|--------|
+| `/settings` | Global settings (club name, member fields, custom fields) | 🔐 | `save`, `validate` | ✅ Implemented |
+| `/admin/roles` | Role management | 🛡️ | `new`, `edit`, `delete` | ✅ Implemented |
+| `/admin/roles/new` | Create role | 🛡️ | `save`, `cancel` | ✅ Implemented |
+| `/admin/roles/:id` | Role detail view | 🛡️ | `edit` | ✅ Implemented |
+| `/admin/roles/:id/edit` | Edit role | 🛡️ | `save`, `cancel` | ✅ Implemented |
+| `/admin` | Admin dashboard | 🛡️ | - | ❌ Not implemented |
+| `/admin/organization` | Organization profile | 🛡️ | `save` | ❌ Not implemented |
+| `/admin/email-templates` | Email template editor | 🛡️ | `create`, `edit`, `preview` | ❌ Not implemented |
+| `/admin/audit-log` | System audit log | 🛡️ | `filter`, `export` | ❌ Not implemented |
-#### Ash Resource Actions (NEW)
+#### Ash Resource Actions (✅ Partially Implemented)
-| Resource | Action | Purpose | Auth | Input | Output |
-|----------|--------|---------|------|-------|--------|
-| `Setting` | `:get` | Get setting value | 🔐 | `{key}` | `value` |
-| `Setting` | `:set` | Set setting value | 🛡️ | `{key, value}` | `{:ok, setting}` |
-| `Setting` | `:list` | List all settings | 🛡️ | - | `[%Setting{}]` |
-| `Organization` | `:read` | Get organization info | 🔐 | - | `%Organization{}` |
-| `Organization` | `:update` | Update organization | 🛡️ | `{name, logo, ...}` | `{:ok, org}` |
-| `AuditLog` | `:list` | List audit entries | 🛡️ | `{filters, pagination}` | `[%AuditLog{}]` |
+| Resource | Action | Purpose | Auth | Input | Output | Status |
+|----------|--------|---------|------|-------|--------|--------|
+| `Setting` | `:read` | Get settings (singleton) | 🔐 | - | `{:ok, settings}` | ✅ Implemented |
+| `Setting` | `:update` | Update settings | 🔐 | `{club_name, member_field_visibility, ...}` | `{:ok, settings}` | ✅ Implemented |
+| `Setting` | `:update_member_field_visibility` | Update field visibility | 🔐 | `{member_field_visibility}` | `{:ok, settings}` | ✅ Implemented |
+| `Setting` | `:update_single_member_field_visibility` | Atomic field visibility update | 🔐 | `{field, show_in_overview}` | `{:ok, settings}` | ✅ Implemented |
+| `Setting` | `:update_membership_fee_settings` | Update fee settings | 🔐 | `{include_joining_cycle, default_membership_fee_type_id}` | `{:ok, settings}` | ✅ Implemented |
+| `Role` | `:read` | List roles | 🛡️ | - | `[%Role{}]` | ✅ Implemented |
+| `Role` | `:create` | Create role | 🛡️ | `{name, permission_set_name, ...}` | `{:ok, role}` | ✅ Implemented |
+| `Role` | `:update` | Update role | 🛡️ | `{id, attrs}` | `{:ok, role}` | ✅ Implemented |
+| `Role` | `:destroy` | Delete role (if not system role) | 🛡️ | `{id}` | `{:ok, role}` | ✅ Implemented |
+| `Organization` | `:read` | Get organization info | 🔐 | - | `%Organization{}` | ❌ Not implemented |
+| `Organization` | `:update` | Update organization | 🛡️ | `{name, logo, ...}` | `{:ok, org}` | ❌ Not implemented |
+| `AuditLog` | `:list` | List audit entries | 🛡️ | `{filters, pagination}` | `[%AuditLog{}]` | ❌ Not implemented |
---
diff --git a/docs/membership-fee-architecture.md b/docs/membership-fee-architecture.md
index 7c8da24..fbb2f08 100644
--- a/docs/membership-fee-architecture.md
+++ b/docs/membership-fee-architecture.md
@@ -3,8 +3,8 @@
**Project:** Mila - Membership Management System
**Feature:** Membership Fee Management
**Version:** 1.0
-**Last Updated:** 2025-11-27
-**Status:** Architecture Design - Ready for Implementation
+**Last Updated:** 2026-01-13
+**Status:** ✅ Implemented
---
diff --git a/docs/membership-fee-overview.md b/docs/membership-fee-overview.md
index bd47faa..8eb48b0 100644
--- a/docs/membership-fee-overview.md
+++ b/docs/membership-fee-overview.md
@@ -3,8 +3,8 @@
**Project:** Mila - Membership Management System
**Feature:** Membership Fee Management
**Version:** 1.0
-**Last Updated:** 2025-11-27
-**Status:** Concept - Ready for Review
+**Last Updated:** 2026-01-13
+**Status:** ✅ Implemented
---
diff --git a/docs/roles-and-permissions-architecture.md b/docs/roles-and-permissions-architecture.md
index 8c89af7..6c21907 100644
--- a/docs/roles-and-permissions-architecture.md
+++ b/docs/roles-and-permissions-architecture.md
@@ -2,7 +2,8 @@
**Version:** 2.0 (Clean Rewrite)
**Date:** 2025-01-13
-**Status:** Ready for Implementation
+**Last Updated:** 2026-01-13
+**Status:** ✅ Implemented (2026-01-08, PR #346, closes #345)
**Related Documents:**
- [Overview](./roles-and-permissions-overview.md) - High-level concepts for stakeholders
- [Implementation Plan](./roles-and-permissions-implementation-plan.md) - Step-by-step implementation guide
@@ -1555,7 +1556,7 @@ end
**Navbar with conditional links:**
```heex
-
+