272 lines
8.9 KiB
Markdown
272 lines
8.9 KiB
Markdown
# Mila
|
||
|
||
**Mila** — simple, usable, self-hostable membership management for small to mid-sized clubs.
|
||
|
||
[](https://drone.dev.local-it.cloud/local-it/mitgliederverwaltung)
|
||

|
||
|
||
## 🚧 Project Status
|
||
|
||
⚠️ **Early development** — not production-ready. 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.**
|
||
|
||
## 📸 Screenshots
|
||
|
||

|
||
*This is how Mila might look in action.*
|
||
|
||
## 🔑 Features
|
||
|
||
- ✅ Manage member data with ease
|
||
- 🚧 Overview of membership fees & payment status
|
||
- ✅ Full-text search
|
||
- 🚧 Sorting & filtering
|
||
- 🚧 Roles & permissions (e.g. board, treasurer)
|
||
- ✅ Custom fields (flexible per club needs)
|
||
- ✅ SSO via OIDC (tested with Rauthy)
|
||
- 🚧 Self-service & online application
|
||
- 🚧 Accessibility, GDPR, usability improvements
|
||
- 🚧 Email sending
|
||
|
||
## 🚀 Quick Start (Development)
|
||
|
||
### Prerequisites
|
||
|
||
We recommend using **[asdf](https://asdf-vm.com/)** for managing tool versions.
|
||
- Tested with: `asdf 0.16.5`
|
||
- Required versions are documented in `.tool-versions` in this repo
|
||
|
||
<details>
|
||
<summary>Install system dependencies (Debian/Ubuntu)</summary>
|
||
|
||
```bash
|
||
# 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
|
||
```
|
||
</details>
|
||
|
||
<details>
|
||
<summary>Install asdf</summary>
|
||
|
||
```bash
|
||
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`):
|
||
|
||
```fish
|
||
asdf completion fish > ~/.config/fish/completions/asdf.fish
|
||
set -gx PATH "$HOME/.asdf/shims" $PATH
|
||
```
|
||
|
||
*Bash example* (`~/.bash_profile` and `~/.bashrc`):
|
||
|
||
```bash
|
||
export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"
|
||
. <(asdf completion bash)
|
||
```
|
||
</details>
|
||
|
||
### Install project dependencies
|
||
|
||
```bash
|
||
git clone https://git.local-it.org/local-it/mitgliederverwaltung.git mila
|
||
cd mila
|
||
asdf install
|
||
|
||
# Inside the repo folder:
|
||
mix local.hex
|
||
mix archive.install hex phx_new
|
||
```
|
||
|
||
> Note: running `mix local.hex` must be done inside the repo folder,
|
||
> because `.tool-versions` defines the Erlang/Elixir versions.
|
||
|
||
### Run the app
|
||
|
||
1. Copy env file:
|
||
```bash
|
||
cp .env.example .env
|
||
# Set OIDC_CLIENT_SECRET inside .env
|
||
```
|
||
|
||
2. Start everything (database, Mailcrab, Rauthy, app):
|
||
```bash
|
||
just run
|
||
```
|
||
|
||
3. Services will be available at:
|
||
- App: <http://localhost:4000>
|
||
- Mail UI: <http://localhost:1080>
|
||
- Postgres: `localhost:5000`
|
||
|
||
## 🔐 Testing SSO locally
|
||
|
||
Mila uses OIDC for Single Sign-On. In development, a local **Rauthy** instance is provided.
|
||
|
||
1. `just run`
|
||
2. go to [localhost:8080](http://localhost:8080), go to the Admin area
|
||
3. Login with "admin@localhost" and password from `BOOTSTRAP_ADMIN_PASSWORD_PLAIN` in docker-compose.yml
|
||
4. add client from the admin panel
|
||
- Client ID: mv
|
||
- redirect uris: http://localhost:4000/auth/user/rauthy/callback
|
||
- Authorization Flows: authorization_code
|
||
- allowed origins: http://localhost:4000
|
||
- access/id token algortihm: RS256 (EDDSA did not work for me, found just few infos in the ashauthentication docs)
|
||
5. copy client secret to `.env` file
|
||
6. abort and run `just run` again
|
||
|
||
Now you can log in to Mila via OIDC!
|
||
|
||
## ⚙️ Configuration
|
||
|
||
- **Env vars:** see `.env.example`
|
||
- `OIDC_CLIENT_SECRET` — secret for your OIDC client
|
||
- Database defaults (Docker Compose):
|
||
- Host: `localhost`
|
||
- Port: `5000`
|
||
- User/pass: `postgres` / `postgres`
|
||
- DB: `mila_dev`
|
||
|
||
## 🏗️ 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/` — Ash resources and domains
|
||
- `lib/mv_web/` — Phoenix controllers, LiveViews, components
|
||
- `assets/` — Tailwind, JavaScript, static files
|
||
|
||
📚 **Full tech stack details:** See [`CODE_GUIDELINES.md`](CODE_GUIDELINES.md)
|
||
📖 **Implementation history:** See [`docs/development-progress-log.md`](docs/development-progress-log.md)
|
||
🗄️ **Database schema:** See [`docs/database-schema-readme.md`](docs/database-schema-readme.md)
|
||
|
||
## 🧑💻 Development
|
||
|
||
**Common commands:**
|
||
```bash
|
||
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`](CODE_GUIDELINES.md)
|
||
|
||
## 📦 Production Deployment
|
||
|
||
### Local Production Testing
|
||
|
||
For testing the production Docker build locally:
|
||
|
||
1. **Generate secrets:**
|
||
```bash
|
||
mix phx.gen.secret # for SECRET_KEY_BASE
|
||
mix phx.gen.secret # for TOKEN_SIGNING_SECRET
|
||
```
|
||
|
||
2. **Create `.env` file:**
|
||
```bash
|
||
# Copy template and edit
|
||
cp .env.example .env
|
||
nano .env
|
||
|
||
# Required variables:
|
||
SECRET_KEY_BASE=<your-generated-secret>
|
||
TOKEN_SIGNING_SECRET=<your-generated-secret>
|
||
PHX_HOST=localhost
|
||
|
||
# Optional (have defaults in docker-compose.prod.yml):
|
||
# OIDC_CLIENT_ID=mv
|
||
# OIDC_BASE_URL=http://localhost:8080/auth/v1
|
||
# OIDC_REDIRECT_URI=http://localhost:4001/auth/user/rauthy/callback
|
||
# OIDC_CLIENT_SECRET=<from-rauthy-client>
|
||
```
|
||
|
||
3. **Start development environment** (for Rauthy):
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
4. **Start production environment:**
|
||
```bash
|
||
docker compose -f docker-compose.prod.yml up
|
||
```
|
||
|
||
5. **Run database migrations:**
|
||
```bash
|
||
docker compose -f docker-compose.prod.yml exec app /app/bin/mv eval "Mv.Release.migrate"
|
||
```
|
||
|
||
6. **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:
|
||
|
||
1. **Use an external OIDC provider** (not the local Rauthy)
|
||
2. **Update `docker-compose.prod.yml`:**
|
||
- Remove `network_mode: host`
|
||
- Set `OIDC_BASE_URL` to your production OIDC provider
|
||
- Configure proper Docker networks
|
||
3. **Set up SSL/TLS** (e.g., via reverse proxy like Nginx/Traefik)
|
||
4. **Use secure secrets management** — All sensitive environment variables support a `_FILE` suffix for Docker secrets (e.g., `SECRET_KEY_BASE_FILE=/run/secrets/secret_key_base`). See `docker-compose.prod.yml` for an example setup with Docker secrets.
|
||
5. **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](LICENSE) file for details.
|
||
|
||
## 📬 Contact
|
||
|
||
- Issues: [GitLab Issues](https://git.local-it.org/local-it/mitgliederverwaltung/-/issues)
|
||
- Community links: coming soon.
|