AndreyandClaude Opus 4.8 44bffecdd0 🚑 fix(tenancy): guard-функции C04 как SECURITY DEFINER
Триггерные функции enforce_tenant_fk/_user/_pair исполнялись как SECURITY
INVOKER, поэтому их внутренний SELECT родительской строки подчинялся RLS.
На кросс-тенантном пути без выставленного custocrm.organization_id
(claim_next_outbox_event берёт событие любой организации) родитель не был
виден, parent_org = NULL, и сравнение IS DISTINCT FROM ложно срабатывало:
легитимный UPDATE падал с `cross-tenant relation on
events_outboxevent.membership_id`.

На проде это увело воркер в краш-петлю (1022 рестарта, ~18 часов простоя):
первое же outbox-событие с membership_id заклинило очередь, а вместе с ней
доставку приглашений на звонок в TG/MAX, поллинг входящих сообщений и
серверные таймауты звонков. Веб-канал не пострадал — там приглашение
проставляется синхронно, минуя outbox.

Проверка не ослабляется: функции исполняются от custocrm_schema, настоящее
нарушение по-прежнему приводит к RAISE. search_path закреплён, как того
требует безопасность SECURITY DEFINER.

Дополнительно claim_next_outbox_event обёрнут в try/except, чтобы
отравленное событие впредь не роняло процесс целиком.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 13:51:53 +03:00
2026-06-17 18:14:16 +03:00
2026-07-12 01:17:17 +03:00
2026-06-26 15:10:36 +03:00

CustoCRM

Canonical implementation workspace for hub.edevs.tech.

Local start

Copy-Item .env.example .env
.\scripts\start.ps1

The local compose stack contains:

  • isolated app, platform, and loopback-only admin Django runtimes;
  • background worker;
  • PostgreSQL;
  • Redis;
  • Internal Hub UI;
  • Web Chat UI;
  • local Nginx reverse proxy.

No production secrets are stored in the repository.

Default local URLs:

  • App gateway: http://app.localhost/
  • Platform health: http://platform.localhost/api/v1/health/live/
  • Django admin (loopback only): http://127.0.0.1:18001/admin/
  • Internal Hub UI (direct Vite): http://localhost:5173
  • Web Chat: http://localhost:5175
  • App API (direct): http://localhost:8010/api/v1

Local accounts (TOTP disabled). These credentials are fixed — do not change them:

  • OWNER — owner@edevs.tech / Owner-Local-2026
  • OPERATOR — a.kotova@edevs.tech / Operator-Local-2026

Bootstrap the organization and both accounts:

docker compose run --rm backend-app python manage.py bootstrap_owner --email owner@edevs.tech --password Owner-Local-2026 --name "Иван Петров"

Tests

All suites run in Docker, so no manual environment is required — the test runners auto-detect themselves and relax production hardening (secret-key fail-fast, SSL redirect, throttling) for the duration of the run.

Run everything (backend tests, frontend unit tests, typechecks):

.\scripts\check.ps1

Individual suites:

# Backend (pytest + pytest-django)
docker compose run --rm backend-app pytest

# Frontend unit tests (vitest)
docker compose run --rm frontend npm run test

# End-to-end (Playwright, internal-ui) — auto-starts the dev server
npx playwright install chromium   # one-time
npx playwright test --project=internal-ui

Backend pytest configuration lives in apps/backend/pytest.ini (it must sit next to manage.py so it is also visible inside the backend container).

Languages
Python 45.5%
TypeScript 24.2%
HTML 15.9%
JavaScript 8.8%
CSS 5.1%
Other 0.4%