Migrations : - plans (uuid id, organization_id FK CASCADE, slug nullable, name, description, is_default). Unique (organization_id, slug) — un slug max par org. - plan_steps (uuid id, plan_id FK CASCADE, order, offset_days, tone ENUM PG natif, subject, body, requires_manual_validation). Schema rules : override du tone (introspection PG → 'any', on précise l'union). Modèles Plan (belongsTo Organization, hasMany PlanStep) et PlanStep (belongsTo Plan). Décision : plans dupliqués par organisation au signup (pas de table globale partagée). Permet l'édition isolée par org sans toucher aux templates des autres tenants. Le service `provisionDefaultPlans(orgId, trx)` est idempotent et appelé depuis NewAccountController dans la transaction de création. Source de vérité des 4 plans (Standard B2B, Rapide, Patient, Ferme) dans app/services/default_plans.ts — alignée sur apps/web/src/mocks/seed.ts. Endpoints : - GET /plans : liste enrichie avec usageCount (à 0 tant qu'Invoice n'est pas câblé). - GET /plans/:slug : détail (lookup par slug pour URL stable côté SPA). - PATCH /plans/:slug : édition partielle. Les steps sont remplacés en bloc dans une transaction (pas de diff fin id-par-id, plus simple et prévisible). POST plan custom = V2 (cf. backend.md §5.5).
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
/*
|
|
|--------------------------------------------------------------------------
|
|
| Routes file
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Toutes les routes sont sous /api/v1/. Les groupes auth et account sont
|
|
| importés depuis le contrôleur généré par Tuyau pour garantir le contrat
|
|
| client typé (cf. docs/tech/backend.md §8).
|
|
|
|
|
*/
|
|
|
|
import { middleware } from '#start/kernel'
|
|
import router from '@adonisjs/core/services/router'
|
|
import { controllers } from '#generated/controllers'
|
|
|
|
router.get('/', () => {
|
|
return { hello: 'world' }
|
|
})
|
|
|
|
router
|
|
.group(() => {
|
|
/**
|
|
* Auth — public.
|
|
*/
|
|
router
|
|
.group(() => {
|
|
router.post('signup', [controllers.NewAccount, 'store']).as('signup')
|
|
router.post('login', [controllers.AccessTokens, 'store']).as('login')
|
|
})
|
|
.prefix('auth')
|
|
.as('auth')
|
|
|
|
/**
|
|
* Compte courant — auth requise.
|
|
*/
|
|
router
|
|
.group(() => {
|
|
router.get('profile', [controllers.Profile, 'show']).as('profile.show')
|
|
router.patch('profile', [controllers.Profile, 'update']).as('profile.update')
|
|
router.post('logout', [controllers.AccessTokens, 'destroy']).as('logout')
|
|
})
|
|
.prefix('account')
|
|
.as('account')
|
|
.use(middleware.auth())
|
|
|
|
/**
|
|
* Organisation rattachée à l'utilisateur courant — auth requise.
|
|
*/
|
|
router
|
|
.group(() => {
|
|
router.get('me', [controllers.Organizations, 'show']).as('show')
|
|
router.patch('me', [controllers.Organizations, 'update']).as('update')
|
|
})
|
|
.prefix('organizations')
|
|
.as('organizations')
|
|
.use(middleware.auth())
|
|
|
|
/**
|
|
* Clients — auth requise, scope par organization de l'utilisateur courant.
|
|
*/
|
|
router
|
|
.group(() => {
|
|
router.get('', [controllers.Clients, 'index']).as('index')
|
|
router.post('', [controllers.Clients, 'store']).as('store')
|
|
router.get(':id', [controllers.Clients, 'show']).as('show').where('id', router.matchers.uuid())
|
|
router.patch(':id', [controllers.Clients, 'update']).as('update').where('id', router.matchers.uuid())
|
|
})
|
|
.prefix('clients')
|
|
.as('clients')
|
|
.use(middleware.auth())
|
|
|
|
/**
|
|
* Plans — auth requise. Lookup par slug (stable et lisible :
|
|
* /parametres/plans/standard-30j). POST plan custom = V2.
|
|
*/
|
|
router
|
|
.group(() => {
|
|
router.get('', [controllers.Plans, 'index']).as('index')
|
|
router.get(':slug', [controllers.Plans, 'show']).as('show')
|
|
router.patch(':slug', [controllers.Plans, 'update']).as('update')
|
|
})
|
|
.prefix('plans')
|
|
.as('plans')
|
|
.use(middleware.auth())
|
|
})
|
|
.prefix('/api/v1')
|