Première moitié de la feature marque blanche : la machinerie complète qui permet à un compte Business d'envoyer ses emails de relance avec son propre logo, ses propres couleurs et son nom comme expéditeur, à la place du branding Rubis. Architecture : - Nouvelle colonne JSONB `organizations.brand_settings` (12 tokens customisables : logo, senderName, et 10 couleurs — primary, banner, body bg, card bg, text, text muted, border, link, button text). Null = palette Rubis intacte. Validation hex stricte (#RRGGBB). - Service `#services/brand` avec `resolveBrandTokens(org)` qui merge defaults + overrides en respectant le plan (couleurs/logo = Business only ; senderName = cascade pour tous les plans). Mergeurs avec sémantique "null = reset au default sur ce champ précis" pour les patches partiels. - Service mutualisé `#services/media_storage` qui remplace l'ancien `blog_uploads.ts`. Scopes `blog` (4 MB, jpg/png/webp) et `brand-logo` (1 MB, + svg accepté). Cleanup automatique du logo précédent lors d'un remplacement (pas de versioning — la conv produit est "on écrase"). - Controller `BrandController` (5 endpoints) + middleware `AssertBusinessPlanMiddleware` qui throw 403 `business_plan_required` (code matché par le SPA pour l'upsell card). - Refactor des 3 templates mail (relance, payment thanks, checkin) + layout commun pour accepter `tokens: BrandTokens` en prop. Le dispatcher résout les tokens per-org pour relance + remerciement (= user → client, branded), et passe `DEFAULT_BRAND` au checkin (= Rubis → user, toujours Rubis-branded). - Routes publiques pour le logo : `/api/v1/uploads/brand-logos/:filename` (sans auth, cache immutable, X-Content-Type-Options: nosniff pour les SVG). UI self-service arrive dans la prochaine version (v1.12.0). En attendant, un compte Business peut être configuré via Bruno / API directe. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
21 lines
816 B
TypeScript
21 lines
816 B
TypeScript
import { OrganizationSchema } from '#database/schema'
|
|
import { column, hasMany } from '@adonisjs/lucid/orm'
|
|
import type { HasMany } from '@adonisjs/lucid/types/relations'
|
|
import User from '#models/user'
|
|
import type { BrandSettings } from '#services/brand'
|
|
|
|
export default class Organization extends OrganizationSchema {
|
|
/**
|
|
* Settings de marque blanche (plan Business) — JSONB, null = palette
|
|
* Rubis par défaut. Cf. `#services/brand` pour la résolution et la
|
|
* validation. Cette déclaration manuelle existe en attendant que
|
|
* `schema.ts` soit régénéré par `node ace migration:run` (cf. migration
|
|
* `1778400000000_add_brand_settings_to_organizations_table.ts`).
|
|
*/
|
|
@column()
|
|
declare brandSettings: BrandSettings | null
|
|
|
|
@hasMany(() => User)
|
|
declare users: HasMany<typeof User>
|
|
}
|