docs(spec): phase2 scope, Spec#18 pilot stub subscription, SMTP note. Refs EventHub/EventHubSpec#8 Fixes EventHub/EventHubSpec#18

This commit is contained in:
2026-08-14 20:08:38 +03:00
parent 0fa213a1f8
commit 436e0a70c0
3 changed files with 41 additions and 15 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ Runtime-копии в приложении: `EventHubFront/public/brand/` (mark,
- [ ] RDAP/whois: свободен ли домен; нет ли конфликтующих TM - [ ] RDAP/whois: свободен ли домен; нет ли конфликтующих TM
- [ ] DNS: A/AAAA или CNAME на edge (Traefik/CDN); отдельно `www` / apex - [ ] DNS: A/AAAA или CNAME на edge (Traefik/CDN); отдельно `www` / apex
- [ ] TLS: ACME (Lets Encrypt) или managed cert; проверить SAN - [ ] TLS: ACME (Lets Encrypt) или managed cert; проверить SAN
- [ ] Почта: SPF/DKIM/DMARC когда будет SMTP (серия B2) - [ ] Почта: SPF/DKIM/DMARC — чеклист в `EventHubDevOps/docs/SMTP.md` (исполнение после ок на домен/ящик)
- [ ] Stage/IFT: либо оставить `eventhub.*` стенды, либо завести `*.calentiq.*` aliases в DevOps - [ ] Stage/IFT: либо оставить `eventhub.*` стенды, либо завести `*.calentiq.*` aliases в DevOps
- [ ] Обновить публичные URL в UI/письмах только после cutover - [ ] Обновить публичные URL в UI/письмах только после cutover
+23 -6
View File
@@ -224,13 +224,23 @@ Legacy: прямой `POST /v1/calendars/:id/specialists` **не использ
по тем же правилам (owner — все события своих календарей; specialist — только свои слоты); по тем же правилам (owner — все события своих календарей; specialist — только свои слоты);
past-pending → `expired` и из ответа исключается. past-pending → `expired` и из ответа исключается.
#### Фаза 2 (вне текущего контракта реализации) #### Фаза 2 (вне текущего контракта реализации; трекер Spec#8)
- `calendar_share` (`read` | `write` | `admin`): не путать с follow, specialist_invite и платной subscription. - **Pilot / ops:** SMTP / transactional email; backup; secrets / certs / alerts; legal stubs;
- Реальный эквайринг, waitlist, оплата услуги клиентом (B2C). позиция и боевой эквайринг **подписки владельца** (не оплата услуги клиентом); 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) ### 2.1.3. Share / приглашения (фаза 2)
Таблица `calendar_share` (`calendar_id`, `user_id`, `rights`: `read` | `write` | `admin`) Таблица `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. События (расширенная версия с повторяющимися событиями) ### 2.2. События (расширенная версия с повторяющимися событиями)
@@ -379,7 +389,12 @@ Legacy: прямой `POST /v1/calendars/:id/specialists` **не использ
- Пользователи могут оформить подписку (`subscription`) с разными планами: monthly, quarterly, - Пользователи могут оформить подписку (`subscription`) с разными планами: monthly, quarterly,
biannual, annual. biannual, annual.
- Цены (`logic_subscription:plan_price/1`, minor units): monthly **999**, quarterly **2499**, - Цены (`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`. - Статус подписки: `active`, `expired`, `cancelled`.
- Отслеживание использования пробного периода (`trial_used`); trial стартует **только** - Отслеживание использования пробного периода (`trial_used`); trial стартует **только**
явным `POST /v1/subscription` (`action=start_trial`), не при create/upgrade commercial явным `POST /v1/subscription` (`action=start_trial`), не при create/upgrade commercial
@@ -500,7 +515,9 @@ src/
- `POST /v1/register` — регистрация. - `POST /v1/register` — регистрация.
- `POST /v1/verify` — подтверждение email; при успехе — `active` и дефолтный personal-календарь. - `POST /v1/verify` — подтверждение email; при успехе — `active` и дефолтный personal-календарь.
- `POST /v1/forgot-password``{email}` → всегда `200` (без enumeration); письмо со сбросом - `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, - `POST /v1/reset-password``{token, password}` (пароль ≥ 8 символов); успех → новый hash,
токен удалён, refresh-сессии user отозваны; `404`/`410`/`400`/`403`. токен удалён, refresh-сессии user отозваны; `404`/`410`/`400`/`403`.
- `POST /v1/login` — вход. - `POST /v1/login` — вход.
+17 -8
View File
@@ -310,7 +310,8 @@ confirmed booking; подсказка gated + жалоба остаются (ж
`GET /v1/subscription`, `POST /v1/subscription` (`start_trial` | `activate` + `plan` + опционально `payment_info`). `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**. Планы и цены (как Back `plan_price/1`, minor units → ₽): monthly **999**, quarterly **2499**, biannual **4499**, annual **7999**.
UI: карточки сравнения, локализованный «Бесплатно» без подписки, trial, демо-оплата (шлюз-заглушка). 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 **нет**, (сначала явный `start_trial` или `activate`; auto-start trial при create **нет**,
Back#61 / BackSpec §2.1.2, §2.9). После renew commercial-календари владельца снова Back#61 / BackSpec §2.1.2, §2.9). После renew commercial-календари владельца снова
с `booking_open=true` без смены type (restricted → full). с `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-моков). 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): Не в текущем контракте реализации (кроме specialist_invite — см. §5.4 / BackSpec §2.1.2).
- шаринг календаря с правами (`calendar_share`) — фаза 2 (не путать со specialist_invite) Эпик: 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 - серверный logout / revoke session
- загрузка файлов (вложения) - загрузка файлов (avatar / cover / вложения)
- явный `client_type=mobile` (фаза 3 бэка) - полноценный push / reminders (сейчас in-app `notification` + email для specialist_invite)
- полноценный push (сейчас in-app `notification` + email для specialist_invite) - waitlist на событие
- waitlist / оплата услуги клиентом (B2C) - шаринг календаря с правами (`calendar_share`) — низкий приоритет, не путать со specialist_invite
- явный `client_type=mobile` — хвост (фаза 3 бэка / нативный клиент)
**Вне горизонта (не фаза 2):** оплата услуги клиентом (B2C).
Лайки/дизлайки отзывов: `PUT/DELETE /v1/reviews/:id/vote`, поле `my_vote` в ответах отзывов (EventHubBack#47). Лайки/дизлайки отзывов: `PUT/DELETE /v1/reviews/:id/vote`, поле `my_vote` в ответах отзывов (EventHubBack#47).