Passa al contenuto principale

Architettura e moduli

Il quadro d'insieme

formandopercorsi-backend è l'intero backend: un'API REST Yii2 (PHP) autenticata via JWT che serve i client di famiglie/studenti/insegnanti e il pannello admin. Non esiste un backend-for-frontend o un gateway separato — routing, logica di business, persistenza, job asincroni e integrazioni con terze parti (Stripe, fatturazione elettronica Acube, Google Calendar, WhatsApp) vivono tutti qui. I frontend sono repository separati.

Lo stesso codice viene distribuito su tre ambienti, ciascuno sul proprio sottodominio: developdev.api.formandopercorsi.com, pre-produzione → preprod.api.formandopercorsi.com, main/produzione → api.formandopercorsi.com. L'ambiente è determinato da YII_ENV/YII_DEBUG, non da un fork o da branch diversi.

Nessuno dei tre deploy è automatico. Il rilascio è in due passi separati:

  1. Push su develop/main, poi lancio manuale (pulsante "Run workflow") della ECR Deployment Workflow in GitHub Actions sul repository formandopercorsi-backend: costruisce e pubblica su ECR le immagini Docker per quel branch (rest, queue, cron).
  2. Rollout effettivo sui servizi ECS tramite ./fpc deploy dal repository FormandoPercorsi/aws — se la release include nuove migrazioni, vanno eseguite prima (./fpc run -- php yii migrate) e solo dopo si esegue il deploy dei servizi rest+queue. Procedura completa in quel repository, docs/how-to/deploy/backend.md.

Il percorso di una richiesta

  1. La rotta viene abbinata in config/routes.php → smistata a modules/api/controllers/*Controller.
  2. Il controller estende RestBaseController (autenticazione JWT + CORS + controllo accessi).
  3. L'input viene validato da un form model (modules/api/models/) che estende BaseForm.
  4. La logica di business è delegata a un service (services/<dominio>/).
  5. La risposta viene serializzata da un DTO (models/dto/), assemblato da un assembler (assemblers/).

I livelli principali

LivelloDoveResponsabilità
Controllermodules/api/controllers/Solo azioni REST, nessuna logica di business. Restituiscono array grezzi o DTO.
Form modelmodules/api/models/Solo validazione della richiesta; estendono BaseForm. Separati dai model ActiveRecord.
Model ActiveRecordmodels/Entità del database; classe base app\models\base\Record (aggiunge TimestampBehavior + BlameableBehavior, non soft-delete).
DTOmodels/dto/Forme di risposta serializzabili; implementano JsonSerializable. Creati via <Entità>Assembler::toArray($entità, $detailLevel).
Serviceservices/Logica di business, organizzata per dominio (lesson/, payments/, availability/, invoice/, credit/, referral/, ...).
Assemblerassemblers/Mappano i model ActiveRecord ai DTO in base al ruolo/livello di dettaglio di chi guarda.
Comandi consolecommands/Job asincroni; estendono AsyncBaseController. Invocati via php yii <comando-kebab>/<azione> o accodati sulla coda basata su database.
Helperhelpers/Utility stateless. EmailHelper::sendEmail() è l'unico punto d'ingresso per tutte le email in uscita.
Validatorvalidators/Validatori custom che estendono yii\validators\Validator, specchiando la struttura a domini di form/service.

Soft delete

Non è gestito genericamente dalla classe base: è una convenzione per-model tramite una colonna status con costanti definite dal model stesso.

  • User usa interi: STATUS_DELETED = 0, STATUS_INACTIVE = 9, STATUS_ACTIVE = 10.
  • La maggior parte degli altri model (Lesson, Availability, AvailabilityGroup, LessonOrder, ...) usa stringhe: STATUS_DELETED = 'deleted', STATUS_ACTIVE = 'active', ...
  • Lesson registra anche il motivo della cancellazione tramite una colonna deletion_reason più deleted_by_user_id; va sempre cancellata tramite Lesson::markDeleted($reason, $status, $actorId), mai assegnando status a mano.

Aggiungere un nuovo endpoint

  1. Form model in modules/api/models/<dominio>/ che estende BaseForm.
  2. Azione nel controller modules/api/controllers/<Dominio>Controller con attributo #[OA\Post(...)] (o simile) — questo è ciò che genera la API Reference.
  3. Rotta in config/routes.php, raggruppata per dominio seguendo i commenti già presenti.

Job asincroni

Yii::$app->queue->push(new SomeJob($data)) da un controller. La coda è basata su database (tabella queue); il listener (php yii queue/listen) gira come processo in background nel container Docker insieme ad Apache.

Moduli per dominio (services/<dominio>/)

DominioCosa contiene
availabilityAvailability → Effective Availability → Consecutive Availability, ranking insegnanti. Vedi Disponibilità e Ranking insegnanti.
creditSaldo/ledger crediti famiglia. Vedi Referral & Crediti.
insuranceAssicurazione lezione, sinistri, compenso insegnante. Vedi Assicurazione.
invoiceFatturazione elettronica (Acube/SDI) e fatture/ricevute esterne. Vedi Pagamenti & Fatturazione.
lessonCreazione, modifica, cancellazione lezione; tipi di notifica in lesson/notification/.
lessonPriceCalculationPricing band e calcolo del costo lezione. Vedi Pagamenti & Fatturazione.
mailerOrchestrazione email in uscita (wrappa EmailHelper).
notificationServizi di notifica in-app per evento di dominio. Vedi Notifiche.
paymentsElaborazione payout mensile/giornaliero, ledger, Stripe. Vedi Pagamenti & Fatturazione.
policyNotifiche di aggiornamento termini e condizioni.
promotionSconti/coupon promozionali.
referralLink e inviti referral. Vedi Referral & Crediti.
schoolCatalogo scuole, passaggio di classe annuale.
subject / subtopic / topicTassonomia del curriculum.
teacherApplicationCandidature di nuovi insegnanti.
track / trackingMetricsTracking eventi e sistema di aggregazione metriche.
userServizi account utente/famiglia/insegnante.
googlecalendarSincronizzazione Google Calendar/Meet per le lezioni — interamente server-to-server, il frontend non è coinvolto.

Struttura del repository

modules/api/ # controller, form model, service scoped all'API
services/ # logica di business per dominio
assemblers/ # mapping ActiveRecord -> DTO in base al ruolo/dettaglio
models/ # entità ActiveRecord + models/dto/ per le risposte
validators/ # validatori custom, specchiano la struttura service/form
commands/ # comandi console per job asincroni
helpers/ # utility stateless (EmailHelper, ecc.)
exceptions/ # eccezioni di dominio custom
mail/ # template email
migrations/ # migrazioni database (Yii2 migrate)
config/ # config web/console, routes, params (incl. credenziali terze parti)
tests/ # Codeception: unit/ e functional/
docs/ # script di generazione della documentazione OpenAPI