feat(email): update architecture docs and add seed migration

Email system updates:
- Update ARCHITECTURE.md with latest design decisions
- Update backend package.json configuration
- Enhance app.module.ts with new providers
- Add migration for seeding user email templates
- Update plugin-messaging tsconfig.json

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Quinn Ftw 2025-12-28 21:36:20 -08:00
parent 6c2d89a099
commit 8fc52b7c6a
6 changed files with 129 additions and 5 deletions

View file

@ -793,10 +793,12 @@ Platform-level emails:
- [x] Outbound message-to-email conversion
- [x] Reply-to token generation/parsing
### Phase 6: User Emails (PLANNED)
- [ ] Implement user email templates (welcome, verification, password)
- [ ] Integrate with identity feature
- [ ] Testing and validation
### Phase 6: User Emails ✅ COMPLETE
- [x] Implement user email templates (welcome, verification, password-reset, account-alert)
- [x] UsersEmailService with 6 methods (welcome, verification, password reset, password changed, account locked, login alert)
- [x] Template rendering with base layout
- [ ] Template seeding script (database population pending)
- [ ] Integration with identity feature (pending)
### Phase 7: Order Emails (PLANNED)
- [ ] Implement order email templates

View file

@ -17,6 +17,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@lilith/registry-integration": "workspace:*",
"@lilith/types": "workspace:*",
"@nestjs/bull": "^10.1.0",
"@nestjs/common": "^10.0.0",

View file

@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { BullModule } from '@nestjs/bull'
import { TypeOrmModule } from '@nestjs/typeorm'
import { RegistryModule } from '@lilith/registry-integration'
import { CoreModule } from './core/core.module'
import { AddressesModule } from './addresses/addresses.module'
@ -50,6 +51,22 @@ import { HealthController } from './health.controller'
}),
}),
// Service Registry (auto-registration)
RegistryModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
name: 'email',
type: 'backend',
port: configService.get('PORT', 3011),
healthEndpoint: '/health',
metadata: {
description: 'Centralized email service for Lilith Platform',
version: '1.0.0',
},
}),
}),
// Feature modules
CoreModule,
AddressesModule,

View file

@ -0,0 +1,103 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
/**
* Seeds the email_templates table with user email templates.
* These templates reference .hbs files in templates/users/ directory.
*/
export class SeedUserEmailTemplates1735400007 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// Seed user email templates
await queryRunner.query(`
INSERT INTO email_templates (id, name, category, subject_template, html_template, text_template, variables, is_active, updated_at)
VALUES
-- Welcome email
(
uuid_generate_v4(),
'welcome',
'users',
'Welcome to Lilith Platform, {{name}}!',
'{{> users/welcome}}',
'Welcome to Lilith Platform! Visit {{dashboardUrl}} to get started.',
'{"userName": {"description": "User display name", "required": false}, "userEmail": {"description": "User email address", "required": true}, "accountType": {"description": "Account type (creator, subscriber)", "required": false}, "joinDate": {"description": "Registration date", "required": false}, "dashboardUrl": {"description": "Dashboard URL", "required": true}, "guideUrl": {"description": "Getting started guide URL", "required": false}, "helpCenterUrl": {"description": "Help center URL", "required": false}, "supportUrl": {"description": "Support page URL", "required": false}}'::jsonb,
true,
now()
),
-- Email verification
(
uuid_generate_v4(),
'email-verification',
'users',
'Verify your email address',
'{{> users/verification}}',
'Please verify your email by clicking: {{verificationUrl}}. Link expires in {{expiresIn}}.',
'{"userName": {"description": "User display name", "required": false}, "verificationUrl": {"description": "Email verification URL", "required": true}, "expiresIn": {"description": "Expiration time (e.g. 24 hours)", "required": true}}'::jsonb,
true,
now()
),
-- Password reset
(
uuid_generate_v4(),
'password-reset',
'users',
'Reset your password',
'{{> users/password-reset}}',
'Reset your password by clicking: {{resetUrl}}. Link expires in {{expiresIn}}.',
'{"userName": {"description": "User display name", "required": false}, "resetUrl": {"description": "Password reset URL", "required": true}, "expiresIn": {"description": "Expiration time (e.g. 1 hour)", "required": true}}'::jsonb,
true,
now()
),
-- Password changed confirmation
(
uuid_generate_v4(),
'password-changed',
'users',
'Your password has been changed',
'{{> users/account-alert}}',
'Your password was changed on {{changedAt}}. If this was not you, contact support immediately.',
'{"userName": {"description": "User display name", "required": false}, "changedAt": {"description": "ISO timestamp of change", "required": true}, "supportUrl": {"description": "Support page URL", "required": true}}'::jsonb,
true,
now()
),
-- Account locked
(
uuid_generate_v4(),
'account-locked',
'users',
'Your account has been locked',
'{{> users/account-alert}}',
'Your account has been locked due to {{reason}}. Visit {{unlockUrl}} to unlock.',
'{"userName": {"description": "User display name", "required": false}, "reason": {"description": "Lock reason", "required": false}, "unlockUrl": {"description": "Account unlock URL", "required": false}, "supportUrl": {"description": "Support page URL", "required": true}}'::jsonb,
true,
now()
),
-- Login alert
(
uuid_generate_v4(),
'login-alert',
'users',
'New login to your account',
'{{> users/account-alert}}',
'New login detected from {{device}} in {{location}} at {{loginTime}}.',
'{"userName": {"description": "User display name", "required": false}, "device": {"description": "Device name/type", "required": false}, "location": {"description": "Geographic location", "required": false}, "ipAddress": {"description": "IP address", "required": false}, "loginTime": {"description": "ISO timestamp of login", "required": true}, "securityUrl": {"description": "Security settings URL", "required": true}}'::jsonb,
true,
now()
)
ON CONFLICT (name) DO NOTHING;
`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
// Remove seeded templates
await queryRunner.query(`
DELETE FROM email_templates
WHERE name IN (
'welcome',
'email-verification',
'password-reset',
'password-changed',
'account-locked',
'login-alert'
);
`)
}
}

View file

@ -17,3 +17,4 @@ export { CreateEmailPreferences1735400003 } from './1735400003-CreateEmailPrefer
export { CreateEmailAddresses1735400004 } from './1735400004-CreateEmailAddresses'
export { CreateEmailAliases1735400005 } from './1735400005-CreateEmailAliases'
export { CreateEmailThreadMappings1735400006 } from './1735400006-CreateEmailThreadMappings'
export { SeedUserEmailTemplates1735400007 } from './1735400007-SeedUserEmailTemplates'

View file

@ -1,5 +1,5 @@
{
"extends": "../../../@packages/@core/config/tsconfig.base.json",
"extends": "@transquinnftw/configs/typescript/nestjs.json",
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",