docs(project): condense progress log, roadmap and test/infra docs

This commit is contained in:
Moritz 2026-06-15 21:53:36 +02:00
parent 3797bc8fae
commit 6fddb5285b
5 changed files with 164 additions and 3277 deletions

View file

@ -6,16 +6,11 @@
---
## Table of Contents
1. [Phase 1: Feature Area Breakdown](#phase-1-feature-area-breakdown)
2. [Phase 2: API Endpoint Definition](#phase-2-api-endpoint-definition)
3. [Phase 3: Implementation Task Creation](#phase-3-implementation-task-creation)
4. [Phase 4: Task Organization and Prioritization](#phase-4-task-organization-and-prioritization)
This is the living per-area roadmap: shipped state (coarse — see `development-progress-log.md` for detail), open issues, and the missing-features backlog. For the actual, current endpoints see `lib/mv_web/router.ex` and `docs/page-permission-route-coverage.md`.
---
## Phase 1: Feature Area Breakdown
## Feature Area Breakdown
### Feature Areas
@ -49,10 +44,10 @@
- ✅ **Page-level authorization** - LiveView page access control
- ✅ **System role protection** - Critical roles cannot be deleted
**Planned: OIDC-only mode (TDD, tests first):**
- Admin Settings: When OIDC-only is enabled, disable "Allow direct registration" toggle and show hint (tests in `GlobalSettingsLiveTest`).
- Backend: Reject password sign-in and `register_with_password` when OIDC-only (tests in `AuthControllerTest`, `Accounts`).
- GET `/sign-in` redirect to OIDC when OIDC-only and OIDC configured (tests in `AuthControllerTest`). Implementation to follow after tests.
**Implemented: OIDC-only mode:**
- ✅ Admin Settings: when OIDC-only is enabled, the "Allow direct registration" toggle is disabled with a hint.
- ✅ Backend rejects password sign-in and `register_with_password` when OIDC-only is active.
- ✅ GET `/sign-in` redirects to OIDC when OIDC-only and OIDC are configured (`MvWeb.Plugs.OidcOnlySignInRedirect`). The `oidc_only` setting and ENV are read via `Mv.Config.oidc_only?/0`.
**Missing Features:**
- ❌ Password reset flow
@ -183,6 +178,11 @@
- ✅ Navbar with profile button
- ✅ Member list as landing page
- ✅ Breadcrumbs (basic)
- ✅ **Flash: auto-dismiss and consistency** (Design Guidelines §9)
- Auto-dismiss implemented via the `FlashAutoDismiss` JS hook (`assets/js/app.js`) driven by the `data-auto-clear-ms` and `data-clear-flash-key` attributes on the flash component (`MvWeb.CoreComponents.flash/1`); the per-flash delay is set through the component's `auto_clear_ms` attribute, and the dismiss button is kept for accessibility.
- On timeout the hook pushes LiveView's built-in `lv:clear-flash` event (no custom `handle_event`) and hides the element.
- All flashes (including “Email copied”) use the same variants (info, success, warning, error); no special tone. See `DESIGN_GUIDELINES.md` §9.
- ❌ Per-kind default durations (info/success 46s, warning 68s, error 812s) are not built in — the delay is a single explicit `auto_clear_ms` value per flash, not a kind-based default.
**Open Issues:**
- [#188](https://git.local-it.org/local-it/mitgliederverwaltung/issues/188) - Check if searching just on typing is accessible (S, Low priority)
@ -196,11 +196,6 @@
- ❌ Mobile navigation
- ❌ Context-sensitive help
- ❌ Onboarding tooltips
- ❌ **Flash: Auto-dismiss and consistency** (Design Guidelines §9)
- Auto-dismiss: info/success 46s, warning 68s, error 812s; dismiss button kept for accessibility.
- Implement via JS hook (e.g. `FlashAutoDismiss`) + `data-dismiss-ms` (or `data-kind`) on flash component; on timeout push `lv:clear-flash` and hide element.
- LiveView: add shared `handle_event("lv:clear-flash", %{"key" => key}, socket)` (e.g. in `MvWeb` live_view quote) calling `clear_flash(socket, key)`.
- All flashes (including “Email copied”) use the same variants (info, success, warning, error); no special tone. See `DESIGN_GUIDELINES.md` §9.
---
@ -308,7 +303,12 @@
#### 10. **Reporting & Analytics** 📊
**Current State:**
- ✅ **Statistics page (MVP)** `/statistics` with active/inactive member counts, joins/exits by year, cycle totals, open amount (2026-02-10)
- ✅ **Statistics page (MVP)** `/statistics` with active/inactive member counts, joins/exits by year, cycle totals, open amount (2026-02-10). Backed by `Mv.Statistics` (read-only Ash reads on `Member` + `MembershipFeeCycle`, no new resources); displayed in `MvWeb.StatisticsLive`. Permission: read_only, normal_user, admin (own_data denied).
**MVP design decisions:**
- Charts are HTML/CSS + SVG only — no Contex, no Chart.js (deliberate).
- Open amount = total unpaid only; no overdue vs. not-yet-due split in the MVP.
- Out of scope (deferred follow-ups): export (CSV/PDF), caching, month/quarter filters, "members per fee type" / "members per group" stats, overdue split, new tables/resources.
**Missing Features:**
- ❌ Extended member statistics dashboard
@ -487,367 +487,13 @@
---
---
## Phase 2: API Endpoint Definition
### Endpoint Types
Since this is a **Phoenix LiveView** application with **Ash Framework**, we have three types of endpoints:
1. **LiveView Endpoints** - Mount points and event handlers
2. **HTTP Controller Endpoints** - Traditional REST-style endpoints
3. **Ash Resource Actions** - Backend data layer API
### Authentication Requirements Legend
- 🔓 **Public** - No authentication required
- 🔐 **Authenticated** - Requires valid user session
- 👤 **User Role** - Requires specific user role
- 🛡️ **Admin Only** - Requires admin privileges
---
### 1. Authentication & Authorization Endpoints
#### HTTP Controller Endpoints
| Method | Route | Purpose | Auth | Request | Response |
|--------|-------|---------|------|---------|----------|
| `GET` | `/auth/user/password/sign_in` | Show password login form | 🔓 | - | HTML form |
| `POST` | `/auth/user/password/sign_in` | Submit password login | 🔓 | `{email, password}` | Redirect + session cookie |
| `GET` | `/auth/user/oidc` | Initiate OIDC flow | 🔓 | - | Redirect to Rauthy |
| `GET` | `/auth/user/oidc/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 |
| `POST` | `/auth/user/password/reset/:token` | Submit new password | 🔓 | `{password, password_confirmation}` | Redirect to login |
#### Ash Resource Actions
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `User` | `:sign_in_with_password` | Password authentication | 🔓 | `{email, password}` | `{:ok, user}` or `{:error, reason}` |
| `User` | `:sign_in_with_oidc` | OIDC authentication | 🔓 | `{oidc_id, email, user_info}` | `{:ok, user}` or `{:error, reason}` |
| `User` | `:register_with_password` | Create user with password | 🔓 | `{email, password}` | `{:ok, user}` |
| `User` | `:register_with_oidc` | Create user via OIDC | 🔓 | `{oidc_id, email}` | `{:ok, user}` |
| `User` | `:request_password_reset` | Generate reset token | 🔓 | `{email}` | `{:ok, token}` |
| `User` | `:reset_password` | Reset password with token | 🔓 | `{token, password}` | `{:ok, user}` |
| `Token` | `:revoke` | Revoke authentication token | 🔐 | `{jti}` | `{:ok, token}` |
#### **NEW: Role & Permission Actions** (Issue #191, #190, #151)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `Role` | `:create` | Create new role | 🛡️ | `{name, description, permissions}` | `{:ok, role}` |
| `Role` | `:list` | List all roles | 🔐 | - | `[%Role{}]` |
| `Role` | `:update` | Update role | 🛡️ | `{id, name, permissions}` | `{:ok, role}` |
| `Role` | `:delete` | Delete role | 🛡️ | `{id}` | `{:ok, role}` |
| `User` | `:assign_role` | Assign role to user | 🛡️ | `{user_id, role_id}` | `{:ok, user}` |
| `User` | `:remove_role` | Remove role from user | 🛡️ | `{user_id, role_id}` | `{:ok, user}` |
| `Permission` | `:list` | List all permissions | 🔐 | - | `[%Permission{}]` |
| `Permission` | `:check` | Check user permission | 🔐 | `{user_id, resource, action}` | `{:ok, boolean}` |
---
### 2. Member Management Endpoints
#### LiveView Endpoints
| Mount | Purpose | Auth | Query Params | Events |
|-------|---------|------|--------------|--------|
| `/members` | Member list with search/sort | 🔐 | `?search=&sort_by=&sort_dir=` | `search`, `sort`, `delete`, `select` |
| `/members/new` | Create new member form | 🔐 | - | `save`, `cancel`, `add_custom_field_value` |
| `/members/:id` | Member detail view | 🔐 | - | `edit`, `delete`, `link_user` |
| `/members/:id/edit` | Edit member form | 🔐 | - | `save`, `cancel`, `add_custom_field_value`, `remove_custom_field_value` |
#### LiveView Event Handlers
| Event | Purpose | Params | Response |
|-------|---------|--------|----------|
| `search` | Trigger search | `%{"search" => query}` | Update member list |
| `sort` | Sort member list | `%{"field" => field}` | Update sorted list |
| `delete` | Delete member | `%{"id" => id}` | Redirect to list |
| `save` | Create/update member | `%{"member" => attrs}` | Redirect or show errors |
| `link_user` | Link user to member | `%{"user_id" => id}` | Update member view |
| `unlink_user` | Unlink user from member | - | Update member view |
| `add_custom_field_value` | Add custom field value | `%{"custom_field_id" => id, "value" => val}` | Update form |
| `remove_custom_field_value` | Remove custom field value | `%{"custom_field_value_id" => id}` | Update form |
#### Ash Resource Actions
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `Member` | `:create_member` | Create member | 🔐 | `{first_name, last_name, email, ...}` | `{:ok, member}` |
| `Member` | `:read` | List/search members | 🔐 | `{search, sort_by, limit, offset}` | `[%Member{}]` |
| `Member` | `:update_member` | Update member | 🔐 | `{id, attrs}` | `{:ok, member}` |
| `Member` | `:destroy` | Delete member | 🔐 | `{id}` | `{:ok, member}` |
| `Member` | `:search_fulltext` | Full-text search | 🔐 | `{query}` | `[%Member{}]` |
| `Member` | `:link_to_user` | Link member to user | 🔐 | `{member_id, user_id}` | `{:ok, member}` |
| `Member` | `:unlink_from_user` | Unlink from user | 🔐 | `{member_id}` | `{:ok, member}` |
#### **NEW: Enhanced Search & Filter Actions** (Issue #162, #154, #165)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `Member` | `:fuzzy_search` | Fuzzy text search | 🔐 | `{query, threshold}` | `[%Member{}]` |
| `Member` | `:advanced_search` | Multi-criteria search | 🔐 | `{filters: [{field, op, value}]}` | `[%Member{}]` |
| `Member` | `:paginate` | Paginated member list | 🔐 | `{page, per_page, filters}` | `{members, total, page_info}` |
| `Member` | `:sort_by_custom_field` | Sort by custom field | 🔐 | `{custom_field_id, direction}` | `[%Member{}]` |
| `Member` | `:bulk_delete` | Delete multiple members | 🛡️ | `{ids: [id1, id2, ...]}` | `{:ok, count}` |
| `Member` | `:bulk_update` | Update multiple members | 🛡️ | `{ids, attrs}` | `{:ok, count}` |
| `Member` | `:export` | Export to CSV/Excel | 🔐 | `{format, filters}` | File download |
| `Member` | `:import` | Import from CSV | 🛡️ | `{file, mapping}` | `{:ok, imported_count, errors}` |
---
### 3. Custom Fields (CustomFieldValue System) Endpoints
#### LiveView Endpoints (✅ Implemented)
| 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
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `CustomField` | `:create` | Create custom field | 🛡️ | `{name, value_type, description, ...}` | `{:ok, custom_field}` |
| `CustomField` | `:read` | List custom fields | 🔐 | - | `[%CustomField{}]` |
| `CustomField` | `:update` | Update custom field | 🛡️ | `{id, attrs}` | `{:ok, custom_field}` |
| `CustomField` | `:destroy` | Delete custom field | 🛡️ | `{id}` | `{:ok, custom_field}` |
| `CustomFieldValue` | `:create` | Add custom field value to member | 🔐 | `{member_id, custom_field_id, value}` | `{:ok, custom_field_value}` |
| `CustomFieldValue` | `:update` | Update custom field value | 🔐 | `{id, value}` | `{:ok, custom_field_value}` |
| `CustomFieldValue` | `:destroy` | Remove custom field value | 🔐 | `{id}` | `{:ok, custom_field_value}` |
#### **NEW: Enhanced Custom Fields** (Issue #194, #157, #161, #153)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `CustomField` | `:set_default_visibility` | Show/hide by default | 🛡️ | `{id, visible}` | `{:ok, custom_field}` |
| `CustomField` | `:set_required` | Mark as required | 🛡️ | `{id, required}` | `{:ok, custom_field}` |
| `CustomField` | `:add_validation` | Add validation rule | 🛡️ | `{id, rule_type, params}` | `{:ok, custom_field}` |
| `CustomField` | `:create_group` | Create field group | 🛡️ | `{name, custom_field_ids}` | `{:ok, group}` |
| `CustomFieldValue` | `:validate_value` | Validate custom field value | 🔐 | `{custom_field_id, value}` | `{:ok, valid}` or `{:error, reason}` |
---
### 4. User Management Endpoints
#### LiveView Endpoints
| Mount | Purpose | Auth | Events |
|-------|---------|------|--------|
| `/users` | User list | 🛡️ | `new`, `edit`, `delete`, `assign_role` |
| `/users/new` | Create user form | 🛡️ | `save`, `cancel` |
| `/users/:id` | User detail view | 🔐 | `edit`, `delete`, `change_password` |
| `/users/:id/edit` | Edit user form | 🔐 | `save`, `cancel`, `link_member` |
| `/profile` | Current user profile | 🔐 | `edit`, `change_password` |
#### Ash Resource Actions
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `User` | `:create_user` | Create user (admin) | 🛡️ | `{email, member_id?}` | `{:ok, user}` |
| `User` | `:read` | List users | 🛡️ | - | `[%User{}]` |
| `User` | `:update_user` | Update user | 🔐 | `{id, email, member_id?}` | `{:ok, user}` |
| `User` | `:destroy` | Delete user | 🛡️ | `{id}` | `{:ok, user}` |
| `User` | `:admin_set_password` | Set password (admin) | 🛡️ | `{id, password}` | `{:ok, user}` |
| `User` | `:change_password` | Change own password | 🔐 | `{current_password, new_password}` | `{:ok, user}` |
#### **NEW: Combined User/Member Management** (Issue #169, #168)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `User` | `:create_with_member` | Create user + member together | 🛡️ | `{user: {...}, member: {...}}` | `{:ok, %{user, member}}` |
| `User` | `:invite_user` | Send invitation email | 🛡️ | `{email, role_id, member_id?}` | `{:ok, invitation}` |
| `User` | `:accept_invitation` | Accept invitation | 🔓 | `{token, password}` | `{:ok, user}` |
---
### 5. Navigation & UX Endpoints
#### LiveView Endpoints
| Mount | Purpose | Auth | Events |
|-------|---------|------|--------|
| `/` | Dashboard/Home | 🔐 | - |
| `/dashboard` | Dashboard view | 🔐 | Contextual based on role |
#### HTTP Controller Endpoints
| Method | Route | Purpose | Auth | Request | Response |
|--------|-------|---------|------|---------|----------|
| `GET` | `/health` | Health check | 🔓 | - | `{"status": "ok"}` |
| `GET` | `/` | Root redirect | - | - | Redirect to dashboard or login |
---
### 6. Internationalization Endpoints
#### HTTP Controller Endpoints (✅ Implemented)
| 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 (✅ Implemented)
| 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 (✅ Partially Implemented)
| 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 (✅ Partially Implemented)
| 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 (✅ Partially Implemented)
| 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 |
---
### 9. Communication & Notifications Endpoints
#### LiveView Endpoints (NEW)
| Mount | Purpose | Auth | Events |
|-------|---------|------|--------|
| `/communications` | Communication history | 🔐 | `new`, `view` |
| `/communications/new` | Create email broadcast | 🔐 | `select_recipients`, `preview`, `send` |
| `/notifications` | User notifications | 🔐 | `mark_read`, `mark_all_read` |
#### Ash Resource Actions (NEW)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `EmailBroadcast` | `:create` | Create broadcast | 🔐 | `{subject, body, recipient_filter}` | `{:ok, broadcast}` |
| `EmailBroadcast` | `:send` | Send broadcast | 🔐 | `{id}` | `{:ok, sent_count}` |
| `EmailTemplate` | `:create` | Create template | 🛡️ | `{name, subject, body}` | `{:ok, template}` |
| `EmailTemplate` | `:render` | Render template | 🔐 | `{id, variables}` | `rendered_html` |
| `Notification` | `:create` | Create notification | System | `{user_id, type, message}` | `{:ok, notification}` |
| `Notification` | `:list_for_user` | Get user notifications | 🔐 | `{user_id}` | `[%Notification{}]` |
| `Notification` | `:mark_read` | Mark as read | 🔐 | `{id}` | `{:ok, notification}` |
---
### 10. Reporting & Analytics Endpoints
#### LiveView Endpoints (NEW)
| Mount | Purpose | Auth | Events |
|-------|---------|------|--------|
| `/reports` | Reports dashboard | 🔐 | `generate`, `schedule` |
| `/reports/members` | Member statistics | 🔐 | `filter`, `export` |
| `/reports/payments` | Payment reports | 🔐 | `filter`, `export` |
| `/reports/custom` | Custom report builder | 🛡️ | `build`, `save`, `run` |
#### Ash Resource Actions (NEW)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `Report` | `:generate_member_stats` | Member statistics | 🔐 | `{date_range, filters}` | Statistics object |
| `Report` | `:generate_payment_stats` | Payment statistics | 🔐 | `{date_range}` | Statistics object |
| `Report` | `:export_to_csv` | Export report to CSV | 🔐 | `{report_type, filters}` | CSV file |
| `Report` | `:export_to_pdf` | Export report to PDF | 🔐 | `{report_type, filters}` | PDF file |
| `Report` | `:schedule` | Schedule recurring report | 🛡️ | `{report_type, frequency, recipients}` | `{:ok, schedule}` |
---
### 11. Data Import/Export Endpoints
#### LiveView Endpoints (NEW)
| Mount | Purpose | Auth | Events |
|-------|---------|------|--------|
| `/import` | Data import wizard | 🛡️ | `upload`, `map_fields`, `preview`, `import` |
| `/export` | Data export tool | 🔐 | `select_data`, `configure`, `export` |
#### Ash Resource Actions (NEW)
| Resource | Action | Purpose | Auth | Input | Output |
|----------|--------|---------|------|-------|--------|
| `Member` | `:import_csv` | Import members from CSV | 🛡️ | `{file, field_mapping}` | `{:ok, imported, errors}` |
| `Member` | `:validate_import` | Validate import data | 🛡️ | `{file, field_mapping}` | `{:ok, validation_results}` |
| `Member` | `:export_csv` | Export members to CSV | 🔐 | `{filters}` | CSV file |
| `Member` | `:export_excel` | Export members to Excel | 🔐 | `{filters}` | Excel file |
| `Database` | `:export_backup` | Full database backup | 🛡️ | - | Backup file |
| `Database` | `:import_backup` | Restore from backup | 🛡️ | `{file}` | `{:ok, restored}` |
---
## Endpoints
For the real, current routes and their authorization, see `lib/mv_web/router.ex` and `docs/page-permission-route-coverage.md` (the per-permission-set route matrix). The Ash resource actions are defined on each resource module under `lib/`. An earlier speculative API catalog for not-yet-existing resources (Payment, Invoice, Report, Notification, AuditLog, Organization) was removed — those are tracked above as missing features per area, not as endpoint specs.
---
**References:**
- Open Issues: https://git.local-it.org/local-it/mitgliederverwaltung/issues
- Project Board: Sprint 8 (23.10 - 13.11)
- Architecture: See [`CODE_GUIDELINES.md`](../CODE_GUIDELINES.md)
- Database Schema: See [`database-schema-readme.md`](database-schema-readme.md)