From 436e0a70c0d8239c16dcfdb8363557a38ebbcd50 Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Fri, 14 Aug 2026 20:08:38 +0300 Subject: [PATCH] docs(spec): phase2 scope, Spec#18 pilot stub subscription, SMTP note. Refs EventHub/EventHubSpec#8 Fixes EventHub/EventHubSpec#18 --- BRANDING.md | 2 +- EventHubBackSpec.md | 29 +++++++++++++++++++++++------ EventHubFrontSpec.md | 25 +++++++++++++++++-------- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/BRANDING.md b/BRANDING.md index 9db9727..85df625 100644 --- a/BRANDING.md +++ b/BRANDING.md @@ -41,7 +41,7 @@ Runtime-копии в приложении: `EventHubFront/public/brand/` (mark, - [ ] RDAP/whois: свободен ли домен; нет ли конфликтующих TM - [ ] DNS: A/AAAA или CNAME на edge (Traefik/CDN); отдельно `www` / apex - [ ] TLS: ACME (Let’s Encrypt) или managed cert; проверить SAN -- [ ] Почта: SPF/DKIM/DMARC когда будет SMTP (серия B2) +- [ ] Почта: SPF/DKIM/DMARC — чеклист в `EventHubDevOps/docs/SMTP.md` (исполнение после ок на домен/ящик) - [ ] Stage/IFT: либо оставить `eventhub.*` стенды, либо завести `*.calentiq.*` aliases в DevOps - [ ] Обновить публичные URL в UI/письмах только после cutover diff --git a/EventHubBackSpec.md b/EventHubBackSpec.md index 23b27e2..eb7e0ab 100644 --- a/EventHubBackSpec.md +++ b/EventHubBackSpec.md @@ -224,13 +224,23 @@ Legacy: прямой `POST /v1/calendars/:id/specialists` **не использ по тем же правилам (owner — все события своих календарей; specialist — только свои слоты); past-pending → `expired` и из ответа исключается. -#### Фаза 2 (вне текущего контракта реализации) -- `calendar_share` (`read` | `write` | `admin`): не путать с follow, specialist_invite и платной subscription. -- Реальный эквайринг, waitlist, оплата услуги клиентом (B2C). +#### Фаза 2 (вне текущего контракта реализации; трекер Spec#8) +- **Pilot / ops:** SMTP / transactional email; backup; secrets / certs / alerts; legal stubs; + позиция и боевой эквайринг **подписки владельца** (не оплата услуги клиентом); DNS/SPF + без покупки домена без явного ок. +- Waitlist на событие (после уведомлений). +- Серверный logout / revoke session; загрузка файлов (avatar/cover); полноценные + уведомления / reminders. +- `calendar_share` (`read` | `write` | `admin`): низкий приоритет; не путать с follow, + specialist_invite и платной subscription. User HTTP API и UI — до отдельной задачи + (таблица в схеме есть, см. §2.1.3). +- `client_type=mobile` — хвост, когда появится нативный клиент. +- **Не в фазе 2:** оплата услуги клиентом (B2C) — вне горизонта продукта. ### 2.1.3. Share / приглашения (фаза 2) Таблица `calendar_share` (`calendar_id`, `user_id`, `rights`: `read` | `write` | `admin`) -существует в схеме. User HTTP API и клиентский UI — Future до отдельной задачи. +существует в схеме. User HTTP API и клиентский UI — не стартовать, пока нет явного +сценария соредактора personal (совместная работа сейчас: specialist_invite + booking inbox). ### 2.2. События (расширенная версия с повторяющимися событиями) @@ -379,7 +389,12 @@ Legacy: прямой `POST /v1/calendars/:id/specialists` **не использ - Пользователи могут оформить подписку (`subscription`) с разными планами: monthly, quarterly, biannual, annual. - Цены (`logic_subscription:plan_price/1`, minor units): monthly **999**, quarterly **2499**, - biannual **4499**, annual **7999**; trial — 0. Платёжный шлюз — заглушка (`process_payment` → ok). + biannual **4499**, annual **7999**; trial — 0. +- **Пилот (Spec#18, вариант A):** боевого PSP **нет**. `process_payment` — заглушка → ok. + Владелец получает commercial через: (1) `POST /v1/subscription` `action=start_trial`, + и/или (2) admin activate (`POST /v1/admin/subscriptions/:id`). Реальный эквайринг + подписки владельца — отдельная задача после пилота (не блокер soft-launch). +- **Вне горизонта:** оплата услуги клиентом (B2C) — не в фазе 2 / не в пилоте. - Статус подписки: `active`, `expired`, `cancelled`. - Отслеживание использования пробного периода (`trial_used`); trial стартует **только** явным `POST /v1/subscription` (`action=start_trial`), не при create/upgrade commercial @@ -500,7 +515,9 @@ src/ - `POST /v1/register` — регистрация. - `POST /v1/verify` — подтверждение email; при успехе — `active` и дефолтный personal-календарь. - `POST /v1/forgot-password` — `{email}` → всегда `200` (без enumeration); письмо со сбросом - только для `active` (stub `logic_email:send_password_reset/2`, как verification). + только для `active`. Почта: `logic_email` через SMTP (`SMTP_HOST` и др.); без хоста — + log-only. HTML+plain шаблоны: `priv/email/layout.html` (CalenTIQ). Ссылки: `PUBLIC_APP_URL` + `/verify?token=`, + `/invites?token=`, `/reset-password?token=` (бренд CalenTIQ). - `POST /v1/reset-password` — `{token, password}` (пароль ≥ 8 символов); успех → новый hash, токен удалён, refresh-сессии user отозваны; `404`/`410`/`400`/`403`. - `POST /v1/login` — вход. diff --git a/EventHubFrontSpec.md b/EventHubFrontSpec.md index 0f39a78..18cb6f4 100644 --- a/EventHubFrontSpec.md +++ b/EventHubFrontSpec.md @@ -310,7 +310,8 @@ confirmed booking; подсказка gated + жалоба остаются (ж `GET /v1/subscription`, `POST /v1/subscription` (`start_trial` | `activate` + `plan` + опционально `payment_info`). Планы и цены (как Back `plan_price/1`, minor units → ₽): monthly **999**, quarterly **2499**, biannual **4499**, annual **7999**. UI: карточки сравнения, локализованный «Бесплатно» без подписки, trial, демо-оплата (шлюз-заглушка). -Create/upgrade commercial без **уже active** sub/trial → `402` → `/subscription` +**Пилот (Spec#18 A):** без боевого PSP; commercial через `start_trial` и/или admin activate. +B2C оплаты услуги нет. Create/upgrade commercial без **уже active** sub/trial → `402` → `/subscription` (сначала явный `start_trial` или `activate`; auto-start trial при create **нет**, Back#61 / BackSpec §2.1.2, §2.9). После renew commercial-календари владельца снова с `booking_open=true` без смены type (restricted → full). @@ -361,15 +362,23 @@ CI: lint → build → Playwright **mock** (до push) → push image → deploy E2E: `e2e/TESTIDS.md`. Моки (`npm run test:e2e`, `project=mock`) — только локально / до деплоя. После деплоя на IFT/stage — `SMOKE_USER_*` + `npm run test:e2e:ift|stage` против реального API (без Playwright route-моков). -## 7. Ограничения MVP (Future) +## 7. Ограничения MVP / Фаза 2 (Spec#8) -Не в текущей волне (кроме specialist_invite — см. §5.4 / BackSpec §2.1.2): -- шаринг календаря с правами (`calendar_share`) — фаза 2 (не путать со specialist_invite) +Не в текущем контракте реализации (кроме specialist_invite — см. §5.4 / BackSpec §2.1.2). +Эпик: https://git.sabilin.com/EventHub/EventHubSpec/issues/8 + +**Pilot / ops (фаза 2):** SMTP / transactional email; backup; secrets / certs / alerts; +legal stubs; позиция по подписке **владельца**; DNS/SPF без покупки домена без явного ок. + +**Продукт (фаза 2):** - серверный logout / revoke session -- загрузка файлов (вложения) -- явный `client_type=mobile` (фаза 3 бэка) -- полноценный push (сейчас in-app `notification` + email для specialist_invite) -- waitlist / оплата услуги клиентом (B2C) +- загрузка файлов (avatar / cover / вложения) +- полноценный push / reminders (сейчас in-app `notification` + email для specialist_invite) +- waitlist на событие +- шаринг календаря с правами (`calendar_share`) — низкий приоритет, не путать со specialist_invite +- явный `client_type=mobile` — хвост (фаза 3 бэка / нативный клиент) + +**Вне горизонта (не фаза 2):** оплата услуги клиентом (B2C). Лайки/дизлайки отзывов: `PUT/DELETE /v1/reviews/:id/vote`, поле `my_vote` в ответах отзывов (EventHubBack#47).