From 34c713e8b3fe804ea479344cf95bdc4645bf72c0 Mon Sep 17 00:00:00 2001 From: gabdevele Date: Thu, 11 Jun 2026 01:25:18 +0200 Subject: [PATCH] Migrate email catcher to Mailpit --- .env.example | 4 ++-- AGENTS.md | 4 ++-- README.md | 10 +++++----- docker-compose.prod.yml | 4 ++-- docker-compose.yml | 8 ++++---- docs/API_SPEC.md | 2 +- docs/ARCHITECTURE.md | 2 +- docs/LLM_CONTEXT.md | 2 +- docs/MILESTONE_01.md | 4 ++-- docs/PROJECT_SPEC.md | 2 +- docs/openapi/visione.openapi.yaml | 4 ++-- scripts/lab/app.py | 2 +- services/AuthService.cc | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.env.example b/.env.example index e006411..e23b9f9 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,6 @@ MYSQL_DATABASE=visione MYSQL_USER=visione MYSQL_PASSWORD=visione MYSQL_ROOT_PASSWORD=root -MAILHOG_SMTP_PORT=1025 -MAILHOG_WEB_PORT=8025 +MAILPIT_SMTP_PORT=1025 +MAILPIT_WEB_PORT=8025 CORS_ALLOWED_ORIGIN=http://localhost:3000 diff --git a/AGENTS.md b/AGENTS.md index 185bdaf..bccfa40 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ - This repository is the backend for **Visione**, an urban issue reporting webapp. - The backend is C++20 with Drogon. Keep code, symbols, API fields, database names and comments in English. - User-facing product labels may be Italian when they represent UI/business vocabulary. -- Docker is for local external services only: MySQL, MailHog and future Redis-like dependencies. +- Docker is for local external services only: MySQL, Mailpit and future Redis-like dependencies. ## Authoritative References - Local Drogon source: `/home/gabdevele/Projects/snitchitaly/backend/drogon` @@ -31,5 +31,5 @@ ## Development Workflow - Update docs when behavior, schema, setup or API contracts change. - After each completed and verified feature, create a short commit. -- Keep commit messages concise, for example `Add MailHog config` or `Add report API`. +- Keep commit messages concise, for example `Add Mailpit config` or `Add report API`. - Do not spend excessive time on exhaustive tests; cover high-risk behavior and regressions. diff --git a/README.md b/README.md index fab360b..af4fcfe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Visione Backend C++20 API backend built with Drogon for the Visione urban reporting project. -Docker is used only for local external services: MySQL and MailHog. +Docker is used only for local external services: MySQL and Mailpit. ## Setup @@ -27,7 +27,7 @@ cmake --build build ``` The API listens on `http://localhost:5555`. -MailHog listens on `http://localhost:8025`. +Mailpit listens on `http://localhost:8025`. Local CORS allows `http://localhost:5173` by default for the future Vue frontend. Multipart uploads currently accept report images and videos up to the app body limit configured in `config.json`. @@ -138,9 +138,9 @@ backend deployment with MySQL and a local SMTP catcher. Configure the public domain in Dokploy against service `backend` and container port `5555`. The runtime image includes `config.json`; override environment-specific values -with Dokploy environment variables. The SMTP catcher service keeps the internal -name `mailhog` for compatibility, but uses the multi-architecture Mailpit image -to avoid `exec format error` failures on ARM servers. +with Dokploy environment variables. The SMTP catcher service uses the +multi-architecture Mailpit image to avoid `exec format error` failures on ARM +servers. Set `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `MYSQL_ROOT_PASSWORD` and `CORS_ALLOWED_ORIGIN` in Dokploy environment variables. Use the exact browser diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index a1f96ab..cc7875e 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -13,7 +13,7 @@ services: DB_PASSWORD: ${DB_PASSWORD:-visione} DB_NAME: ${DB_NAME:-visione} DB_TIMEOUT: ${DB_TIMEOUT:-30} - SMTP_HOST: ${SMTP_HOST:-mailhog} + SMTP_HOST: ${SMTP_HOST:-mailpit} SMTP_PORT: ${SMTP_PORT:-1025} CORS_ALLOWED_ORIGIN: ${CORS_ALLOWED_ORIGIN:-http://localhost:3000} expose: @@ -46,7 +46,7 @@ services: retries: 20 start_period: 20s - mailhog: + mailpit: image: axllent/mailpit:latest restart: unless-stopped expose: diff --git a/docker-compose.yml b/docker-compose.yml index b7d1506..3d16f0f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,11 +17,11 @@ services: retries: 20 start_period: 20s - mailhog: - image: mailhog/mailhog:v1.0.1 + mailpit: + image: axllent/mailpit:latest ports: - - "${MAILHOG_SMTP_PORT:-1025}:1025" - - "${MAILHOG_WEB_PORT:-8025}:8025" + - "${MAILPIT_SMTP_PORT:-1025}:1025" + - "${MAILPIT_WEB_PORT:-8025}:8025" volumes: mysql-data: diff --git a/docs/API_SPEC.md b/docs/API_SPEC.md index e0f2a8d..53d6d44 100644 --- a/docs/API_SPEC.md +++ b/docs/API_SPEC.md @@ -10,7 +10,7 @@ Base path: `/api/v1`. ## Auth - `POST /auth/register`: create a citizen account. -- `POST /auth/otp/request`: send an OTP email through MailHog. +- `POST /auth/otp/request`: send an OTP email through Mailpit. - `POST /auth/otp/verify`: verify OTP and create an API token. - `POST /auth/login/password`: password login fallback. - `POST /auth/change-password`: change the authenticated user's password. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a3b447e..68b969f 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -20,7 +20,7 @@ The codebase does not use Drogon generated models or `Mapper`. Raw SQL stays in repository/database helpers because the schema is still evolving. ## Local Email -OTP emails are sent to MailHog over SMTP. MailHog keeps messages local and +OTP emails are sent to Mailpit over SMTP. Mailpit keeps messages local and inspectable through its web UI. ## Password Hashing diff --git a/docs/LLM_CONTEXT.md b/docs/LLM_CONTEXT.md index a53829b..2bca72b 100644 --- a/docs/LLM_CONTEXT.md +++ b/docs/LLM_CONTEXT.md @@ -8,7 +8,7 @@ and use intervention summaries. Admins manage roles, users, areas, teams, reference data, moderation and stats. The project runs locally on the host machine. Docker is used only for external -services such as MySQL and MailHog. Real production deployment and Dockerizing +services such as MySQL and Mailpit. Real production deployment and Dockerizing the backend are later delivery tasks. Important conventions: diff --git a/docs/MILESTONE_01.md b/docs/MILESTONE_01.md index 73eaf22..a52a85c 100644 --- a/docs/MILESTONE_01.md +++ b/docs/MILESTONE_01.md @@ -3,10 +3,10 @@ ## Implemented in this milestone - Project identity and documentation for Visione. - Root `AGENTS.md` for future coding agents. -- Local Docker services for MySQL and MailHog. +- Local Docker services for MySQL and Mailpit. - Initial MySQL schema and seed data. - Drogon backend structure for auth, reports, admin data and stats. -- OTP email delivery through MailHog. +- OTP email delivery through Mailpit. - Focused regression tests for technical endpoints and core validation helpers. - Local admin seed: `admin@visione.local` / `ChangeMe123!`, with forced password change flag. - Multipart report media upload endpoint storing files under `uploads/reports/`. diff --git a/docs/PROJECT_SPEC.md b/docs/PROJECT_SPEC.md index ade9325..bee95fb 100644 --- a/docs/PROJECT_SPEC.md +++ b/docs/PROJECT_SPEC.md @@ -34,7 +34,7 @@ Valid milestone 2 transitions: - `REJECTED -> CLOSED`. ## MVP Scope -- Local auth with email OTP delivered through MailHog. +- Local auth with email OTP delivered through Mailpit. - MySQL persistence with migrations and seed data. - Report creation/list/detail/status/message/assignment/feedback/moderation flows. - Area polygons stored as GeoJSON and matched by backend logic. diff --git a/docs/openapi/visione.openapi.yaml b/docs/openapi/visione.openapi.yaml index f94e88a..c9a432d 100644 --- a/docs/openapi/visione.openapi.yaml +++ b/docs/openapi/visione.openapi.yaml @@ -897,7 +897,7 @@ "additionalProperties": false, "properties": { "delivery": { - "example": "mailhog", + "example": "mailpit", "type": "string" }, "expires_in_minutes": { @@ -2209,7 +2209,7 @@ }, "/api/v1/auth/otp/request": { "post": { - "description": "Sends a one-time code by email through MailHog locally.", + "description": "Sends a one-time code by email through Mailpit locally.", "operationId": "AuthController.requestOtp", "parameters": [], "requestBody": { diff --git a/scripts/lab/app.py b/scripts/lab/app.py index 6f2d4a3..b95c201 100644 --- a/scripts/lab/app.py +++ b/scripts/lab/app.py @@ -466,6 +466,6 @@ with docs_tab: with st.sidebar: st.text_input("Backend API", key="base_url") st.text_input("Bearer token", key="token", type="password") - st.link_button("MailHog", "http://127.0.0.1:8025") + st.link_button("Mailpit", "http://127.0.0.1:8025") if st.button("Health check"): show_response(request("GET", "/health", timeout=5)) diff --git a/services/AuthService.cc b/services/AuthService.cc index 7809d99..0d6109c 100644 --- a/services/AuthService.cc +++ b/services/AuthService.cc @@ -147,12 +147,12 @@ Json::Value AuthService::requestOtp(const Json::Value &body) email::EmailService mail; if (!mail.sendOtp(user[0]["email"].as(), code)) { - LOG_WARN << "Could not send OTP email through MailHog"; + LOG_WARN << "Could not send OTP email through Mailpit"; return failure("otp_email_failed"); } auto response = success(); - response["delivery"] = "mailhog"; + response["delivery"] = "mailpit"; response["expires_in_minutes"] = otpTtlMinutes(); return response; }