0e1d2fb0d1
Add a lazy/guarded Stripe client (boots without keys), Invoice/Payout schemas, per-currency Price.stripePriceIds, and a BillingService deriving partner/platform summaries, invoices and a partner-cut payout ledger. Partner and operator billing controllers plus a signature-verified Stripe webhook (Fastify raw body). Frontend: partner and operator billing pages and the operator tenant billing/audit tabs on real data. Gated behind new_billing_engine and BILLING_STRIPE_ENABLED; live money paths stay off until keys are set.
43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
// Dezky platform API — Entry point.
|
|
// Owns the platform control plane: tenants, partners, users, subscriptions,
|
|
// plus the provisioning orchestration (Authentik / Stalwart / OCIS).
|
|
|
|
import { ValidationPipe } from '@nestjs/common'
|
|
import { NestFactory } from '@nestjs/core'
|
|
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'
|
|
import { AppModule } from './app.module.js'
|
|
|
|
async function bootstrap() {
|
|
const app = await NestFactory.create<NestFastifyApplication>(
|
|
AppModule,
|
|
new FastifyAdapter({ logger: true }),
|
|
// rawBody exposes req.rawBody (Buffer) — needed for Stripe webhook
|
|
// signature verification, which must hash the exact bytes Stripe sent.
|
|
{ rawBody: true },
|
|
)
|
|
|
|
app.enableCors({
|
|
origin: /^https:\/\/([a-z0-9-]+\.)?dezky\.local$/,
|
|
credentials: true,
|
|
})
|
|
|
|
app.useGlobalPipes(
|
|
new ValidationPipe({
|
|
whitelist: true,
|
|
forbidNonWhitelisted: true,
|
|
transform: true,
|
|
transformOptions: { enableImplicitConversion: true },
|
|
}),
|
|
)
|
|
|
|
const port = Number(process.env.PORT ?? 3001)
|
|
await app.listen(port, '0.0.0.0')
|
|
|
|
console.log(`platform-api listening on http://0.0.0.0:${port}`)
|
|
}
|
|
|
|
bootstrap().catch((err) => {
|
|
console.error('Failed to start platform-api', err)
|
|
process.exit(1)
|
|
})
|