15 — Development Workflow (The Edit → Build → Test Loop)
This is the "I just want to make a change and see it work" guide.
Getting Started: Local Development & Testing (First Time)
This section is the full onboarding flow for developers who are building and testing madmail-v2 from source.
Requirements
- Rust (stable, ≥ 1.75)
make- (Optional but recommended)
bunornpm— only needed if you plan to work on or preview the admin web UI
Steps
# 1. Get the code
git clone ... # or however you obtained the repository
cd madmailv2
# 2. Build the server
make build
# 3. Start it in the background with debug logging
make restart
# 4. Watch the logs in another terminal
make logs
The server is now running with sensible development defaults.
Connecting Delta Chat Clients for Testing
Point Delta Chat (Desktop or Android) at:
- IMAP:
127.0.0.1port1143(or993for TLS) - SMTP / Submission:
127.0.0.1port1025(or465/587) - Address: [email protected] or anything@localhost (dev mode accepts these)
- Password: anything — the account is created automatically (JIT)
You can also reach the admin interface at:
- http://127.0.0.1:8080/admin/
- Token is in the file
data/admin_token
Useful Make Targets for Daily Development Work
make restart— rebuild + restart (the most common command)make logs— follow the log filemake stopmake reset-db— wipe the database (keeps themail/folder)make dev-certs— regenerate self-signed TLS certificates for 127.0.0.1
make restart is deliberately lightweight and does not rebuild the admin web SPA.
The Golden Local Loop (90% of daily work)
# 1. Make your edit in crates/ or docs/
# 2. Rebuild + restart the dev server
make restart # stop + dev-certs + run-bg (with debug logging)
# 3. Watch logs in another terminal
make logs
# 4. Exercise your change
# - Use Delta Chat desktop pointed at 127.0.0.1:1143 / 1025 (or whatever your config says)
# - Or use the relay-ping tool
# - Or curl the admin API with the token from data/admin_token
# - Or open http://127.0.0.1:8080/admin/ (after make build-with-admin-web)
# 5. When done
make stop
make restart is deliberately fast for the common case (it does not rebuild the admin web SPA).
When You Change the Admin Web SPA
# Edit files in external/madmail-admin-web/src/...
# From repo root:
make build-with-admin-web # builds SPA + re-embeds + rebuilds madmail
make restart
Then hard-reload the browser at /admin/. The version.json stamp helps with service worker cache.
Working with the Database
# Inspect
sqlite3 data/chatmail.db ".schema"
sqlite3 data/chatmail.db "SELECT * FROM settings;"
sqlite3 data/chatmail.db "SELECT key, substr(value,1,60) FROM settings;"
# After editing a migration .sql file you often need a clean DB
make reset-db
make restart
make reset-db removes both the app DB and the credentials DB (but keeps the mail/ tree and config).
Adding a New CLI Command (Madmail Parity Style)
- Add the clap definition in
chatmail-config/src/cli.rs. - Add a handler module in
crates/chatmail/src/ctl/your_cmd.rs. - Wire it in
ctl/dispatch.rs(or the big match). - Add a test in
ctl/dispatch_tests.rsorops_tests.rs. - Document the parity status in
docs/TDD/14-cli-tools.md.
Many "stub" commands exist that just print "not yet implemented — use the Admin API instead".
Adding a New Admin Resource
- Create
crates/chatmail-admin/src/resources/your_thing.rs. - Implement the handler function(s) that read/write the DB or AppState.
- Register the method in the big dispatch in
handler.rsorrouter.rs. - Add a matching entry in the Svelte admin UI (if you want it visible in the dashboard).
- Add tests (unit in the admin crate or E2E via the ctl binary).
Working on SMTP / IMAP Changes
- Unit tests in the crate itself are fast.
- For protocol-level work, use
make run-bg+ a tool likeswaks,openssl s_client -crlf, or a Python IMAP client against the dev ports. - The full E2E (
make test-e2eor specificcargo test -p chatmail-integration imap_) is the final gate.
Working on Federation or Delivery
- Stand up two local instances (different state dirs + ports).
- Or use the existing multi-server E2E tests.
- Inspect the outbound queue with the admin
queueresource or by looking indata/remote_queue/.
Debugging a Running Server
make logs(follows the nohup log from run-bg)RUST_LOG=debug,chatmail=trace cargo run ...for extreme verbosity (whendebug trueis also in the config)sudo ss -tlnp | grep madmailor the admin listener-ports resource to see what is actually boundsqlite3 data/chatmail.db "SELECT * FROM federation_stats ORDER BY last_updated DESC LIMIT 20;"- For TURN: the dedicated debug env script
scripts/turn-debug-env.sh
When You Need a Completely Clean Slate
make stop
make reset-db
rm -rf data/mail data/certs
make dev-certs
make restart
Working on Tests
- Fast unit:
cargo test -p chatmail-foo - E2E that still uses the just-built binary:
make test-e2e - Specific E2E filter:
cargo test -p chatmail-integration -- turn_ - Full Delta Chat client E2E (slow, needs incus + uv + cmlxc):
make test-deltachat
Git & Submodules
- Normal Rust changes: just commit in
crates/,docs/,scripts/,Makefile. - Admin web changes: edit in
external/madmail-admin-web/, commit there (it is a separate repo), then the parent repo records the new submodule pointer. - Never commit the huge
target/ornode_modules/trees. .envanddata/are gitignored (or should be).
Next
The final document in the series covers troubleshooting, common gotchas, and the full testing story.