47eb9502f8
Wire the mail/identity stack to real Stalwart/Authentik/OCIS provisioning, replacing the mocked Domains and Users pages. Domains (customer-admin): - StalwartClient: real JMAP management (v0.16 dropped REST) — create/list/delete email domains via x:Domain at the internal http://stalwart:8080 listener; DKIM auto-generated; the records to publish are read from the domain's dnsZoneFile. Gated by STALWART_PROVISIONING_ENABLED. - New Domain collection + DomainsModule: add/list/recheck/set-DMARC/remove, tenant-membership-gated and audited. - DnsVerifierService: verifies MX/SPF/DKIM/DMARC/ownership against a public resolver (1.1.1.1/8.8.8.8) and diffs them against the expected records. - Remove is guarded: refuses while accounts/aliases/mailing lists still use the domain (via Stalwart referential integrity). - Domains page + add wizard on real data; sidebar badge counts domains needing attention. Users & groups (customer-admin): - Create a member provisioned across Authentik SSO, a Stalwart mailbox on the tenant's primary domain, and OCIS — returning a one-time password. - Lifecycle: suspend/resume (Authentik is_active + freeze the mailbox via account permissions, original password preserved), force-logout (terminate sessions, filtered client-side so it can never end other users' sessions), reset password (new one-time password on SSO + mailbox), and remove (tear down mailbox + SSO identity + OCIS + doc; mailbox-in-use aware for multi-tenant users). Self-suspend / self-force-logout are blocked. Infra: point platform-api at the internal Stalwart listener; document the new STALWART_/provisioning vars in .env.example.
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import { Module } from '@nestjs/common'
|
|
import { ConfigModule } from '@nestjs/config'
|
|
import { MongooseModule } from '@nestjs/mongoose'
|
|
import { AuditModule } from './audit/audit.module.js'
|
|
import { AuthModule } from './auth/auth.module.js'
|
|
import { BillingModule } from './billing/billing.module.js'
|
|
import { DomainsModule } from './domains/domains.module.js'
|
|
import { FlagsModule } from './flags/flags.module.js'
|
|
import { HealthModule } from './health/health.module.js'
|
|
import { IngestModule } from './ingest/ingest.module.js'
|
|
import { MeModule } from './me/me.module.js'
|
|
import { PartnersModule } from './partners/partners.module.js'
|
|
import { PricesModule } from './prices/prices.module.js'
|
|
import { SeedModule } from './seed/seed.module.js'
|
|
import { SubscriptionsModule } from './subscriptions/subscriptions.module.js'
|
|
import { TenantsModule } from './tenants/tenants.module.js'
|
|
import { UsersModule } from './users/users.module.js'
|
|
|
|
@Module({
|
|
imports: [
|
|
ConfigModule.forRoot({ isGlobal: true }),
|
|
MongooseModule.forRoot(
|
|
process.env.MONGODB_URI ?? 'mongodb://localhost:27017/dezky',
|
|
),
|
|
AuthModule,
|
|
AuditModule,
|
|
HealthModule,
|
|
TenantsModule,
|
|
DomainsModule,
|
|
PartnersModule,
|
|
UsersModule,
|
|
MeModule,
|
|
SubscriptionsModule,
|
|
PricesModule,
|
|
FlagsModule,
|
|
BillingModule,
|
|
IngestModule,
|
|
SeedModule,
|
|
],
|
|
})
|
|
export class AppModule {}
|