marchi

module
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: MIT

README

Marchi

Marchi — self-hosted сервис архивации электронной почты. Подключает произвольные IMAP-аккаунты, архивирует письма в фоне по настраиваемым правилам, даёт полнотекстовый поиск по архиву, умеет реплицировать архив в S3-совместимое хранилище и восстанавливать письма обратно в почтовый ящик.

Работает на одном бинарнике без внешних зависимостей (кроме опционального S3), хранит все данные локально (SQLite + Maildir), шифрует пароли/токены/S3-ключи на диске.

Возможности

  • IMAP-аккаунты: пароль или OAuth2 (Google/Microsoft, BYO-приложение — свой client_id/client_secret, Marchi не поставляет общий клиент).
  • Gmail API-коннектор: альтернатива IMAP для Google-аккаунтов — синк через нативный Gmail REST API с дельта-синхронизацией (History API) вместо полного обхода UID; пока только через REST (POST /api/v1/accounts/oauth2 с "connector_type": "gmail_api"), без формы в Web UI. Подробности — docs/api/openapi.yaml.
  • MS Graph-коннектор: аналогично для Microsoft 365/Exchange Online — синк через Microsoft Graph REST API с реальными иерархическими папками (не как у Gmail — с метками) и дельта-синхронизацией per-folder. "connector_type": "ms_graph" в том же эндпоинте.
  • Правила архивации: визуальный AND/OR-конструктор условий (тема, отправитель, домен, вложения, размер, дата, папка — 15 типов условий, вложенность до 3 уровней), действия archive/skip/archive_and_delete/archive_and_mark_read. Правила можно редактировать и в Web UI, и через rules.yaml (однонаправленная синхронизация файла в БД, отслеживается через fsnotify). «Проверить на архиве» — dry-run нового условия против уже заархивированных писем, до сохранения правила. Каждое правило накапливает счётчик срабатываний и дату последнего совпадения, видимые прямо в списке правил.
  • Полнотекстовый поиск: индекс на Bluge по теме/телу/отправителю/вложениям, с фильтрами по дате/аккаунту/папке.
  • S3-репликация: зеркалирование заархивированных писем в любое S3-совместимое хранилище (AWS S3, MinIO, ...) с клиентским шифрованием (AES-256-GCM) перед загрузкой.
  • Retention: трёхстадийный жизненный цикл письма — локально → перенос в S3 → окончательное удаление, с настраиваемыми по умолчанию и переопределяемыми на уровне аккаунта порогами в днях.
  • Восстановление: письмо (или пачка писем по результатам поиска) можно вернуть в любой IMAP-аккаунт через APPEND, с фолбэком на SMTP — как по выбору, так и целиком весь аккаунт/папку, опционально сузив по диапазону дат.
  • Массовые операции над результатами поиска: удаление и перенос в другую папку (в рамках того же аккаунта) выбранных писем, экспорт выбранного (или всего результата поиска) в .zip (по письму на файл) или в один файл mbox.
  • Импорт: перенос почты из mbox, Maildir или отдельных .eml в архив — marchi import (CLI; идемпотентно — повторный запуск докачивает только новое, дедупликация по Message-ID).
  • Уведомления о сбоях: webhook (с HMAC-подписью тела) и/или письмо через отдельный исходящий SMTP-relay — при сбое синхронизации/retention, росте очереди S3, нехватке места на диске.
  • Аудит-лог: разблокировки, CRUD правил, восстановление, удаление писем — с IP и временем, просмотр в Settings.
  • Web UI: Dashboard, Accounts, Archive (поиск + просмотр письма + восстановление), Rules, Settings — тёмная/светлая тема, RU/EN-локализация, адаптивная вёрстка для мобильных экранов.
  • CLI: те же операции без браузера — add-account, sync, status, retention run, reindex, import, backup и т.д. (marchi --help, marchi --lang ru --help).
  • Master Key: единый пароль (Argon2id) шифрует Data Encryption Key, из которого выводятся отдельные подключи для IMAP-паролей, OAuth2-токенов и S3-объектов — смена пароля не требует перешифровывания уже сохранённых данных.
  • Метрики: /metrics в формате Prometheus (счётчики писем, синхронизаций, очереди S3, HTTP-latency) — опционально закрывается bearer-токеном (security.metrics_token в config.yaml или MARCHI_METRICS_TOKEN), если отдаётся за пределы доверенной сети.
  • /healthz: всегда 200, пока жив процесс, без гейта разблокировки — для Docker/Kubernetes healthcheck'ов, которым не нужно (и не должно) перезапускать контейнер только из-за того, что vault ещё заперт.

Быстрый старт (Docker)

Единственная поддерживаемая платформа — Linux (amd64/arm64), запуск через Docker или systemd.

git clone https://github.com/yurydemin/marchi.git
cd marchi
docker compose up

docker-compose.yml ссылается на готовый образ ghcr.io/yurydemin/marchi:latest — Docker сам скачает его при первом запуске, собирать из исходников не нужно (хотя git clone всё равно удобен ради самого docker-compose.yml). Без compose — тот же образ можно запустить и напрямую:

docker pull ghcr.io/yurydemin/marchi:latest   # или конкретная версия, например :0.10.0
docker run -p 8443:8080 -v marchi-data:/data ghcr.io/yurydemin/marchi:latest

Откройте https://localhost:8443 (самоподписанный TLS-сертификат — браузер спросит подтверждение). При первом запуске сервис попросит задать пароль Master Key (минимум 12 символов) — это единственный секрет, который нужно запомнить.

Данные (SQLite, Maildir, поисковый индекс, TLS-сертификат) живут в именованном Docker volume marchi-data, переживают docker compose down && up.

Хотите потестировать S3-репликацию локально (MinIO, без реального облачного аккаунта)?

docker compose --profile s3 up

MinIO-консоль будет на http://localhost:9001 (логин/пароль — marchiadmin/marchisecret, см. docker-compose.yml; смените перед любым использованием за пределами локального теста).

Автоматическая разблокировка при рестарте контейнера

Без этого сервис после каждого docker compose restart требует зайти в браузер и разблокировать вручную. Чтобы разблокировался сам:

cp .env.example .env
# впишите MARCHI_MASTER_KEY=ваш-пароль в .env
docker compose up

.env в .gitignore — реальный пароль туда, в репозиторий не попадёт.

Быстрый старт (systemd)

Полная пошаговая инструкция — build/systemd/README.md. Коротко:

go build -o marchi ./cmd/marchi
sudo install -o root -g root -m 0755 marchi /usr/local/bin/marchi
sudo useradd --system --home-dir /var/lib/marchi --shell /usr/sbin/nologin marchi
sudo mkdir -p /var/lib/marchi /etc/marchi
sudo chown marchi:marchi /var/lib/marchi
sudo install -o root -g marchi -m 0640 build/systemd/config.yaml.example /etc/marchi/config.yaml
sudo install -o root -g root -m 0644 build/systemd/marchi.service /etc/systemd/system/marchi.service
sudo systemctl daemon-reload
sudo systemctl enable --now marchi

Готовые бинарники под linux/amd64 и linux/arm64 — на странице Releases.

Первый запуск (zero-config)

Без единой правки конфига сервис поднимается на https://127.0.0.1:8080 с самоподписанным TLS, всеми данными под ./data (или app.data_dir из конфига) и в заблокированном состоянии — синхронизация не начнётся, пока не задан Master Key.

При первом открытии Web UI (или первой CLI-команде, требующей ключ) — форма задаёт новый пароль. При каждом следующем запуске — тот же пароль его разблокирует. Процесс, запущенный без MARCHI_MASTER_KEY в окружении, стартует заблокированным и ждёт ручной разблокировки через браузер.

Конфигурация

config.yaml (путь передаётся флагом --config, по умолчанию ./config.yaml) — все поля опциональны, значения по умолчанию покрывают zero-config запуск. Переменные окружения имеют приоритет над файлом. Самое важное:

Ключ По умолчанию Назначение
app.data_dir ./data Корень для БД, Maildir, индекса, TLS-сертификата, логов
http.host / http.port 127.0.0.1 / 8080 Адрес Web UI. В Docker нужно 0.0.0.0, иначе порт не будет доступен снаружи контейнера
http.tls.enabled / auto_cert true / true Самоподписанный TLS, генерируется в {data_dir}/tls
http.trusted_proxies не задано IP/подсети reverse-proxy, чьему X-Forwarded-For можно доверять — см. Работа за reverse-proxy
security.master_key_env MARCHI_MASTER_KEY Имя переменной окружения для unattended-разблокировки
app.log_output both Куда пишутся логи: file (только {data_dir}/logs), stdout (только консоль — физически stderr, чтобы не засорять stdout вывод команд вроде config show; виден в docker logs/journalctl -u marchi), both
sync.default_schedule 0 */6 * * * Cron-расписание автосинхронизации по умолчанию (переопределяется на уровне аккаунта)
storage.cache.max_size_gb 10 Лимит byte-budget LRU-кэша для ленивой загрузки писем из S3

marchi config show печатает итоговую конфигурацию (дефолты + файл + окружение) — удобно проверить, что реально применилось.

Резервное копирование и восстановление

Всё состояние — в app.data_dir:

data/
  marchi.db          # SQLite: аккаунты, правила, метаданные писем, логи
  marchi.db-wal       # WAL-журнал (может присутствовать)
  .salt / .mk-verify / .dek  # производные Master Key — без них данные не расшифровать
  maildir/            # оригинальные .eml по аккаунтам/папкам
  index/              # поисковый индекс Bluge (перестраивается через `marchi reindex`)
  tls/                # самоподписанный сертификат
  logs/               # ротируемые логи приложения

Бэкап без остановки сервиса (рекомендуемый способ): marchi backup run <dest-dir> пишет консистентный снапшот работающего архива — SQLite через собственный Online Backup API (не копия файла: WAL гарантирует, что чтение для бэкапа не блокирует и не блокируется записью), плюс maildir/ (в виде maildir.tar.gz) и .salt/.mk-verify/.dek. Ничего не расшифровывается по пути — сохранённые пароли/токены остаются зашифрованными той же самой обёрткой, что и в оригинале. <dest-dir> должен быть новым/пустым — команда не перезаписывает существующий бэкап молча. Пароль Master Key для этого не нужен.

marchi backup verify <dest-dir> сверяет SHA-256 каждого файла (записаны в manifest.json при создании) и прогоняет PRAGMA integrity_check на скопированной базе — стоит выполнять сразу после backup run, а не только в момент реального восстановления.

Восстановление: остановленный сервис, пустой (или новый) data_dir, туда распаковывается бэкап целиком (maildir.tar.gz — обратно в maildir/, marchi.db и .salt/.mk-verify/.dek — как есть), сервис запускается — Master Key тот же, что был на момент бэкапа. Если поисковый индекс не скопирован или подозревается в рассинхроне — marchi reindex пересоберёт его из maildir/ и marchi.db без обращения к сети.

Ручной способ (без CLI-команды, но так же надёжно): остановите сервис (systemctl stop marchi / docker compose down) и скопируйте весь data_dir целиком — .salt/.mk-verify/.dek обязательны, без них расшифровать marchi.db и maildir невозможно даже зная пароль. В отличие от marchi backup run, копирование файлов на живую здесь не поддерживается: SQLite WAL и запись .eml-файлов не атомарны относительно простой файловой копии.

Дополнительная защита от потери исходных писем (не то же самое, что резервная копия самого Marchi): пока включена S3-репликация, копия каждого письма уже лежит в S3 независимо от локального data_dir.

Технологии

Go 1.25, Fiber (HTTP), modernc.org/sqlite (чистый Go, без CGO), Bluge (поиск), emersion/go-imap + emersion/go-message (IMAP/MIME), aws-sdk-go-v2 (S3), wneessen/go-mail (SMTP-фолбэк восстановления), HTMX + Tailwind CSS (Web UI, без Node в рантайме), go-i18n (RU/EN), Cobra (CLI), Prometheus client (метрики).

Документация

Лицензия

MIT. Лицензии зависимостей — THIRD_PARTY_LICENSES.md.

Directories

Path Synopsis
cmd
marchi command
Command marchi is the single-binary entry point for the Marchi email archiving service.
Command marchi is the single-binary entry point for the Marchi email archiving service.
internal
account
Package account is the Account Manager (FR-AM-01..06): the business-logic layer between the CLI/HTTP handlers and repo.AccountsRepo.
Package account is the Account Manager (FR-AM-01..06): the business-logic layer between the CLI/HTTP handlers and repo.AccountsRepo.
backup
Package backup produces a consistent, hot (no-downtime) snapshot of everything needed to restore a Marchi archive elsewhere: the SQLite database (via SQLite's Online Backup API, not a raw file copy — the database is live and under WAL, so copying the file directly could catch it mid-write), the Maildir tree, and the Master Key's wrapped key material (.salt/.mk-verify/.dek).
Package backup produces a consistent, hot (no-downtime) snapshot of everything needed to restore a Marchi archive elsewhere: the SQLite database (via SQLite's Online Backup API, not a raw file copy — the database is live and under WAL, so copying the file directly could catch it mid-write), the Maildir tree, and the Master Key's wrapped key material (.salt/.mk-verify/.dek).
config
Package config loads Marchi's configuration from config.yaml, layering environment variable overrides on top per NFR-DP-03 (env wins over YAML).
Package config loads Marchi's configuration from config.yaml, layering environment variable overrides on top per NFR-DP-03 (env wins over YAML).
db
Package db opens the SQLite database (FR-ST-02: WAL mode, the only database Marchi uses) and applies embedded schema migrations.
Package db opens the SQLite database (FR-ST-02: WAL mode, the only database Marchi uses) and applies embedded schema migrations.
db/migrations
Package migrations embeds the SQLite schema migrations into the binary (FR-DP-01: single binary, no external files needed at runtime).
Package migrations embeds the SQLite schema migrations into the binary (FR-DP-01: single binary, no external files needed at runtime).
db/repo
Package repo holds per-table data access: reads go straight against the pooled *sql.DB (WAL allows concurrent readers), writes go through writer.Writer so every mutation is serialized through the Single Writer Pattern (FR-ST-02).
Package repo holds per-table data access: reads go straight against the pooled *sql.DB (WAL allows concurrent readers), writes go through writer.Writer so every mutation is serialized through the Single Writer Pattern (FR-ST-02).
db/writer
Package writer implements the Single Writer Pattern (FR-ST-02): every INSERT/UPDATE/DELETE against SQLite goes through one goroutine and one channel, so concurrent Sync Engine/S3 uploader/Rule Engine components never contend on WAL writer locks or deadlock against each other.
Package writer implements the Single Writer Pattern (FR-ST-02): every INSERT/UPDATE/DELETE against SQLite goes through one goroutine and one channel, so concurrent Sync Engine/S3 uploader/Rule Engine components never contend on WAL writer locks or deadlock against each other.
domain
Package domain holds plain data structs shared across packages (Account, and more as later steps add Folder/Email/Attachment/Rule/...).
Package domain holds plain data structs shared across packages (Account, and more as later steps add Folder/Email/Attachment/Rule/...).
gmailapi
Package gmailapi is a hand-rolled client for the handful of Gmail REST API v1 endpoints the Gmail connector needs (internal/sync's SyncAccountGmailAPI): listing/fetching messages, delta sync via the History API, and label/trash mutations for rule actions.
Package gmailapi is a hand-rolled client for the handful of Gmail REST API v1 endpoints the Gmail connector needs (internal/sync's SyncAccountGmailAPI): listing/fetching messages, delta sync via the History API, and label/trash mutations for rule actions.
httpapi
Package httpapi is Marchi's HTTP server (FR-WU-*, FR-API-*): the long-running Fiber process that, unlike Phase 1's one-shot CLI commands, stays up across many requests and starts in a locked state until the Master Key is supplied (see the unlock-gate added in a later step).
Package httpapi is Marchi's HTTP server (FR-WU-*, FR-API-*): the long-running Fiber process that, unlike Phase 1's one-shot CLI commands, stays up across many requests and starts in a locked state until the Master Key is supplied (see the unlock-gate added in a later step).
i18n
Package i18n resolves Marchi's UI language (ru/en, FR-WU-*) and looks up translated strings for both the Web UI (per-request) and the CLI (once, at process startup).
Package i18n resolves Marchi's UI language (ru/en, FR-WU-*) and looks up translated strings for both the Web UI (per-request) and the CLI (once, at process startup).
imapclient
Package imapclient wraps emersion/go-imap's client for Marchi's Account Manager and Sync Engine: connecting with a chosen TLS mode, logging in, and classifying failures into stages.
Package imapclient wraps emersion/go-imap's client for Marchi's Account Manager and Sync Engine: connecting with a chosen TLS mode, logging in, and classifying failures into stages.
importer
Package importer reads already-exported mail out of three common offline formats — mbox, Maildir, and a directory of loose .eml files — and hands each message's raw RFC 5322 bytes to a callback.
Package importer reads already-exported mail out of three common offline formats — mbox, Maildir, and a directory of loose .eml files — and hands each message's raw RFC 5322 bytes to a callback.
logging
Package logging wires uber-go/zap to a daily-rotating file sink per NFR-RL-04: {data_dir}/logs/marchi-{YYYY-MM-DD}.log, 30-day retention, 100MB max file size — and, by default, a second console sink alongside it (see Options.Output's doc comment for why both are on by default, and why that sink is stderr despite being called "stdout").
Package logging wires uber-go/zap to a daily-rotating file sink per NFR-RL-04: {data_dir}/logs/marchi-{YYYY-MM-DD}.log, 30-day retention, 100MB max file size — and, by default, a second console sink alongside it (see Options.Output's doc comment for why both are on by default, and why that sink is stderr despite being called "stdout").
maildir
Package maildir writes archived emails to disk in Maildir format (FR-ST-01): {data_dir}/accounts/{account_id}/mail/{folder_safe_name}/{cur,new,tmp}/, one file per message, filenames per the Maildir spec.
Package maildir writes archived emails to disk in Maildir format (FR-ST-01): {data_dir}/accounts/{account_id}/mail/{folder_safe_name}/{cur,new,tmp}/, one file per message, filenames per the Maildir spec.
mimeparse
Package mimeparse extracts archival metadata — Message-ID, Subject, From, To, Cc, Date — from a raw RFC 5322 message, via emersion/go-message.
Package mimeparse extracts archival metadata — Message-ID, Subject, From, To, Cc, Date — from a raw RFC 5322 message, via emersion/go-message.
msgraph
Package msgraph is a hand-rolled client for the handful of Microsoft Graph REST API v1.0 endpoints the MS Graph connector needs (internal/sync's SyncAccountMSGraph): listing mail folders, delta-syncing messages within a folder, fetching raw MIME content, and marking read/deleting for rule actions.
Package msgraph is a hand-rolled client for the handful of Microsoft Graph REST API v1.0 endpoints the MS Graph connector needs (internal/sync's SyncAccountMSGraph): listing mail folders, delta-syncing messages within a folder, fetching raw MIME content, and marking read/deleting for rule actions.
notify
Package notify sends failure notifications through independent channels (webhook, email) so a background sync/retention failure, an S3 upload backlog, or low disk space doesn't sit silently until someone happens to open the Web UI.
Package notify sends failure notifications through independent channels (webhook, email) so a background sync/retention failure, an S3 upload backlog, or low disk space doesn't sit silently until someone happens to open the Web UI.
notifyconfig
Package notifyconfig is the Notification Settings Manager (Phase 5 P0-2): the business-logic layer between the HTTP API and repo.NotificationSettingsRepo, mirroring internal/s3config's role for S3 credentials.
Package notifyconfig is the Notification Settings Manager (Phase 5 P0-2): the business-logic layer between the HTTP API and repo.NotificationSettingsRepo, mirroring internal/s3config's role for S3 credentials.
oauth2
Package oauth2 implements FR-AM-01's OAuth2 accounts (Google and Microsoft): the BYO-app authorization-code exchange, refresh, and the SASL XOAUTH2 initial-response encoding IMAP and SMTP both use to authenticate with a bearer token instead of a plain password.
Package oauth2 implements FR-AM-01's OAuth2 accounts (Google and Microsoft): the BYO-app authorization-code exchange, refresh, and the SASL XOAUTH2 initial-response encoding IMAP and SMTP both use to authenticate with a bearer token instead of a plain password.
oauth2config
Package oauth2config is the OAuth2 BYO App Settings Manager (поправка #4, Phase 3 step 13): the business-logic layer between the HTTP API and repo.OAuth2AppsRepo, mirroring internal/s3config's role for S3 connection settings and internal/account's for IMAP credentials.
Package oauth2config is the OAuth2 BYO App Settings Manager (поправка #4, Phase 3 step 13): the business-logic layer between the HTTP API and repo.OAuth2AppsRepo, mirroring internal/s3config's role for S3 connection settings and internal/account's for IMAP credentials.
reindex
Package reindex implements FR-SR-04: wiping and rebuilding the search index from the local .eml archive — the recovery path whenever the index falls out of sync with the archive (best-effort indexing failures during sync, per internal/sync's archiveOne, or restoring from a backup that didn't include the index, since FR-SR-01 never replicates it).
Package reindex implements FR-SR-04: wiping and rebuilding the search index from the local .eml archive — the recovery path whenever the index falls out of sync with the archive (best-effort indexing failures during sync, per internal/sync's archiveOne, or restoring from a backup that didn't include the index, since FR-SR-01 never replicates it).
restore
Package restore implements the Restore Engine (FR-RS-01..05): copying an archived email back into a live IMAP mailbox.
Package restore implements the Restore Engine (FR-RS-01..05): copying an archived email back into a live IMAP mailbox.
retention
Package retention implements FR-RE-04's cron-driven archive lifecycle: a three-stage model per email —
Package retention implements FR-RE-04's cron-driven archive lifecycle: a three-stage model per email —
rules
Package rules evaluates archive rules (FR-RE-01..03) against a message fetched but not yet archived.
Package rules evaluates archive rules (FR-RE-01..03) against a message fetched but not yet archived.
s3config
Package s3config is the S3 Settings Manager (FR-S3-02, Phase 3 step 9): the business-logic layer between the HTTP API and repo.S3ConfigRepo, mirroring internal/account's role for IMAP credentials.
Package s3config is the S3 Settings Manager (FR-S3-02, Phase 3 step 9): the business-logic layer between the HTTP API and repo.S3ConfigRepo, mirroring internal/account's role for IMAP credentials.
s3store
Package s3store implements the S3 mirror/disaster-recovery layer (FR-S3-01 through FR-S3-09): a client wrapping aws-sdk-go-v2 for MinIO-compatible endpoints, the FR-S3-04 object key layout, and (in later Phase 3 steps) client-side encryption and an upload queue worker pool.
Package s3store implements the S3 mirror/disaster-recovery layer (FR-S3-01 through FR-S3-09): a client wrapping aws-sdk-go-v2 for MinIO-compatible endpoints, the FR-S3-04 object key layout, and (in later Phase 3 steps) client-side encryption and an upload queue worker pool.
scheduler
Package scheduler implements FR-SE-06: background sync on a per-account cron schedule, with bounded concurrency across accounts.
Package scheduler implements FR-SE-06: background sync on a per-account cron schedule, with bounded concurrency across accounts.
search
Package search wraps Bluge, Marchi's full-text search engine (FR-SR-01..04).
Package search wraps Bluge, Marchi's full-text search engine (FR-SR-01..04).
security/crypto
Package crypto provides the AES-256-GCM encryption and HKDF subkey derivation primitives used throughout Marchi: encrypting IMAP passwords/OAuth2 tokens/S3 credentials before they touch SQLite, and client-side encrypting .eml files before they're uploaded to S3.
Package crypto provides the AES-256-GCM encryption and HKDF subkey derivation primitives used throughout Marchi: encrypting IMAP passwords/OAuth2 tokens/S3 credentials before they touch SQLite, and client-side encrypting .eml files before they're uploaded to S3.
security/masterkey
Package masterkey implements FR-ST-04 / NFR-SC-01: deriving the Master Key from a user password via Argon2id, and verifying a password against a previously-bootstrapped vault without ever persisting the key itself.
Package masterkey implements FR-ST-04 / NFR-SC-01: deriving the Master Key from a user password via Argon2id, and verifying a password against a previously-bootstrapped vault without ever persisting the key itself.
sync
Package sync is the Sync Engine: orchestrating IMAP folder/UID bookkeeping (this step) and, from a later step, incremental message fetch and archiving.
Package sync is the Sync Engine: orchestrating IMAP folder/UID bookkeeping (this step) and, from a later step, incremental message fetch and archiving.
testutil/dovecot
Package dovecot is a reusable test harness that runs a real dovecot/dovecot:latest container for integration tests that need an actual IMAP server rather than the in-process fake servers internal/imapclient and internal/sync's own unit tests use for deterministic, Docker-free coverage of protocol edge cases.
Package dovecot is a reusable test harness that runs a real dovecot/dovecot:latest container for integration tests that need an actual IMAP server rather than the in-process fake servers internal/imapclient and internal/sync's own unit tests use for deterministic, Docker-free coverage of protocol edge cases.
testutil/minio
Package minio is a reusable test harness that runs a real minio/minio container for integration tests that need an actual S3-compatible server, mirroring internal/testutil/dovecot's pattern for IMAP.
Package minio is a reusable test harness that runs a real minio/minio container for integration tests that need an actual S3-compatible server, mirroring internal/testutil/dovecot's pattern for IMAP.
version
Package version holds build metadata injected via -ldflags at release build time.
Package version holds build metadata injected via -ldflags at release build time.
webui
Package webui parses Marchi's embedded html/template sources and exposes its embedded static assets (Tailwind CSS, self-hosted HTMX).
Package webui parses Marchi's embedded html/template sources and exposes its embedded static assets (Tailwind CSS, self-hosted HTMX).
Package web embeds Marchi's html/template sources, Tailwind-built CSS, and self-hosted HTMX so the server ships as a single binary with no runtime dependency on Node.js, a CDN, or a filesystem checkout (NFR-DP-02).
Package web embeds Marchi's html/template sources, Tailwind-built CSS, and self-hosted HTMX so the server ships as a single binary with no runtime dependency on Node.js, a CDN, or a filesystem checkout (NFR-DP-02).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL