feat(membership-exit): email-подтверждение выхода — backend + письмо
Двойное подтверждение необратимого выхода (закрытия аккаунта): заявление подписывается и принимается сразу, но в блокчейн уходит только после перехода по ссылке из письма (по аналогии с verify-email/reset-key токенами). - notifications: воркфлоу MembershipExitConfirmation (письмо со ссылкой confirmationUrl). - token: тип CONFIRM_EXIT + generateConfirmExitToken (домен + application). - entity membership_exit_requests (off-chain черновик подписанного заявления; uniq coopname+username; удаляется при confirm/cancel). - MembershipExitStatus += AWAITING_CONFIRMATION; MembershipExitResult += status. - service: createMembershipExit теперь сохраняет черновик + шлёт письмо (НЕ цепь); confirmMembershipExit(token) проверяет токен и шлёт exitcoop в цепь; cancelMembershipExit удаляет черновик+токен; getMembershipExit отдаёт off-chain фазу. - resolver: + confirmMembershipExit (публичная, по токену) + cancelMembershipExit (auth+владелец). Проверено вживую: мутации в схеме, enum/Result обновлены, таблица создана (synchronize). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import { workflow as newDepositPaymentRequestWorkflow } from './new-deposit-paym
|
||||
import { workflow as resetKeyWorkflow } from './reset-key';
|
||||
import { workflow as inviteWorkflow } from './invite';
|
||||
import { workflow as emailVerificationWorkflow } from './email-verification';
|
||||
import { workflow as membershipExitConfirmationWorkflow } from './membership-exit-confirmation';
|
||||
import { workflow as serverProvisionedWorkflow } from './server-provisioned';
|
||||
import { workflow as decisionExpiredWorkflow } from './decision-expired';
|
||||
import { workflow as chatcoopCalendarEventCreatedWorkflow } from './chatcoop-calendar-event-created';
|
||||
@@ -46,6 +47,7 @@ export * as NewDepositPaymentRequest from './new-deposit-payment-request';
|
||||
export * as ResetKey from './reset-key';
|
||||
export * as Invite from './invite';
|
||||
export * as EmailVerification from './email-verification';
|
||||
export * as MembershipExitConfirmation from './membership-exit-confirmation';
|
||||
export * as ServerProvisioned from './server-provisioned';
|
||||
export * as DecisionExpired from './decision-expired';
|
||||
export * as ChatCoopCalendarEventCreated from './chatcoop-calendar-event-created';
|
||||
@@ -73,6 +75,7 @@ export const allWorkflows: WorkflowDefinition[] = [
|
||||
resetKeyWorkflow,
|
||||
inviteWorkflow,
|
||||
emailVerificationWorkflow,
|
||||
membershipExitConfirmationWorkflow,
|
||||
serverProvisionedWorkflow,
|
||||
decisionExpiredWorkflow,
|
||||
chatcoopCalendarEventCreatedWorkflow,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { WorkflowDefinition, type BaseWorkflowPayload } from '../../types';
|
||||
import { WorkflowBuilder } from '../../base/workflow-builder';
|
||||
import { createEmailStep } from '../../base/defaults';
|
||||
import { z } from 'zod';
|
||||
import { slugify } from '../../utils';
|
||||
|
||||
// Схема payload для письма-подтверждения выхода из кооператива
|
||||
export const membershipExitConfirmationPayloadSchema = z.object({
|
||||
confirmationUrl: z.string(),
|
||||
});
|
||||
|
||||
export type IPayload = z.infer<typeof membershipExitConfirmationPayloadSchema>;
|
||||
|
||||
export interface IWorkflow extends BaseWorkflowPayload, IPayload {}
|
||||
|
||||
export const name = 'Подтверждение выхода из кооператива';
|
||||
export const id = slugify(name);
|
||||
|
||||
export const workflow: WorkflowDefinition<IWorkflow> = WorkflowBuilder
|
||||
.create<IWorkflow>()
|
||||
.name(name)
|
||||
.workflowId(id)
|
||||
.description('Подтверждение по email заявления о добровольном выходе пайщика из кооператива')
|
||||
.payloadSchema(membershipExitConfirmationPayloadSchema)
|
||||
.tags(['auth'])
|
||||
.addSteps([
|
||||
createEmailStep(
|
||||
'membership-exit-confirmation-email',
|
||||
'Подтверждение выхода из кооператива',
|
||||
'Здравствуйте!<br><br>' +
|
||||
'Вы подали заявление о добровольном выходе из кооператива. Это действие необратимо: ' +
|
||||
'после подтверждения запускается процедура выхода и возврата паевого взноса, а ваш аккаунт блокируется.<br><br>' +
|
||||
'Если вы действительно хотите выйти из кооператива, перейдите по ссылке для подтверждения: ' +
|
||||
'<a href="{{payload.confirmationUrl}}">{{payload.confirmationUrl}}</a><br><br>' +
|
||||
'Если вы не подавали такое заявление — просто проигнорируйте это письмо, ничего не произойдёт.'
|
||||
),
|
||||
])
|
||||
.build();
|
||||
Reference in New Issue
Block a user