The growing row of bulk-action buttons above the member overview is replaced by one "Aktionen" dropdown holding all four actions (open in email program, copy addresses, export CSV, export PDF). With no selection the actions operate on all — or the currently filtered — members; the email-program action is disabled past a recipient cap, because the browser cannot reliably hand a very long mailto over to the mail client. The trigger shows the active scope as a badge: an emphasized count when members are selected, a muted "alle"/"gefiltert" otherwise. |
||
|---|---|---|
| .forgejo | ||
| assets | ||
| config | ||
| docs | ||
| lib | ||
| priv | ||
| rauthy-bootstrap | ||
| rel/overlays/bin | ||
| test | ||
| .credo.exs | ||
| .deps_audit_ignore | ||
| .dialyzer_ignore.exs | ||
| .dockerignore | ||
| .drone.jsonnet | ||
| .editorconfig | ||
| .env.example | ||
| .formatter.exs | ||
| .gitignore | ||
| .igniter.exs | ||
| .sobelow-conf | ||
| .tool-versions | ||
| CHANGELOG.md | ||
| CODE_GUIDELINES.md | ||
| DESIGN_GUIDELINES.md | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| Justfile | ||
| LICENSE | ||
| mix.exs | ||
| mix.lock | ||
| README.md | ||
| renovate.json | ||
| renovate_backend_config.js | ||
Mila
Mila — simple, usable, self-hostable membership management for small to mid-sized clubs.
🚧 Project Status
⚠️ First Version — Expect breaking changes.
Contributions and feedback are welcome!
✨ Overview
Mila is a free and open-source membership management tool designed for real club needs.
It is self-hosting friendly, aims for accessibility and GDPR compliance, and focuses on usability instead of feature overload.
💡 Why Mila?
Most membership tools for clubs are either:
- Too complex — overloaded with features small and mid-sized clubs don’t need
- Too expensive — hidden fees, closed ecosystems, vendor lock-in
- Too rigid — no way to adapt fields, processes, or roles to your club’s reality
Mila is different:
- Simple: Focused on what clubs really need — members, dues, communication.
- Usable: Clean, accessible UI, GDPR-compliant, designed with everyday volunteers in mind.
- Flexible: Customize what data you collect about members, role-based permissions, and self-service for members.
- Truly open: 100% free and open source — no lock-in, transparent code, self-host friendly.
Our philosophy: software should help people spend less time on administration and more time on their community.
User Documentation (German)
You can find our documentation for users here: https://wiki.local-it.org/s/mila-user-dokumentation
🔑 Features
- ✅ Manage member data with ease
- ✅ 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 improvements (WCAG 2.1 AA compliant keyboard navigation)
- ✅ Email sending
- ✅ Integration of Accounting-Software (Vereinfacht)
🚀 Quick Start (Development)
Prerequisites
We recommend using asdf for managing tool versions.
- Tested with:
asdf 0.16.5 - Required versions are documented in
.tool-versionsin this repo
Install system dependencies (Debian/Ubuntu)
# Debian 12
apt-get -y install build-essential autoconf m4 libncurses-dev libwxgtk3.2-dev libwxgtk-webview3.2-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libssh-dev unixodbc-dev xsltproc fop libxml2-utils openjdk-17-jdk icu-devtools bison flex pkg-config
# Ubuntu 24
apt-get -y install build-essential autoconf m4 libwxgtk3.2-dev libwxgtk-webview3.2-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libssh-dev unixodbc-dev xsltproc fop libxml2-utils libncurses-dev openjdk-11-jdk icu-devtools bison flex libreadline-dev
Install asdf
mkdir ~/.asdf
cd ~/.asdf
wget https://github.com/asdf-vm/asdf/releases/download/v0.16.5/asdf-v0.16.5-linux-amd64.tar.gz
tar -xvf asdf-v0.16.5-linux-amd64.tar.gz
ln -s ~/.asdf/asdf ~/.local/bin/asdf
Then follow the official “Shell Configuration” steps in the asdf docs.
Fish example (~/.config/fish/config.fish):
asdf completion fish > ~/.config/fish/completions/asdf.fish
set -gx PATH "$HOME/.asdf/shims" $PATH
Bash example (~/.bash_profile and ~/.bashrc):
export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"
. <(asdf completion bash)
Install project dependencies
git clone https://git.local-it.org/local-it/mitgliederverwaltung.git mila
cd mila
asdf plugin add elixir
asdf plugin add erlang
asdf plugin add just
asdf install
# Inside the repo folder:
mix local.hex
mix archive.install hex phx_new
Note: running
mix local.hexmust be done inside the repo folder,
because.tool-versionsdefines the Erlang/Elixir versions.
Run the app
-
Copy env file:
cp .env.example .envThe dev
OIDC_CLIENT_SECRETis already preset — no manual GUI step needed. -
Start everything (database, Mailcrab, Rauthy, app):
just run -
Services will be available at:
- App: http://localhost:4000
- Mail UI: http://localhost:1080
- Postgres:
localhost:5000
🔐 Testing SSO locally
A local Rauthy instance is provided in dev. The mv client is auto-seeded from rauthy-bootstrap/clients.json on first start (and after docker compose down -v), so the secret in .env.example always matches.
Rauthy admin UI: http://localhost:8080 — login admin@localhost, password from BOOTSTRAP_ADMIN_PASSWORD_PLAIN in docker-compose.yml.
OIDC with other providers (Authentik, Keycloak, etc.)
Mila works with any OIDC-compliant provider. The internal strategy is named :oidc — it works with any OIDC-compliant provider.
Important: The redirect URI must always end with /auth/user/oidc/callback.
Example for Authentik:
- Create an OAuth2/OpenID Provider in Authentik
- Set the redirect URI to:
https://your-domain.com/auth/user/oidc/callback - Configure environment variables:
DOMAIN=your-domain.com # or PHX_HOST=your-domain.com OIDC_CLIENT_ID=your-client-id OIDC_BASE_URL=https://auth.example.com/application/o/your-app OIDC_CLIENT_SECRET=your-client-secret # or use OIDC_CLIENT_SECRET_FILE
The OIDC_REDIRECT_URI is auto-generated as https://{DOMAIN}/auth/user/oidc/callback if not explicitly set.
⚙️ Configuration
- Env vars: see
.env.example
🏗️ Architecture
Tech Stack Overview:
- Backend: Elixir + Phoenix + Ash Framework
- Frontend: Phoenix LiveView + Tailwind CSS + DaisyUI
- Database: PostgreSQL
- Auth: AshAuthentication (OIDC + password)
Code Structure:
lib/accounts/&lib/membership/&lib/membership_fees/&lib/mv/authorization/— Ash resources and domainslib/mv_web/— Phoenix controllers, LiveViews, componentslib/mv/— Shared helpers and business logicassets/— Tailwind, JavaScript, static filestest/— All tests
📚 Full tech stack details: See CODE_GUIDELINES.md
📖 Implementation history: See docs/development-progress-log.md
🗄️ Database schema: See docs/database-schema-readme.md
🧑💻 Development
Common commands:
just run # Start full dev environment
just test # Run test suite
just lint # Code style checks
just audit # Security audits
just reset-database # Reset local DB
📚 Full development guidelines: See CODE_GUIDELINES.md
📦 Production Deployment
Local Production Testing
For testing the production Docker build locally:
-
Generate secrets:
mix phx.gen.secret # for SECRET_KEY_BASE mix phx.gen.secret # for TOKEN_SIGNING_SECRET -
Create
.envfile:# Copy template and edit cp .env.example .env nano .env -
Start production environment:
docker compose -f docker-compose.prod.yml up -
Database migrations run automatically on app start. For manual migration:
docker compose -f docker-compose.prod.yml exec app /app/bin/mv eval "Mv.Release.migrate" -
Access the production app:
- Production App: http://localhost:4001
- Uses same Rauthy instance as dev (localhost:8080)
Note: The local production setup uses network_mode: host to share localhost with the development Rauthy instance. For real production deployment, configure an external OIDC provider and remove network_mode: host.
Real Production Deployment
For actual production deployment:
- Use an external OIDC provider (not the local Rauthy)
- Update
docker-compose.prod.yml:- Remove
network_mode: host - Set
OIDC_BASE_URLto your production OIDC provider - Configure proper Docker networks
- Remove
- Set up SSL/TLS (e.g., via reverse proxy like Nginx/Traefik)
- Use secure secrets management — All sensitive environment variables support a
_FILEsuffix for Docker secrets (e.g.,SECRET_KEY_BASE_FILE=/run/secrets/secret_key_base). Seedocker-compose.prod.ymlfor an example setup with Docker secrets. - Configure database backups
🤝 Contributing
We welcome contributions!
- Open issues and PRs in this repo
- Please follow existing code style and conventions
- Expect breaking changes while the project is in early development
📄 License
License: AGPLv3
See the LICENSE file for details.
📬 Contact
- Issues: GitLab Issues
- E-Mail: info@local-it.org