Multi-tenant event manager built with NestJS 10, Prisma ORM, and PostgreSQL.
- Multi-tenant: Ogni client ha accesso solo ai propri eventi tramite token
- Gestione Partecipanti: Aggiungi e rimuovi partecipanti agli eventi
- Eventi Ricorrenti: Crea eventi che si ripetono settimanalmente/mensilmente/annualmente
- RRULE Support: Utilizza lo standard RFC 5545 per le ricorrenze
- Auto Cleanup: Pulizia automatica degli eventi passati
pnpm installcp .env.example .env
# Modifica .env con i tuoi dati di connessione PostgreSQLpnpm prisma:migrate
pnpm prisma:generatepnpm start:devL'app sarà disponibile su http://localhost:3000
Nessun endpoint pubblico per i client. Li crea un SUPER_ADMIN da Meridian → Gatherly → Clients
(/admin/clients, Bastion user JWT con ruolo SUPER_ADMIN). Ogni client è legato a un tenantId Bastion.
Tutti gli endpoint degli eventi richiedono un service-client JWT Bastion: Authorization: Bearer <jwt>
POST /events
Headers: Authorization: Bearer <jwt>
Content-Type: application/json
{
"title": "Weekly Team Meeting",
"description": "Discussione settimanale",
"authorId": "user123",
"authorName": "John Doe",
"startTime": "2026-03-05T14:00:00Z",
"recurrenceRule": "FREQ=WEEKLY;BYDAY=WE;INTERVAL=1"
}Risposta:
{
"id": "cluxxxxxx",
"title": "Weekly Team Meeting",
"description": "Discussione settimanale",
"clientId": "cluxxxxxx",
"authorId": "user123",
"authorName": "John Doe",
"startTime": "2026-03-05T14:00:00Z",
"isRecurring": true,
"recurrenceRule": "FREQ=WEEKLY;BYDAY=WE;INTERVAL=1",
"participants": [],
"createdAt": "2026-02-26T10:00:00Z",
"updatedAt": "2026-02-26T10:00:00Z"
}GET /events
Headers: Authorization: Bearer <jwt>GET /events/:eventId
Headers: Authorization: Bearer <jwt>POST /events/:eventId/participants
Headers: Authorization: Bearer <jwt>
Content-Type: application/json
{
"userId": "user456",
"userName": "Jane Smith"
}DELETE /events/:eventId/participants/:userId
Headers: Authorization: Bearer <jwt>FREQ=WEEKLY;BYDAY=MO
FREQ=WEEKLY;BYDAY=MO,TH;INTERVAL=2
FREQ=MONTHLY;BYMONTHDAY=1
FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR
Client (1) ---< (M) Event
Event (1) ---< (M) Participant
Event (Parent) ---< (Child) Event (per ricorrenze)
- Il chiamante ottiene un service-client JWT da Bastion (
POST /auth/client) e lo invia comeAuthorization: Bearer <jwt> BastionJwtGuard(globale) verifica la firma RS256 via JWKS e risolve il client attivo legato altenantIddel token- Request viene arricchita con
req.clientcontenente i dati del client - Tutti i servizi filtrano i dati per
clientId
Le route /admin/* usano invece un Bastion user JWT, verificato dai guard dei singoli controller.
- Quando crei un evento ricorrente, viene creato l'evento genitore
- Automaticamente vengono generate 52 istanze (1 anno) dell'evento
- Ogni istanza ha
parentEventIdche punta all'evento genitore - Un cron job giornaliero (ore 2:00) elimina le istanze scadute
# Avvia in modalità development con watch
pnpm start:dev
# Build per production
pnpm build
# Esegui migrazioni Prisma
pnpm prisma:migrate
# Genera Prisma Client
pnpm prisma:generatesrc/
├── main.ts # Entry point
├── configs/ # Validazione env (config.validation.ts)
├── guards/ # AdminThrottlerGuard
└── modules/
├── app/ # AppModule
├── bastion/ # JWKS, BastionJwtGuard, guard admin
├── admin/ # /admin/* (Meridian)
├── clients/ # ClientService (niente controller)
├── events/ # Eventi, partecipanti, ricorrenze
├── categories/
├── tags/
├── webhook/ # Outbox + delivery webhook
└── prisma/ # PrismaService (@Global)
pnpm prisma:generateVerifica che:
- PostgreSQL sia in esecuzione
- L'URL di connessione in
.envsia corretta - I permessi del database siano corretti
Assicurati che:
- Esista un client attivo per il
tenantIddel JWT (creato da Meridian → Gatherly → Clients) - Il JWT sia un service-client token Bastion valido, inviato come
Authorization: Bearer <jwt>
MIT
