Dev setup
Dev setup
Section titled “Dev setup”Prerequisites
Section titled “Prerequisites”- Rust ≥ 1.88 (pinned in
rust-toolchain.toml) - Bun ≥ 1.3 (for React Email templates)
- Docker + Docker Compose (for Postgres + Mailpit)
- make (the Makefile is the canonical entry point)
Optional:
swaksfor SMTP smoke testing.jqfor piping JSON responses.psqlfor poking the apalis job table.
First clone
Section titled “First clone”git clone https://github.com/donilite/mailify.gitcd mailify
# Install JS deps for the templates workspacemake setup
# Bring up Postgres + Mailpitmake up-deps
# Compile templates oncemake build-templates
# Run the servermake devVisit http://localhost:8080/swagger-ui for the API explorer. Mailpit UI at http://localhost:8025.
Daily workflow
Section titled “Daily workflow”| Task | Command |
|---|---|
| Start deps | make up-deps |
| Run server with hot restart | make dev (Ctrl+C and re-run on edits) |
| Preview templates | make dev-templates |
Rebuild templates after .tsx edit | make build-templates |
| Run all tests | make test |
| Run a single test | cargo test -p <crate> <test_name> |
| Format | make fmt |
| Lint (CI-strict) | make clippy |
| Full CI check | make ci |
Running integration tests
Section titled “Running integration tests”Integration tests under crates/mailify-api/tests/ require Postgres + Mailpit.
# In one terminal, bring up deps:make up-deps
# In another:cargo test -p mailify-api --test it_e2eEnvironment variables the tests expect:
MAILIFY_DATABASE__URL=postgres://mailify:mailify@localhost:5432/mailifyMAILIFY_SMTP__HOST=localhostMAILIFY_SMTP__PORT=1025MAILIFY_SMTP__TLS=noneMAILPIT_API_URL=http://localhost:8025MAILIFY_DOTENV=falseThese are set automatically by the CI workflow — see .github/workflows/ci.yml.
Editor setup
Section titled “Editor setup”VSCode
Section titled “VSCode”Recommended extensions:
rust-analyzer(Rust)Even Better TOML(config files — once we publish a JSON schema, this will autocompleteMailify.toml)PrettierorBiome(templates-parser/)
.vscode/settings.json suggestions:
{ "rust-analyzer.cargo.allTargets": true, "rust-analyzer.check.command": "clippy", "rust-analyzer.check.extraArgs": ["--", "-D", "warnings"], "[rust]": { "editor.formatOnSave": true, "editor.defaultFormatter": "rust-lang.rust-analyzer" }}Neovim / Zed / Helix
Section titled “Neovim / Zed / Helix”Configure LSP to target rust-analyzer with the same --all-targets + clippy args. Format-on-save is enforced by CI (make fmt-check), so wire it up in your editor to save headaches.
Commit style
Section titled “Commit style”Conventional Commits — prefixes like feat:, fix:, chore:, refactor:, test:, docs:. These drive the auto-generated changelog on release.
Good examples from history:
feat: enhance CI/CD pipeline with multi-platform Docker builds and configuration file discoverytest: update expected status from "queued" to "pending" in mailpit delivery testchore: update package versions to 0.1.2 in Cargo.lock and Cargo.tomlfix: propagate MAILIFY_AUTH__JWT_SECRET through AppState for require_jwt middlewareBefore opening a PR
Section titled “Before opening a PR”Run:
make ciThat runs fmt-check + clippy (-D warnings) + tests. If make ci is green, CI will be green too.
Small things to remember:
- New public API? Doc-comment it, and if it affects a user-facing endpoint, update
docs/reference/http-api.md. - New config key? Add it to
docs/reference/config.mdwith its TOML path, env var, type, default, and purpose. - New error? Consider adding it to
docs/troubleshooting/common-errors.mdwith a diagnosis + fix. - Breaking change? Call it out in the PR description. It’ll show up in the release notes.