API-контракты: полное покрытие OpenAPI + coverage-тест, MCP err.body/дрейф/новые инструменты#86
Merged
Conversation
The manifest documented ~35 operations of ~90 mounted — entire resources (sync, quarantine, users, feature-flags, backups, settings, me/*) and nearly all item-level CRUD were missing, so a client generated from /openapi.json got half the API. Backfilled every mounted admin route (request bodies wired from the real zod validators where they exist). Adds tests/integration/openapi-coverage — introspects the mounted Express router and asserts every route is either in the spec or a reviewed allow-list (autoconfig, OIDC redirects, /metrics), plus the inverse (no spec path that isn't mounted). The manifest can no longer silently drift: a new router.get(...) fails CI until it's documented. Also fixes the version served in Docker: `node dist/index.js` left npm_package_version unset so /openapi.json advertised 0.1.0 — a new appVersion() helper falls back to reading package.json. Closes #78
…ools
- fail() now appends the MailApiError body, so a backend 400's
{error, issues:[{path,message}]} reaches the model — it can self-correct
instead of seeing a bare "Validation error".
- ok() emits compact JSON (was pretty-printed), so large lists like
list_quarantine across every mailbox don't flood the context window.
- Schema drift fixes: webhook `events` is now the real enum (incl. send.bounced)
on create+update instead of z.array(z.string()); update_smtp_account gains the
active/domainId/userEnvVar/passwordEnvVar fields it was missing (so it can
deactivate an account, not only delete it); dns_check gains ?refresh.
- New tools (69 → 82): generate_temp_alias, update_alias, regenerate_access_rules,
update_fetchmail (pause), delete_migration, bulk_quarantine,
get_quarantine_message, set_user_password, reset_feature_flag, and the
get_webhook / get_smtp_account / get_settings item reads.
Refs #79
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Четвёртый заход — API-контракты. Два коммита.
#78 — OpenAPI: полное покрытие + защита от дрейфа
Манифест документировал ~35 операций из ~90 смонтированных — целые ресурсы (
sync,quarantine,users,feature-flags,backups,settings,me/*) и почти все item-level CRUD отсутствовали, так что клиент, сгенерированный из/openapi.json, получал половину API. Добил каждый смонтированный admin-роут (request-body подтянуты из реальных zod-валидаторов, где они есть).Добавлен
tests/integration/openapi-coverage: интроспектит смонтированный Express-роутер и проверяет, что каждый роут либо в спеке, либо в отревьюенном allow-list (autoconfig, OIDC-редиректы,/metrics); плюс обратная проверка (нет пути в спеке, которого нет в роутере). Манифест больше не может молча разойтись — новыйrouter.get(...)роняет CI, пока не задокументирован.Заодно фикс версии в Docker:
node dist/index.jsне выставляетnpm_package_version, поэтому/openapi.jsonотдавал0.1.0— новый хелперappVersion()читаетpackage.jsonкак fallback.#79 — MCP: детали ошибок, дрейф схем, недостающие инструменты
fail()теперь дописываетerr.body— бэкендовый 400 с{error, issues:[{path,message}]}доходит до модели, и она может само-скорректироваться вместо голого «Validation error».ok()отдаёт compact-JSON (был pretty-print) — большие списки вродеlist_quarantineпо всем ящикам не топят контекст.events— теперь реальный enum (вкл.send.bounced) на create+update вместоz.array(z.string());update_smtp_accountполучил недостающиеactive/domainId/userEnvVar/passwordEnvVar(теперь умеет деактивировать аккаунт, а не только удалять);dns_checkполучил?refresh.generate_temp_alias,update_alias,regenerate_access_rules,update_fetchmail(пауза),delete_migration,bulk_quarantine,get_quarantine_message,set_user_password,reset_feature_flag, а также item-readsget_webhook/get_smtp_account/get_settings.Проверки
Backend:
typecheck·lint·format:check· 562 теста ✓ (+2 coverage). MCP:typecheck·build✓; счётчик инструментов в README и коде совпадает (82).Closes #78
Closes #79
🤖 Generated with Claude Code