Несколько ящиков у одного логина, общие ящики, «кто ответил», вход ящик*логин #27

Merged
Liosha84 merged 1 commits from feat/multi-mailbox into master 2026-11-07 14:45:26 +01:00
Owner

Второй PR почты по согласованной схеме. Сначала мерж #26 — этот PR построен на нём (его коммит тоже виден здесь; после мержа #26 останется только свой).

Что делает

  • Несколько ящиков у одного логина: слева в меню MAILBOXES — свой, общие (участник), подключённые (⊕: адрес + пароль того ящика, с LoginGuard). Клик — переключиться (сессия ящика, JWT с by = логин), × — убрать из меню. Непрочитанные — INBOX + свои папки.
  • Общий ящик (support@, billing@): галочка «shared» при создании, кнопка group — участники. Своего входа нет (веб, SMTP, IMAP — отказ), «прочитано» общее, у письма «Answered by …» (ответ из веб-почты).
  • Почтовые программы: ящик*свой_логин + свой пароль — IMAP и SMTP (письма от имени общего ящика; MAIL FROM чужого адреса — 553).
  • В открытом чужом ящике (общий / подключённый / OPEN админа) профиль и пароль не меняются — 403.
  • Служебное API: PUT /api/service/shared/{address} {displayName, members[]}; выключение аккаунта убирает и из рассылок, и из общих ящиков.
  • README: несколько ящиков, общие, ящик*логин.

Проверено

  • 88 тестов (ImapServerTest один раз упал на STARTTLS — флак, 2 перезапуска зелёные, полный прогон зелёный).
  • Живой прогон jar на Postgres 17 с апгрейдом V6→V7 на данных первого прогона: shared создан с участниками; вход общим ящиком — отказ (веб, SMTP 535); support*bob SMTP OK, MAIL FROM bob в этой сессии — 553, отправка от support OK; IMAP support*bob OK, без доступа — отказ; сессия чужого ящика без доступа — 403; смена пароля в открытом ящике — 403; bob ответил из support → у jambotronpw в support видно answeredBy=bob; подключить staging@ (неверный пароль 400, верный — ATTACHED с непрочитанными), убрать — 204.
  • Скриншоты UI (левое меню с support@ и счётчиком, настройки: SHARED, участники, LISTS). ng build OK.

Дальше: PR Jambotron (роль → ящик <username>@, назначения → рассылки → роли, раздел чеклиста), Kuma → alerts-prod@/alerts-staging@.

α

🤖 Generated with Claude Code

Второй PR почты по согласованной схеме. **Сначала мерж #26** — этот PR построен на нём (его коммит тоже виден здесь; после мержа #26 останется только свой). **Что делает** - **Несколько ящиков у одного логина**: слева в меню **MAILBOXES** — свой, общие (участник), подключённые (⊕: адрес + пароль того ящика, с LoginGuard). Клик — переключиться (сессия ящика, JWT с `by` = логин), × — убрать из меню. Непрочитанные — INBOX + свои папки. - **Общий ящик** (`support@`, `billing@`): галочка «shared» при создании, кнопка `group` — участники. Своего входа нет (веб, SMTP, IMAP — отказ), «прочитано» общее, у письма **«Answered by …»** (ответ из веб-почты). - **Почтовые программы**: `ящик*свой_логин` + свой пароль — IMAP и SMTP (письма от имени общего ящика; MAIL FROM чужого адреса — 553). - В открытом чужом ящике (общий / подключённый / OPEN админа) профиль и пароль не меняются — 403. - Служебное API: `PUT /api/service/shared/{address}` `{displayName, members[]}`; выключение аккаунта убирает и из рассылок, и из общих ящиков. - README: несколько ящиков, общие, `ящик*логин`. **Проверено** - 88 тестов (ImapServerTest один раз упал на STARTTLS — флак, 2 перезапуска зелёные, полный прогон зелёный). - Живой прогон jar на Postgres 17 с **апгрейдом V6→V7 на данных** первого прогона: shared создан с участниками; вход общим ящиком — отказ (веб, SMTP 535); `support*bob` SMTP OK, MAIL FROM bob в этой сессии — 553, отправка от support OK; IMAP `support*bob` OK, без доступа — отказ; сессия чужого ящика без доступа — 403; смена пароля в открытом ящике — 403; bob ответил из support → у jambotronpw в support видно `answeredBy=bob`; подключить staging@ (неверный пароль 400, верный — ATTACHED с непрочитанными), убрать — 204. - Скриншоты UI (левое меню с support@ и счётчиком, настройки: SHARED, участники, LISTS). `ng build` OK. **Дальше**: PR Jambotron (роль → ящик `<username>@`, назначения → рассылки → роли, раздел чеклиста), Kuma → `alerts-prod@`/`alerts-staging@`. α 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Liosha84 added 2 commits 2026-11-07 14:27:29 +01:00
- V6 mail_lists + mail_list_members: письмо на alerts-prod@ → каждому участнику своя копия в папку рассылки;
  закрытая рассылка — только от вошедших отправителей (550 снаружи)
- bob+prod@ → ящик bob@, папка prod (создаётся сама; системные папки нельзя)
- TRAP: чужие адреса → одна копия в INBOX отправителя; наши ящики и рассылки доставляются
- /api/service/** (SERVICE_TOKEN из secrets-init): аккаунты (пароль один раз, выключение → вон из рассылок), рассылки
- MailDirectory: одно пространство адресов для ящиков и рассылок, без «+» в именах
- Настройки → LISTS для администраторов
- 86 тестов; живой прогон на Postgres 17: миграции V1–V6, API, SMTP (рассылка/метка/ловушка)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- V7: users.is_shared, mailbox_access (MEMBER от админа/Jambotron, ATTACHED по паролю ящика), messages.answered_by
- /api/mailboxes: мои ящики с непрочитанными, сессия другого ящика (JWT с claim by), подключить по паролю
  (LoginGuard), убрать из меню
- общий ящик: без своего входа (веб/SMTP/IMAP), участники открывают; «прочитано» общее; ответ из веба → answered_by
- SMTP/IMAP: ящик*логин + пароль логина (как master user в Dovecot)
- открытый чужой ящик (общий, подключённый, OPEN админа): профиль и пароль не меняются (403)
- админ: создать shared, участники ящика (PUT /{id}/members); служебное API: PUT /shared/{address};
  выключение аккаунта убирает и из общих ящиков
- UI: MAILBOXES в левом меню (переключение, ⊕ подключить, × убрать), shared/участники в настройках,
  «Answered by» у письма
- 88 тестов; живой прогон на Postgres 17 (апгрейд V6→V7 на данных), скриншоты UI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Liosha84 merged commit a26e8fe3dd into master 2026-11-07 14:45:26 +01:00
Sign in to join this conversation.