🚚 chore!: переименование инфраструктуры CustoCRM/hub → Chatballs с миграцией

- каталог code/custocrm → code/chatballs; CLI custocrm → chatballs; пакеты
  hub_platform → chatballs, hub_backend → chatballs_backend (app labels прежние)
- переменные CUS_* и CUSTOCRM_* → CHATBALLS_*; образы chatballs-*; compose-проект
  и база chatballs (были edevs_hub); роли Postgres chatballs_* (были custocrm_*);
  схема RLS chatballs и GUC chatballs.organization_id; cookie chatballs_*
- CI: APP_DIR code/chatballs, DEPLOY_ROOT /opt/chatballs
- deploy/migrate/rename-to-chatballs.sh — миграция существующей установки без
  потери данных: остановка старого проекта, .env (с резервной копией),
  переименование суперпользователя initdb через временную роль, остальных ролей,
  базы, схемы и функции RLS; проверено на локальном стеке
- dev-стек хранит Postgres в bind-mount data/postgres, как prod (именованный том
  compose.dev был устаревшим снимком и вводил в заблуждение)
- снятие демо удаляет объекты, созданные поверх демо-данных тестировавшим
  (звонки по демо-диалогу), вместо падения на PROTECT
- реальные домены *.custocrm.ru и идентификаторы документов не тронуты

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
AndreyandClaude Fable 5.1 committed 2026-09-05 22:21:12 +03:00
1 parent dbd7ae3150
commit 1a61780dec
628 files changed
+5839 -5622

No files matched your search

+20 -20
View File
@@ -1,18 +1,18 @@
#!/usr/bin/env bash
# common.sh — shared helpers for the CustoCRM deployment CLI.
# common.sh — shared helpers for the Chatballs deployment CLI.
CUSTOCRM_NON_INTERACTIVE=0
CUSTOCRM_JSON=0
CHATBALLS_NON_INTERACTIVE=0
CHATBALLS_JSON=0
log() { printf '[custocrm] %s\n' "$*" >&2; }
log_ok() { printf '[custocrm] OK: %s\n' "$*" >&2; }
log_warn() { printf '[custocrm] WARN: %s\n' "$*" >&2; }
log_err() { printf '[custocrm] ERROR: %s\n' "$*" >&2; }
log() { printf '[chatballs] %s\n' "$*" >&2; }
log_ok() { printf '[chatballs] OK: %s\n' "$*" >&2; }
log_warn() { printf '[chatballs] WARN: %s\n' "$*" >&2; }
log_err() { printf '[chatballs] ERROR: %s\n' "$*" >&2; }
die() {
local msg="$1"
local code="${2:-1}"
if [[ "$CUSTOCRM_JSON" == "1" ]]; then
if [[ "$CHATBALLS_JSON" == "1" ]]; then
printf '{"status":"error","error":%s}\n' "$(json_escape "$msg")"
else
log_err "$msg"
@@ -35,11 +35,11 @@ require_cmd() {
}
release_dir() {
printf '%s' "${CUSTOCRM_RELEASE_DIR:?CUSTOCRM_RELEASE_DIR is not set}"
printf '%s' "${CHATBALLS_RELEASE_DIR:?CHATBALLS_RELEASE_DIR is not set}"
}
instance_dir() {
printf '%s' "${CUSTOCRM_INSTANCE_DIR:?CUSTOCRM_INSTANCE_DIR is not set}"
printf '%s' "${CHATBALLS_INSTANCE_DIR:?CHATBALLS_INSTANCE_DIR is not set}"
}
instance_env_file() { printf '%s/.env' "$(instance_dir)"; }
@@ -100,15 +100,15 @@ verify_release_checksums() {
validate_calls_network_boundary() {
local web_ip turn_ip
web_ip="$(env_get "$(instance_env_file)" CUSTOCRM_WEB_LISTENING_IP)"
turn_ip="$(env_get "$(instance_env_file)" CUS_TURN_LISTENING_IP)"
web_ip="$(env_get "$(instance_env_file)" CHATBALLS_WEB_LISTENING_IP)"
turn_ip="$(env_get "$(instance_env_file)" CHATBALLS_TURN_LISTENING_IP)"
[[ -n "$web_ip" ]] || {
log_err "CUSTOCRM_WEB_LISTENING_IP is required for calls profile"
log_err "CHATBALLS_WEB_LISTENING_IP is required for calls profile"
return 1
}
[[ "$web_ip" != "0.0.0.0" ]] || {
log_err "CUSTOCRM_WEB_LISTENING_IP cannot be 0.0.0.0 when calls profile uses TURN TLS on 443"
log_err "CHATBALLS_WEB_LISTENING_IP cannot be 0.0.0.0 when calls profile uses TURN TLS on 443"
return 1
}
[[ "$web_ip" != "$turn_ip" ]] || {
@@ -119,12 +119,12 @@ validate_calls_network_boundary() {
release_image_keys() {
printf '%s\n' \
CUSTOCRM_BACKEND_IMAGE \
CUSTOCRM_FRONTEND_IMAGE \
CUSTOCRM_POSTGRES_IMAGE \
CUSTOCRM_REDIS_IMAGE \
CUSTOCRM_GATEWAY_IMAGE \
CUSTOCRM_COTURN_IMAGE
CHATBALLS_BACKEND_IMAGE \
CHATBALLS_FRONTEND_IMAGE \
CHATBALLS_POSTGRES_IMAGE \
CHATBALLS_REDIS_IMAGE \
CHATBALLS_GATEWAY_IMAGE \
CHATBALLS_COTURN_IMAGE
}
validate_release_image_refs() {
+14 -14
View File
@@ -56,10 +56,10 @@ _deploy_validate() {
validate_release_image_refs || return 1
local app_domain platform_domain
app_domain="$(env_get "$(instance_env_file)" CUSTOCRM_APP_DOMAIN)"
platform_domain="$(env_get "$(instance_env_file)" CUSTOCRM_PLATFORM_DOMAIN)"
[[ -n "$app_domain" ]] || { log_err "CUSTOCRM_APP_DOMAIN not set"; return 1; }
[[ -n "$platform_domain" ]] || { log_err "CUSTOCRM_PLATFORM_DOMAIN not set"; return 1; }
app_domain="$(env_get "$(instance_env_file)" CHATBALLS_APP_DOMAIN)"
platform_domain="$(env_get "$(instance_env_file)" CHATBALLS_PLATFORM_DOMAIN)"
[[ -n "$app_domain" ]] || { log_err "CHATBALLS_APP_DOMAIN not set"; return 1; }
[[ -n "$platform_domain" ]] || { log_err "CHATBALLS_PLATFORM_DOMAIN not set"; return 1; }
[[ "$app_domain" != "$platform_domain" ]] || {
log_err "app and platform domains must be distinct"
return 1
@@ -100,7 +100,7 @@ _wait_running() {
}
_normalize_schema_ownership() {
# Приводит владение объектов public-схемы к роли custocrm_schema, в которую
# Приводит владение объектов public-схемы к роли chatballs_schema, в которую
# входит migration-user. Идемпотентно: безопасно на каждом деплое. Без этого
# миграции от migration-user падают на таблицах, созданных не им
# («must be owner of table …»). Выполняется под суперпользователем POSTGRES_USER.
@@ -112,7 +112,7 @@ _normalize_schema_ownership() {
[[ -n "$pg_db" ]] || { log_err "POSTGRES_DB not set"; return 1; }
run_compose exec -T postgres \
psql -v ON_ERROR_STOP=1 -U "$pg_user" -d "$pg_db" \
-f /custocrm-reassign-ownership.sql >/dev/null
-f /chatballs-reassign-ownership.sql >/dev/null
}
_first_json_service_state() {
@@ -129,18 +129,18 @@ _first_json_service_state() {
_smoke() {
local app_domain platform_domain
app_domain="$(env_get "$(instance_env_file)" CUSTOCRM_APP_DOMAIN)"
platform_domain="$(env_get "$(instance_env_file)" CUSTOCRM_PLATFORM_DOMAIN)"
app_domain="$(env_get "$(instance_env_file)" CHATBALLS_APP_DOMAIN)"
platform_domain="$(env_get "$(instance_env_file)" CHATBALLS_PLATFORM_DOMAIN)"
run_compose exec -T backend-app python - <<'PY' >/dev/null 2>&1 || {
import os
import urllib.error
import urllib.request
app_domain = os.environ["CUSTOCRM_APP_DOMAIN"]
platform_domain = os.environ["CUSTOCRM_PLATFORM_DOMAIN"]
app_health_host = os.environ.get("CUSTOCRM_APP_HEALTHCHECK_HOST") or app_domain
platform_health_host = os.environ.get("CUSTOCRM_PLATFORM_HEALTHCHECK_HOST") or platform_domain
app_domain = os.environ["CHATBALLS_APP_DOMAIN"]
platform_domain = os.environ["CHATBALLS_PLATFORM_DOMAIN"]
app_health_host = os.environ.get("CHATBALLS_APP_HEALTHCHECK_HOST") or app_domain
platform_health_host = os.environ.get("CHATBALLS_PLATFORM_HEALTHCHECK_HOST") or platform_domain
app_health_request = urllib.request.Request(
"http://127.0.0.1:8000/api/v1/health/ready/",
headers={"Host": app_health_host, "X-Forwarded-Proto": "https"},
@@ -194,11 +194,11 @@ _state_file() { printf '%s/applied_release' "$(state_dir)"; }
_record_release() {
local ver
ver="$(env_get "$(release_env_file)" CUSTOCRM_VERSION)"
ver="$(env_get "$(release_env_file)" CHATBALLS_VERSION)"
printf 'applied_version=%s\napplied_at=%s\n' "${ver:-unknown}" \
"$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date)" > "$(_state_file)"
}
_applied_version_target() {
env_get "$(release_env_file)" CUSTOCRM_VERSION || printf 'unknown'
env_get "$(release_env_file)" CHATBALLS_VERSION || printf 'unknown'
}
+16 -16
View File
@@ -11,9 +11,9 @@ cmd_doctor() {
shift
local msg="$*"
if [[ "$ok" == "1" ]]; then
[[ "$CUSTOCRM_JSON" == "1" ]] || log_ok "$msg"
[[ "$CHATBALLS_JSON" == "1" ]] || log_ok "$msg"
else
[[ "$CUSTOCRM_JSON" == "1" ]] || log_err "$msg"
[[ "$CHATBALLS_JSON" == "1" ]] || log_err "$msg"
failures=$((failures + 1))
fi
}
@@ -86,17 +86,17 @@ cmd_doctor() {
fi
local app_domain platform_domain
app_domain="$(env_get "$(instance_env_file)" CUSTOCRM_APP_DOMAIN)"
platform_domain="$(env_get "$(instance_env_file)" CUSTOCRM_PLATFORM_DOMAIN)"
app_domain="$(env_get "$(instance_env_file)" CHATBALLS_APP_DOMAIN)"
platform_domain="$(env_get "$(instance_env_file)" CHATBALLS_PLATFORM_DOMAIN)"
if [[ -n "$app_domain" ]]; then
_doctor_report 1 "CUSTOCRM_APP_DOMAIN set: $app_domain"
_doctor_report 1 "CHATBALLS_APP_DOMAIN set: $app_domain"
else
_doctor_report 0 "CUSTOCRM_APP_DOMAIN not set"
_doctor_report 0 "CHATBALLS_APP_DOMAIN not set"
fi
if [[ -n "$platform_domain" ]]; then
_doctor_report 1 "CUSTOCRM_PLATFORM_DOMAIN set: $platform_domain"
_doctor_report 1 "CHATBALLS_PLATFORM_DOMAIN set: $platform_domain"
else
_doctor_report 0 "CUSTOCRM_PLATFORM_DOMAIN not set"
_doctor_report 0 "CHATBALLS_PLATFORM_DOMAIN not set"
fi
if [[ -n "$app_domain" ]] && [[ "$app_domain" != "$platform_domain" ]]; then
_doctor_report 1 "app and platform domains are distinct"
@@ -105,11 +105,11 @@ cmd_doctor() {
fi
local acme_email
acme_email="$(env_get "$(instance_env_file)" CUSTOCRM_ACME_EMAIL)"
acme_email="$(env_get "$(instance_env_file)" CHATBALLS_ACME_EMAIL)"
if [[ -n "$acme_email" ]]; then
_doctor_report 1 "CUSTOCRM_ACME_EMAIL set"
_doctor_report 1 "CHATBALLS_ACME_EMAIL set"
else
_doctor_report 0 "CUSTOCRM_ACME_EMAIL not set"
_doctor_report 0 "CHATBALLS_ACME_EMAIL not set"
fi
local pg_pwd
@@ -121,16 +121,16 @@ cmd_doctor() {
fi
local secret
secret="$(env_get "$(instance_env_file)" CUS_SECRET_KEY)"
secret="$(env_get "$(instance_env_file)" CHATBALLS_SECRET_KEY)"
if [[ -n "$secret" ]] && [[ "$secret" != "change-me-long-random-secret" ]]; then
_doctor_report 1 "CUS_SECRET_KEY set"
_doctor_report 1 "CHATBALLS_SECRET_KEY set"
else
_doctor_report 0 "CUS_SECRET_KEY default/empty"
_doctor_report 0 "CHATBALLS_SECRET_KEY default/empty"
fi
if profile_enabled calls; then
local missing=0 k
for k in CUS_CALL_TURN_SECRET CUS_CALL_TURN_REALM CUS_TURN_EXTERNAL_IP CUS_TURN_LISTENING_IP; do
for k in CHATBALLS_CALL_TURN_SECRET CHATBALLS_CALL_TURN_REALM CHATBALLS_TURN_EXTERNAL_IP CHATBALLS_TURN_LISTENING_IP; do
if [[ -z "$(env_get "$(instance_env_file)" "$k")" ]]; then
_doctor_report 0 "$k required for calls profile"
missing=1
@@ -159,7 +159,7 @@ cmd_doctor() {
die "doctor: $failures check(s) failed" 1
fi
if [[ "$CUSTOCRM_JSON" == "1" ]]; then
if [[ "$CHATBALLS_JSON" == "1" ]]; then
printf '{"status":"ok","checks":"passed"}\n'
else
log_ok "doctor: all checks passed"
+3 -3
View File
@@ -6,17 +6,17 @@ cmd_status() {
local inst rel applied target
inst="$(instance_dir)"
rel="$(release_dir)"
target="$(env_get "$(release_env_file)" CUSTOCRM_VERSION)"
target="$(env_get "$(release_env_file)" CHATBALLS_VERSION)"
applied="$(env_get "$(_state_file)" applied_version)"
if [[ "$CUSTOCRM_JSON" == "1" ]]; then
if [[ "$CHATBALLS_JSON" == "1" ]]; then
printf '{"status":"info","instance":%s,"release_dir":%s,"target_version":%s,"applied_version":%s}\n' \
"$(json_escape "$inst")" "$(json_escape "$rel")" \
"$(json_escape "${target:-unknown}")" "$(json_escape "${applied:-none}")"
return 0
fi
printf 'CustoCRM status\n'
printf 'Chatballs status\n'
printf ' instance dir: %s\n' "$inst"
printf ' release dir: %s\n' "$rel"
printf ' target version: %s\n' "${target:-unknown}"