Team serverКомандный сервер
One binary and one Postgres. The server is the place where replicas meet: everyone keeps a local workspace, work happens at local speed, and myc sync is the deliberate step that exchanges what changed.
Один бинарь и один Postgres. Сервер — то место, где встречаются реплики: у каждого локальный воркспейс, работа идёт на местной скорости, а myc sync — тот осознанный шаг, который обменивает изменения.
The client always initiates. The network never sits in the hot path of a command: prime, ready and show read the local database and never wait for an exchange.
Инициатор всегда клиент. Сеть не входит в горячий путь ни одной команды: prime, ready и show читают локальную базу и никогда не ждут обмена.
What the server is — and what it is not
Что такое сервер — и чего он не делает
Three properties decide everything else on this page.
Три свойства, из которых следует всё остальное на этой странице.
A meeting point, not a cloud
Место встречи, а не облако
Every machine keeps its own database; the server's copy is another site, not the source of truth for your laptop. Losing the server costs a server, not the knowledge — for every workspace that was actually synced.
У каждой машины своя база; копия на сервере — такой же сайт, а не истина для вашего ноутбука. Потерянный сервер стоит сервера, а не знания — для каждого воркспейса, который действительно синхронизировали.
The client initiates — always
Инициатор — всегда клиент
Exchange is pull-push over HTTP with the client driving every round (design §9.5). No daemon, no open ports on your machine, no connection held open; an interrupted exchange resumes by running it again — it is idempotent by operation id.
Обмен — pull-push по HTTP, каждую петлю ведёт клиент (дизайн §9.5). Ни демона, ни открытых портов на вашей машине, ни висящего соединения; оборванный обмен продолжается повторным запуском — он идемпотентен по id операции.
Tenants are isolated by the database
Арендаторов изолирует сама база
Rows of different tenants are separated by PostgreSQL row-level security, not by application checks. Tokens are issued per tenant; only sha256 hashes are stored — a copy of the database gives no access.
Строки разных арендаторов разведены политиками RLS самого PostgreSQL, а не проверками приложения. Токены выпускаются под арендатором, хранятся только их sha256 — копия базы не даёт доступа.
Run the server
Запуск сервера
What you need: a host with Docker and a domain name pointing at it; PostgreSQL 17 with pgvector ≥ 0.7 (the schema needs halfvec and HNSW — the sample compose raises it for you); a reverse proxy for TLS, because the server speaks plain HTTP on purpose and holds no certificate.
Что нужно: хост с Docker и доменное имя, указывающее на него; PostgreSQL 17 с pgvector ≥ 0.7 (схеме нужны halfvec и HNSW — образец compose поднимет его сам); обратный прокси для TLS, потому что сервер намеренно говорит по обычному HTTP и сертификат не держит.
1. Clone and adjust the sample
1. Клонируем и правим образец
git clone https://github.com/aistastudio/myc && cd myc
cp deploy/compose.yml deploy/compose.prod.yml
git clone https://github.com/aistastudio/myc && cd myc
cp deploy/compose.yml deploy/compose.prod.yml
Three things in deploy/compose.prod.yml must change before the first start — this is what separates the sample from an installation:
Три вещи в deploy/compose.prod.yml меняются до первого старта — именно они отличают образец от установки:
- The password — in three places:
POSTGRES_PASSWORD, insideMYC_PG_URL, and indeploy/initdb/10-app-role.sql. Take it from the orchestrator's secret, not from a file. - The published port — keep it on
127.0.0.1so only the proxy can reach it. MYC_BOOTSTRAP_TENANTandMYC_BOOTSTRAP_TOKEN— leave them for the first start and remove both lines after. They exist so thatup -dhands you a server you can log into; the first secret is printed to the container log, which is not where it should live permanently.
- Пароль — в трёх местах:
POSTGRES_PASSWORD, пароль внутриMYC_PG_URLиdeploy/initdb/10-app-role.sql. Берите его из секрета оркестратора, а не из файла. - Опубликованный порт — оставьте на
127.0.0.1, чтобы до него доставал только прокси. MYC_BOOTSTRAP_TENANTиMYC_BOOTSTRAP_TOKEN— оставьте на первый старт и уберите обе строки после. Они существуют, чтобыup -dдавал сервер, в который можно войти; первый секрет они печатают в журнал контейнера, а это не то место, где ему жить постоянно.
2. First start
2. Первый старт
docker compose -f deploy/compose.prod.yml up -d
docker compose -f deploy/compose.prod.yml logs server | grep -A2 'bootstrap token'
On an empty volume Postgres applies the schema itself: first the login role (10-app-role.sql), then db/schema.postgres.sql — tables, triggers and RLS policies. The application role is deliberately not allowed to do that, so the superuser applies it and the server afterwards lives as myc_app. Write down the secret from the log: it is shown once, only its sha256 is stored.
На пустом томе Postgres накатывает схему сам: сперва роль со входом (10-app-role.sql), затем db/schema.postgres.sql — таблицы, триггеры и политики RLS. Права накатывать её у прикладной роли намеренно нет, поэтому её накатывает суперпользователь, а сервер дальше живёт ролью myc_app. Секрет из журнала запишите: он показывается один раз, в базе хранится только его sha256.
TLS in front, and two probes
TLS спереди и две пробы
Whether the session cookie gets the Secure flag is decided by X-Forwarded-Proto, so the proxy must set it. Caddy does it in two lines; nginx — by hand.
Признак Secure у куки сессии ставится по X-Forwarded-Proto, поэтому прокси обязан его ставить. Caddy делает это в две строки, nginx — руками.
Caddy
myc.example.com {
reverse_proxy 127.0.0.1:8080
}
nginx
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
}
Probe 1 — liveness
Проба 1 — живость
curl https://myc.example.com/v1/health
Is the process up. It deliberately never touches the database, so someone else's Postgres outage does not get your container restarted. Needs no token.
Процесс поднят. Базу он намеренно не трогает, поэтому чужой простой Postgres не приводит к перезапуску вашего контейнера. Токена не требует.
Probe 2 — readiness
Проба 2 — готовность
curl -s -o /dev/null -w '%{http_code}\n' https://myc.example.com/v1/readyz
200 while the database answers, 503 db.unavailable while it does not. This is what the orchestrator's traffic decision should hang on. Needs no token either; everything else answers 401 until a token arrives.
200, пока база отвечает, 503 db.unavailable, пока нет. Именно на неё вешайте решение оркестратора о трафике. Токена тоже не требует; всё остальное отвечает 401, пока токена нет.
Tenants and tokens
Арендаторы и токены
A tenant is an organization; tokens are issued under it, and rows of different tenants are isolated by RLS. Most teams need exactly one. One token per person and per agent — never a shared one: then revoking costs one row and nobody else's access.
Арендатор — это организация; токены выпускаются под ним, строки разных арендаторов изолированы RLS. Большинству команд нужен ровно один. По токену на человека и на агента — общий не заводите: тогда отзыв стоит одной строки и никому больше не стоит доступа.
alias myc-srv='docker compose -f deploy/compose.prod.yml exec -T server myc serve'
myc-srv --add-tenant acme:Acme
myc-srv --add-token acme:anna --role owner
myc-srv --add-token acme:boris --role member
myc-srv --add-token acme:reviewer-bot --role agent
myc-srv --tokens # who holds what and when each was last used
myc-srv --revoke-token tok_…
Roles and rights. Roles: owner, maintainer, member, agent, viewer; rights: read, write, claim, sync, admin. A role is a default set of rights; --scopes read,sync narrows it explicitly. --token-ws binds a token to a single workspace.
Роли и права. Роли: owner, maintainer, member, agent, viewer; права: read, write, claim, sync, admin. Роль — набор прав по умолчанию, а --scopes read,sync сужает его явно. --token-ws привязывает токен к одному воркспейсу.
Why sync is not given out lightly. The exchange carries the oplog, which the visibility predicate does not filter: a replica is complete by construction, otherwise it does not converge. So the right to take a replica is the right to see everything in the workspace, including other people's private notes. Give sync to those who already have that access — everyone else reads through the API under ACL with member.
Почему sync не раздаётся просто так. Обмен везёт оплог, который предикат видимости не фильтрует: реплика полна по построению, иначе она не сходится. Значит право забрать реплику — это право видеть в воркспейсе всё, включая чужие приватные заметки. Давайте sync тем, у кого такой доступ и так есть, остальным — member, который читает через API под ACL.
The admin page is https://myc.example.com/v1/admin: it asks the browser for a token in a form and keeps it in an HttpOnly cookie with SameSite=Strict. It requires the admin right.
Админка — https://myc.example.com/v1/admin: спрашивает у браузера токен формой и держит его в HttpOnly-куке с SameSite=Strict. Нужно право admin.
A machine joins
Подключение машины
The workspace name on the server and the slug on the machine must match: the slug is part of every node's id, so exchanging workspace cherry with workspace web would move nodes where neither side expects them. myc sync refuses that instead of merging it.
Имя воркспейса на сервере и слаг на машине обязаны совпасть: слаг входит в id каждого узла, поэтому обмен воркспейса cherry с воркспейсом web переселил бы узлы туда, где их не ждёт ни одна из сторон. myc sync такое отвергает, а не сливает.
myc init --slug acme # or: the slug is already in .myc/workspace.toml
export MYC_SERVER=https://myc.example.com # workspace comes from the local slug
export MYC_TOKEN=myc_… # never on the command line
myc sync
myc init --slug acme # или: слаг уже лежит в .myc/workspace.toml
export MYC_SERVER=https://myc.example.com # воркспейс — из слага .myc/workspace.toml
export MYC_TOKEN=myc_… # не в командной строке
myc sync
The workspace by default is the slug from .myc/workspace.toml — the same file that builds node ids, so the requirement matches by construction. Explicit ways (--ws, MYC_WS, a path in the address) stay for looking into a foreign workspace from your own directory.
Воркспейс по умолчанию — слаг из .myc/workspace.toml: тот же файл, что строит id узлов, поэтому требование «слаг совпадает с воркспейсом сервера» соблюдается само. Явные способы (--ws, MYC_WS, путь в адресе) остаются — ими заходят в чужой воркспейс из своего каталога.
The name you sign with
Имя, которым вы подписываете работу
It must match the person the token was issued to. myc init takes it from git — the same signature that goes into your commits — writes it into the workspace and prints it. Issue the token for exactly that name (--add-token acme:"Anna Ivanova"), or set MYC_ACTOR to what the token says. A private node belongs to its author by name: on mismatch the note still reaches you locally, but on the server it belongs to a name nobody holds a token for — visible to no one. Nothing leaks, but nothing is found either.
Имя обязано совпасть с тем, на кого выпущен токен. myc init берёт его из git — той же подписи, что в ваших коммитах, — записывает в воркспейс и печатает. Выпустите токен ровно на это имя (--add-token acme:"Анна Иванова") или задайте MYC_ACTOR тем, что написано в токене. Приватный узел принадлежит автору по имени: при расхождении заметка доезжает и локально, но на сервере принадлежит имени, на которое токена ни у кого нет, — и не видна никому. Ничего не утекает, но и не находится.
Why the token lives in the environment
Почему токен живёт в окружении
Arguments are visible in ps, in shell history and in hook logs. Put both exports into your shell profile or into a project .envrc that never gets committed. The local cycle stays the usual one — myc prime, myc ready --claim, myc recall, myc remember, myc close — all against the local database, at local speed; myc sync is when you choose to hand yours over and take others'.
Аргументы видны в ps, в истории оболочки и в журналах хуков. Положите оба экспорта в профиль оболочки или в .envrc проекта, который не коммитится. Локальный цикл остаётся обычным — myc prime, myc ready --claim, myc recall, myc remember, myc close — всё по локальной базе, на местной скорости; myc sync — когда вы решили отдать своё и забрать чужое.
Verifying: what myc sync tells you
Проверка: что говорит myc sync
The first call sends nothing: the client does not yet know the server's watermarks, and sending blindly would push a thousand operations the server already has at every launch. The answer carries the watermarks; the next round sends exactly what is missing. The status line then reports where the target and the token came from and when the background exchange is due:
Первый вызов ничего не шлёт: у клиента ещё нет вод сервера, и отправка «на всякий случай» гнала бы по сети тысячи операций, которые сервер и так знает, при каждом запуске. Ответ приносит воды — дальше отправляется ровно недостающее. Строка состояния называет, откуда взялись цель и токен и когда пора следующий обмен:
push 12 op · pull 3 op · 2 rounds · 84 ms
applied 3, duplicate 0, stale 0
mode auto · server config · token .myc/token · last sync 43s ago · background in 17s
Counts by direction, rounds spent, and what the pull did with each operation: applied, duplicate (already known), stale (lost the field clock), deferred (an operation arrived before its node — parked in oplog_pending, named so that "accepted 9, visible 7" never hides).
Числа по направлениям, потраченные круги и что пул сделал с каждой операцией: applied, duplicate (уже известна), stale (проиграла полевые часы), deferred (операция приехала раньше своего узла — лежит в oplog_pending, и это называется, чтобы «приняли 9, видно 7» не прятало проблему).
Agents join
Подключение агентов
Agents do not talk to the server — they talk to the local workspace, and the exchange stays a human-scale step. One command wires hooks, the MCP server and the skill for six agents:
Агенты не разговаривают с сервером — они разговаривают с локальным воркспейсом, а обмен остаётся шагом человеческого масштаба. Одна команда ставит хуки, MCP-сервер и скилл для шести агентов:
Everything at once
Всё сразу
myc wire --agents claude,codex,opencode,kimi,mcode,mimo
myc wire --dry-run # print every file and change, write nothing
myc wire --agents claude,codex,opencode,kimi,mcode,mimo
myc wire --dry-run # показать каждый файл и изменение, ничего не писать
Opt-ins: --status-line (myc's line under Claude Code's prompt), --queue-hook (heavy Bash commands through myc run), --agents-md (the myc block into AGENTS.md). --scope user wires the user layer instead of the project — for agents in git worktrees and nested repos where the project layer has no myc.
По желанию: --status-line (строка myc под приглашением Claude Code), --queue-hook (тяжёлые Bash-команды через myc run), --agents-md (блок myc в AGENTS.md). --scope user ставит пользовательский слой вместо проектного — для агентов в git worktree и вложенных репозиториях, где в проектном слое myc нет.
Or the MCP server by hand
Или MCP-сервер вручную
For a host that reads its own config, point it at myc mcp over stdio: the agent profile of tools, working rules and the bootstrap block delivered in initialize.instructions. The server resolves its workspace at start from -C, then CLAUDE_PROJECT_DIR, then the current directory — and outside a workspace it honestly serves zero tools rather than tools that answer "not initialized".
Для хоста, который читает свой конфиг, укажите myc mcp по stdio: профиль инструментов agent, правила работы и бутстрап-блок в initialize.instructions. Сервер определяет свой воркспейс при старте из -C, затем CLAUDE_PROJECT_DIR, затем текущего каталога — а вне воркспейса честно отдаёт ноль инструментов вместо инструментов, которые отвечают «не инициализировано».
myc mcp
One repository — one server (0.5)
Одна репозитория — один сервер (0.5)
Repositories of different companies must not mix. The address and the token are read from the repository, not from the profile — because the profile does not know which repository you are sitting in.
Репозитории разных компаний не должны смешиваться. Адрес и токен читаются из репозитории, а не из профиля — потому что профиль не знает, в чьей репозитории вы сидите.
Committed: the target
В коммит: цель
# .myc/workspace.toml
slug = "qmatic"
server = "https://myc.company-a.com/tenant"
sync = "auto"
server is the address of this repository's server (with the workspace path, if you keep it in the URL). sync = "auto" turns on the background exchange described below; the default is manual.
server — адрес сервера этой репозитории (с путём воркспейса, если держите его в URL). sync = "auto" включает фоновый обмен ниже; по умолчанию — manual.
Gitignored: the token
В gitignore: токен
.myc/token
One token per repository, in .myc/token; the file is listed in .myc/.gitignore — a token is a secret, not the workspace's identity, so it must not be committed. A clone arrives with the config and without the token: whoever has the server's access drops their own file in.
Один токен на репозиторию — в .myc/token; файл перечислен в .myc/.gitignore: токен — секрет, а не личность воркспейса, коммититься он не обязан. Клон приезжает с конфигом, но без токена: кто имеет доступ к серверу, кладёт свой файл.
Resolution order — the repository beats the profile
Порядок разрешения — репозитория обгоняет профиль
| Target (URL)Цель (URL) | TokenТокен | MeaningСмысл |
|---|---|---|
--server |
.myc/token |
The flag wins: a deliberate one-off look at a foreign server.Флаг сильнее всего: осмотр чужого сервера в этот раз. |
server in .myc/workspace.toml |
MYC_TOKEN |
Then the repository's config: committed, per-repository, shared with everyone who clones it.Дальше конфиг репозитории: коммитится, свой на каждую репу, общий для всех, кто её клонирует. |
MYC_SERVER |
— | The profile last: a fallback for repositories without a config.Профиль последним: запасной путь для реп без конфига. |
The config beating the profile is deliberate: the profile is global and does not know which repository you are in — in repositories of different companies that is not an inconvenience but protection against sending data to the wrong server. Two rules around it: the config never switches ordinary commands into remote mode (that still takes an explicit ask — flag or profile; otherwise server in a repository would put every list on the network), and a local command under an explicit --server refuses by name (precond.no_remote) instead of quietly substituting the local database.
Конфиг обгоняет профиль намеренно: профиль глобален и не знает, в чьей репозитории вы сидите, — в репозиториях разных компаний это неудобство, а защита от отправки данных не на тот сервер. Два правила вокруг: конфиг никогда не переводит обычные команды в удалённый режим (для этого всё равно нужен явный спрос — флаг или профиль, иначе server в репозитории гнал бы в сеть каждый list), а явный --server у локальной команды отвечает отказом по имени (precond.no_remote), а не подменяет локальную базу молча.
Background exchange when sync is on
Фоновый обмен, когда sync включён
With sync = "auto" the exchange happens on its own: every 60 seconds once due, and 2 seconds after a local close/claim — in the background, as a detached process, never inside a command's hot path. Failed background attempts are visible in the queue's last_error, and the last one is named by the status line of the next manual myc sync. The exchange remains client-initiated: the network sits between your database and the server only when you asked for it — explicitly, or by turning the mode on.
С sync = "auto" обмен случается сам: раз в 60 с, когда пора, и через 2 с после локального close/claim — фоном, отсоединённым процессом, никогда не в горячем пути команды. Упавшие фоновые попытки видны в last_error очереди, а последнюю называет строка состояния следующего явного myc sync. Обмен остаётся инициативой клиента: сеть стоит между вашей базой и сервером только когда вы об этом попросили — явно или включённым режимом.
| KnobПереключатель | What it doesЧто делает |
|---|---|
sync = "auto" | "manual" in .myc/workspace.toml | The mode itself; committed with the repository, so the whole team agrees once.Сам режим; коммитится с репозиторией — вся команда договаривается один раз. |
MYC_SYNC=auto | Turns the mode on for one machine without touching the config.Включает режим на одной машине, не трогая конфиг. |
MYC_SYNC_BG=0 | Disables the mechanism entirely — for tests and cautious machines.Гасит механизм целиком — для тестов и осторожных машин. |
myc sync --dry-run | Counts both directions without changing anything — what the automation would do.Считает оба направления, ничего не меняя — что сделал бы автомат. |
A repository without a server or a token does not fail in the background — the step names why it stood still («no server to exchange with», «no token») in the status line of myc sync, and with sync = "manual" nothing is scheduled at all.
Репозитория без сервера или токена не падает в фоне: шаг называет, почему он стоит («no server to exchange with», «no token»), в строке состояния myc sync, а при sync = "manual" не планируется ничего.
Backup and update
Резервное копирование и обновление
The Postgres volume is the server's only state: the binary has none, and the admin page and tokens live in the same database.
Том Postgres — единственное состояние сервера: бинарь его не имеет, а админка и токены лежат в той же базе.
Backup
Бэкап
docker compose -f deploy/compose.prod.yml exec -T db \
pg_dump -U postgres -Fc myc > myc-$(date +%F).dump
Every machine additionally holds a full replica of its workspace — but only for workspaces somebody actually synced. Make the copies anyway.
У каждой машины к тому же лежит полная реплика воркспейса — но только для тех воркспейсов, кто-то действительно синхронизировал. Копии всё равно делайте.
Update
Обновление
The image builds from the repository, so an update is a rebuild — and if the release moved the schema, bring the database up explicitly with --migrate as the superuser: RLS hides other tenants' rows from the application role, and under it a data migration would change nothing — silently — while still writing a new schema number. The command refuses that.
Образ собирается из репозитория, поэтому обновление — пересборка, а если релиз сдвинул схему — доведите базу явно через --migrate от суперпользователя: политики RLS прячат от прикладной роли чужие строки, и под ней миграция данных не изменила бы ничего — молча — но номер схемы записала бы. Команда такое отвергает.
git pull
docker compose -f deploy/compose.prod.yml build server
docker compose -f deploy/compose.prod.yml up -d server
curl -s https://myc.example.com/v1/health # "ver" must change
The server checks the binary's version against the schema at start and refuses a database that is behind — naming both numbers. A database it simply cannot reach is different and does not stop the start: a container may come up before its database, which is what /v1/readyz exists for. --apply-schema writes the schema into an empty database and refuses a populated one — applying DDL over live data is a migration, with its own order, checks and rollback.
Сервер при старте сверяет версию бинаря со схемой и на отставшей базе работать отказывается, называя оба номера. База, до которой он просто не достучался, — другое и старт не останавливает: контейнер вправе подняться раньше базы, на то и заведён /v1/readyz. --apply-schema пишет схему в пустую базу и отказывается от населённой: накат DDL поверх живых данных — это миграция, у неё свой порядок, свои проверки и свой откат.
What does not work yet
Чего пока нет
Only part of the CLI speaks to a server. Working remotely today: create/task/bug/epic/msg, update, claim, list, ready, show, prime and sync. Every other command is local: with a server in MYC_SERVER it still runs locally and names that in one WARN line («this run used the LOCAL database») — no quiet substitution — and init/remember/close keep working. An explicit --server for such a command is a refusal (precond.no_remote).
С сервером разговаривает лишь часть CLI. Удалённо сегодня работают create/task/bug/epic/msg, update, claim, list, ready, show, prime и sync. Остальные команды локальны: с сервером в MYC_SERVER они всё равно работают локально и называют это одной строкой WARN («this run used the LOCAL database») — молчаливой подмены нет, — а init/remember/close при этом остаются рабочими. Явный --server для такой команды — отказ (precond.no_remote).
So the working shape is: everyone keeps a local workspace and exchanges through the server. Pointing MYC_SERVER at the server and working «in» it is not the mode to plan around. Also not there yet: hybrid search on Postgres (the server's own recall has no lexical or vector branch), SSE deltas for the web interface, and a bulk SQLite→Postgres import of an existing workspace.
Поэтому работающая форма такая: у каждого локальный воркспейс, а обмен идёт через сервер. Указать MYC_SERVER и работать «в нём» — не тот режим, вокруг которого стоит строить процесс. Ещё нет: гибридного поиска на Postgres (у серверного recall нет ни лексической, ни векторной ветки), SSE-дельт для веб-интерфейса и массового ввоза существующего воркспейса из SQLite в Postgres.
When something refuses
Когда что-то отказывает
| What you see | What it means |
|---|---|
401 denied.no_token | No MYC_TOKEN, or the proxy strips the Authorization header. |
denied.scope: this token has no 'sync' scope | The token was issued as member; reissue with --role owner or --scopes …,sync. |
usage.ws_mismatch | The local slug and the server's workspace differ — the message names both. |
precond.no_remote | An explicit --server for a command with no remote mode; run it without the flag (with MYC_SERVER set it runs locally with a WARN). |
WARN server.local_only | MYC_SERVER is set but the command has no server mode: it ran locally — check that this is what you meant. |
/v1/health says ok, other routes say 503 db.query | The container is alive but cannot reach Postgres. Liveness deliberately knows nothing about the database — ask /v1/readyz, which answers 503 db.unavailable exactly for this. |
/v1/readyz answers 401, with a token — notfound.route | There is no readiness route at all: /v1/health is liveness and knows nothing about the database. Hang the orchestrator's probe on readiness and watch the database separately. |
| Что видно | Что это значит |
|---|---|
401 denied.no_token | Нет MYC_TOKEN, либо прокси срезает заголовок Authorization. |
denied.scope: this token has no 'sync' scope | Токен выпущен как member; выпустите с --role owner или --scopes …,sync. |
usage.ws_mismatch | Локальный слаг и воркспейс сервера разные — в сообщении названы оба. |
precond.no_remote | Явный --server для команды без удалённого режима; выполните её без флага (с MYC_SERVER в окружении она работает локально с WARN). |
WARN server.local_only | MYC_SERVER задан, но у команды нет серверного режима: выполнено локально — проверьте, что это то, что нужно. |
/v1/health отвечает ok, остальные маршруты — 503 db.query | Контейнер жив, но до Postgres не достаёт. Живость намеренно ничего не знает о базе — спрашивайте /v1/readyz, он отвечает 503 db.unavailable именно на этот случай. |
/v1/readyz отвечает 401, с токеном — notfound.route | Маршрута готовности нет вовсе: /v1/health — живость, и о базе он ничего не знает. Пробу оркестратора вешайте на готовность, а за базой следите отдельно. |
The full deployment guide lives in the repository: docs/deploy.ru.md (Russian) and docs/deploy.md (English).
Полное руководство по развёртыванию лежит в репозитории: docs/deploy.ru.md (русский) и docs/deploy.md (английский).