Esamina questo modello per un LMS, pensato per Directus. Ci sono problemi di logica, campi duplicati, imprecisioni logiche, etc.? E' per un MVP da fare in 3 mesi.

- People -> Users (M2O)*
- People <- Participations -> Courses (M2M con alias su entrambi)
- Participations -> LMS roles (M2O)
- People <- Enrollments -> Courses (M2M con alias su entrambi)
- People <- People affiliations -> Units (M2M con alias su entrambi)
- Units -> Units (O2M, ricorsivo per la relazione parent_unit)
- Courses <- Courses affiliations -> Units (M2M con alias su entrambi)
- Courses <- Custom eligibility -> Units (M2M con alias su Courses)
- Courses -> Modules (O2M)
- Modules -> Lessons (O2M)
- Lessons <- Lesson materials -> Materials (M2M con alias su entrambi)
- Lessons -> Activities (O2M)
- Activities -> Quizzes (O2M)*
- Activities -> Assignments (O2M)*
- Quizzes -> Quiz questions (O2M)
- Quiz questions -> Quiz answers (O2M)
- Quiz attempts -> People (M2O)
- Quiz attempts -> Quizzes (M2O)
- Quiz attempts -> Activities (M2O)
- Quiz attempts -> Quiz responses (O2M)
- People <- Progress -> Lessons (M2M con alias su entrambi)
- Progress -> Activities (M2O)
- People <- Certificates -> Courses (M2M con alias su entrambi)
- Courses <- Course categories -> Categories (M2M con alias su entrambi)
- Courses -> Course settings (O2M)*
- Course settings -> Lessons (O2M)
- People -> Notifications (O2M)
- Assignments <- Assignment submissions -> People (M2M con alias su Assignments)
- Assignment submissions -> Activities (M2O)
- Activities -> Activity groups (O2M)
- Activity groups <- Activity group members -> People (M2M con alias su Activity groups)
- Activities <- Activity assignments -> People (M2M con alias su Activities)
- Grades -> People (M2O, per la relazione student_id)
- Grades -> People (M2O, per la relazione grader_id)
- Courses -> Grades (O2M)
- Activities -> Grades (O2M)
- Quiz attempts -> Grades (O2M)
- Assignment submissions -> Grades (O2M)
- Grades -> Grades (O2M, ricorsivo per la relazione previous_grade)

Note:
- "People -> Users (M2O)" è in realtà una relazione O2O, con campo "user" in "People" settato come "unique".
- "Quiz attempts -> People (M2O)" e "Quiz attempts -> Quizzes (M2O)" si traducono sostanzialmente in "People <- Quiz attempts -> Quizzes" (M2M senza alias)
- "Courses -> Course settings (O2M)" è in realtà una relazione O2O, con campo "course" in "Course settings" settato come "unique".
- "Activities -> Quizzes (O2M)" è in realtà una relazione O2O, con campo "activity" in "Quizzes" settato come "unique".
- "Activities -> Assignments (O2M)" è in realtà una relazione O2O, con campo "activity" in "Assignments" settato come "unique".
## Users (Collezione nativa di Directus)
- person (O2O relazione con People: M2O con valore Unique in Directus)

## People
# Asterisco: readonly field only if data_source = internal_api
# Versione Preview: Sì
- id (UUID, primary key)
- first_name (string)*
- last_name (string)*
- email (string)*
- bio (text, nullable)
- profile_image (file, nullable)
- eui_id (string, nullable)*
- data_source (string: "internal_api", "external_api", "manual")
- course_roles (M2M alias, relazione con Courses)
- units (M2M alias, relazione con Units)* -> Chiamare affiliations?
- enrollments (M2M alias, relazione con Courses)
- progress (M2M alias, relazione con Lessons)
- certificates (M2M alias, relazione con Courses)
- tasks (M2M alias, relazione con Courses)
- notifications (O2M alias, relazione con Notifications)
- group_memberships (M2M alias, relazione con Assignment group members) -> forse meglio di no.
- settings (O2M alias, relazione con Course settings)
- IsStudent (boolean)
- IsProfessor (boolean)
- IsAssistant (boolean)
- IsStaff (boolean)
- IsFellow (boolean)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Roles (LMS_Roles)
# Versione Preview: Sì
- id (UUID, primary key)
- name (string)
- lms_permissions (json)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Participations (Collezione junction)
# Vincolo di unicità user – course per avere più di un ruolo per corso
# Versione Preview: Sì
- id (UUID, primary key)
- user (M2O relazione con People)
- role (M2O relazione con Roles) – Da creare manualmente sulla tabella di giunzione
- course (M2O relazione con Courses)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Units
# Versione Preview: Sì
- id (UUID, primary key)
- name (string)
- type (enum: "academic_unit", "service_unit")
- parent_unit (M2O, relazione con Units)
- sub_units (O2M alias, relazione inversa con Units) – Creando O2M sub_unit creerà anche parent_unit.
- people (M2M alias, relazione con People)
- courses (M2M alias, relazione con Courses)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## People affiliations (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key)
- person (M2O relazione con People)
- unit (M2O relazione con Units)
-  role (string)
- is_primary (boolean)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Courses
Per Algolia. Ci sarà pagina corsi solo attivi, e nel caso pagina archivio. I corsi completati o self paced che non sono più attivi saranno sempre visibili nella pagina personale di chi li ha seguiti o guidati.
Regolare fuso su Directus.
Per mantenere certificati etc., devono restare sempre pubblicati, senza più possibilità di enrollare/rifare.
Il booleano is_active deve determinare la presenza o meno nel listing?
Pensare se ha senso enrollment open a corso iniziato: se sì ripensare course_status; Come gestire Algolia?
# Versione Preview: Sì
- id (UUID, primary key)
- title (string)
- slug (string, unique, calculated on title)
- course_code (string, unique)
- description (text)
- contact (text)
- language (string or enum) 
- estimated_workload (integer)
- prerequisites (text, nullable)
- learning_objectives (text)
- cover_image (file, nullable) -> Implementare AI generated
- course_format (enum: "scheduled", "self_paced")
- course_status (enum: "upcoming", "open_for_enrollment", "enrollments_closed", "ongoing", "completed", "self_paced") -> readonly & invisible (client), gestito da cron che aggiorna sistematicamente.
- start_date (date, nullable) -> Valido solo per scheduled, obbligatorio.
- end_date (date, nullable) -> Valido solo per scheduled, obbligatorio.
- enrollment_start (date, nullable) -> Valido solo per scheduled, obbligatorio.
- enrollment_end (date, nullable) -> Valido solo per scheduled, obbligatorio.
- max_completion_days_after_end (integer, nullable) -> Valido solo per scheduled. Se è null vale end_date.
- completion_deadline_date: date (nullable, calcolato, presentation field) -> su end_date, max_completion.
- sort_date (date, nullable) -> Featured? Pinned? Booleani 
- is_visible (boolean, default: true) -> relative al listing.
- is_password_protected (boolean, default: false)
- access_password (string, nullable, required if is_password_protected is true) -> Da criptare?
- is_cancelled (boolean, default: false, applicable only to scheduled courses)
- is_active (boolean, default: true) -> Editabile per self_paced, readonly computed invisibile per scheduled = (current_date between start_date and end_date) AND NOT is_cancelled. Tasto “deactivate” da mettere.
- enrollment_active: (Boolean, computed, presentation field -> non salvato nel database)
- eligibility (enum: "everyone", "academic ", "staff ", "course_specific", "custom") -> course_specific = le unità a cui il Corso è afferente, cioè campo units, custom = le unità specificate in custom_eligibility, che metterei dopo.
- max_students (integer, nullable)
- ects_credits (decimal)
- level (string: "beginner", "intermediate", "advanced")
- delivery_mode (enum: "online", "residential", "hybrid", "blended")
- use_modules (boolean, default: true) ??? Spostare a livello di modulo?
- custom_eligibility (M2M relazione con Units, applicabile se access_type è "unit_specific")
- units (O2M alias, relazione con Units) -> Chiamare affiliations?
- modules (O2M alias, relazione con Modules)
- enrollments (M2M alias, relazione con People)
- categories (M2M alias, relazione con Categories)
- roles (M2M alias, relazione inversa con People)
- certificates (O2M alias, relazione con Certificates)
- grades (O2M alias, relazione con Grades)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Course settings
# Versione Preview: Sì
- id (UUID, primary key) 
- course (M2O relazione con Courses, unique) 
- required_lessons (O2M alias, relazione con Lessons, nullable) ->  solo per criteria: specific_lessons (se possibile filtrare per corso in Directus)
- certificate_enabled (boolean) 
- grading_method (enum: "completion_based", "continuous_assessment", "manual_grade") -> che si potrebbero rinominare “completion”, “score”, “manual”.
- grade_format (enum: "pass_fail", "numeric", "letter") -> non per completion_based
- completion_criteria (enum: "all_lessons", "specific_lessons") -> relato a required_lessons per specific_lessons. | Non ha nulla a vedere col voto.
- progression_type (string: "sequential", "open") -> default sequential.
- passing_grade (integer): Vale per activities e corso
- grade_range (integer): 100 = 0-100, etc. Vale per activities e corso
- grade_calculation (string: "weighted", "average") -> no per grading_method:completion_based
- grade_weights (group) -> solo se grade_calculation: weighted | no per grading_method:completion_based
•	quizzes (group): 
o	weight (float)
o	drop_lowest (boolean)
•	assignments (group): 
o	weight (float)
o	drop_lowest (boolean)
•	final_exam (group):
o	weight (float)
o	drop_lowest (boolean)
(Se non ci sono quizzes o assignments, si spalma peso sugli altri due proporzionalmente)
notification_settings (group)
•	course_updates (boolean)
•	assignment_deadlines (boolean)
•	grade_posted (boolean)
•	enrollment_status (boolean)
•	certificate_issued (boolean)
•	miscellaneous (boolean)
- override_file_size_limits (boolean) -> Sovrascriverebbe i limiti di Directus, che sono customizzabili. Queste opzioni sarebbero SOLO admin, che possono modificare su richiesta. Non accessibili a nessun altro.
- course_max_file_size (integer, nullable)
- course_max_video_file_size (integer, nullable)
- course_max_audio_file_size (integer, nullable)
- course_max_document_file_size (integer, nullable)
- course_max_image_file_size (integer, nullable)
- status (string: "draft", "published", "archived") 
- created_by (UUID) 
- created_on (datetime) 
- modified_by (UUID) 
- modified_on (datetime)
Aggiungere opzioni default per passaggio lezione?

## Courses affiliations (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key):
- course (M2O relazione con Courses)
- unit (M2O relazione con Units)
- relationship_type (enum: "primary", "secondary", "collaborative")
- is_main_provider (boolean)
- responsibilities (text, nullable)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Custom eligibility (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key)
- course (M2O relazione con Courses)
- unit (M2O relazione con Units)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Modules
# Versione Preview: Sì
- id (UUID, primary key)
- course (M2O relazione con Courses)
- title (string)
- description (text)
- lessons (O2M alias, relazione con Lessons)
- status (string: "draft", "published", "archived")
- sort (integer)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Lessons
# Versione Preview: Sì
- id (UUID, primary key)
- module (M2O relazione con Modules)
- title (string)
- description (text)
- estimated_duration (integer, in minutes)
- completion_criteria (group) -> da mostrare agli utenti (+ required audio e video e activities)
•	time_spent (integer) -> default 0 minutes
•	content_viewed (boolean) -> default true
- content (repeater)  -> Ogni sezione con titolo.
•	text (WYSIWYG)
•	image (image) -> con alt_text (text)
•	files (files) -> con name (text), lingua (text), size (automatico)
•	video: file (file) o external_url (text) -> [solo mp4 / youtube, vimeo])
o	required (boolean) -> sempre valido indipendentemente dai completion_criteria
o	completion_criteria: percentage (integer, default 100) -> solo se required = true
•	audio: file (file) o external_url (text) ->  [solo mp3 / soundcloud])
o	required (boolean) -> sempre valido indipendentemente dai completion_criteria
o	completion_criteria: percentage (integer, default 100) -> solo se required = true
•	library_resources: […resource_ids] -> idealmente con ricerca da API
- visibility_conditions (group) -> non visibile agli utenti | no se Course_settings:progression_type:open
•	unlock_date (date) -> default null -> Non per Course: course_format:self_paced
•	previous_lesson_completed (boolean) -> default true
- materials (M2M alias, relazione con Materials)
- activities (O2M alias, relazione con Activities)
- progress (M2M alias, relazione con Progress)
- course_settings (M2O relazione con Course settings, nullable, unique?)
- status (string: "draft", "published", "archived")
- sort (integer)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Lesson materials (Collezione junction)
Versione Preview: Sì
- id (UUID, primary key)
- lesson (M2O relazione con Lessons)
- material (M2O relazione con Materials)
- status (string: "draft", "published", "archived")
- sort (integer)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Materials
# Versione Preview: Sì
- id (UUID, primary key)
- lessons (M2M alias, relazione con Lessons)
- title (string)
- description (text, nullable)
- file (file)
- type (string: "pdf", "video", "audio", "image", "other") -> Se possible computato
- status (string: "draft", "published", "archived")
- sort (integer)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Quizzes
# Versione Preview: Sì
- id (UUID, primary key)
- activity (M2O relazione con Activities, unique)
- title (string)
- time_limit (integer, in minutes, nullable)
- max_attempts (integer, nullable)
- shuffle_questions (boolean)
- shuffle_answers (boolean)
- show_correct_answers (boolean) -> solo se quiz_type = graded (vale anche per I 4 successivi)
- feedback_timing" (enum: "after_submission", "after_due_date") -> solo se show_correct_answers = true
- allow_review (boolean) -> solo se feedback_timing = after_due_date
- grade_method" (enum: "highest_attempt", "average", "last_attempt") -> solo se max_attempts > 1. Va spiegato agli studenti.
- questions (O2M alias, relazione con Quiz_Questions)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Quiz questions
# Versione Preview: Sì
- id (UUID, primary key)
- quiz (M2O relazione con Quizzes)
- question (text)
- type (string: "multiple_choice", "true_false", "short_answer", "matching")
- matching_scoring_type (enum: "all_or_nothing", "partial", nullable)
- points (int) (anche AI generated!) -> relato a passing_grade e grade_range in course_settings. La somma dei punti delle domande deve essere pari a grade_range.
- feedback (text, nullable)
- answers (O2M alias, relazione con Quiz_Answers)
- status (string: "draft", "published", "archived")
- sort (integer)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Quiz answers
# Versione Preview: Sì
- id (UUID, primary key)
- question (M2O relazione con Quiz_Questions)
- answer (text) -> contiene la risposta; is_correct o matching_item contengono il valore della risposta
- is_correct (boolean) -> per tutti i tipi tranne matching
- matching_item (text, nullable) -> per matching
- explanation (text, nullable)
- status (string: "draft", "published", "archived")
- sort (integer)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Quiz responses
# Rappresenta ogni risposta dell’utente a ogni domanda di ogni tentativo di quiz
# Versione Preview: Sì 
- id (UUID, primary key)
- quiz_attempt (M2O relazione con Quiz_Attempts)
- question (M2O relazione con Quiz_Questions)
- response (code -> JSON) -> trasformare in campi strutturati?
- is_correct (boolean)
- score (int)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

Vincoli:
- Unicità composta su (quiz_attempt, question)

## Quiz attempts
# Rappresenta la sovrastruttura di un tentativo di quiz e il suo risultato
# Versione Preview: Sì
- id (UUID, primary key)
- user (M2O relazione con People)
- activity (M2O relazione con Activities)
- quiz (M2O relazione con Quizzes)
- responses (O2M alias, relazione con Quiz responses)
- grades (O2M alias, relazione con Grades)
- start_time (datetime)
- end_time (datetime, nullable)
- attempt_status (enum: "in_progress", "completed", "abandoned")
- attempt_number (integer)
- interruption_reason (string, nullable) -> se status = abandoned. Provare a implementare automatismo.
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

Vincoli:
- Unicità composta su (user, quiz, attempt_number)
- Check constraint: attempt_number <= quiz.max_attempts
- Check constraint: start_time < end_time (quando end_time non è null)
- Al massimo un record con status "in_progress" per (user, quiz)

## Enrollments (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key)
- user (M2O relazione con People)
- course (M2O relazione con Courses)
- enrollment_status (string: "pending", "active", "completed", "dropped")
- enrollment_method (string: "self_enrolled", "admin_enrolled", "code_enrolled")
- dropped_reason (enum: "self_unenrolled", "admin_unenrolled", "auto_unenrolled", null)
- enrollment_date (date)
- last_activity_date (date, nullable)
- is_passed (boolean, nullable)
- completion_date (date, nullable) -> Anche se non è passato: sia per failed che per completed.
- attempt_number: (integer)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Progress (da rivedere)
# Versione Preview: Sì
- id (UUID, primary key)
- user (M2O relazione con People)
- activity (M2O relazione con Activities)
- lesson (M2O relazione con Lessons)
- progress_status (string: "not_started", "in_progress", "completed")
- completion_percentage (integer)
- time_spent (integer, in seconds) -> per Lessons: completion_criteria: time_spent
- content_viewed (boolean) -> per Lessons: completion_criteria: content_viewed
- media_progress (repeater) 
•	media_id (string)
•	type (enum: "video", "audio")
•	progress_percentage (integer)
- last_interaction (datetime) -> se serve, per calcolare tempo di inattività
- status (string: "draft", "published", "archived")
- last_accessed (datetime)
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Certificates
# Versione Preview: Sì
- id (UUID, primary key)
- user (M2O relazione con People)
- course (M2O relazione con Courses)
- issue_date (date)
- certificate_number (string, unique) -> deve essere unique (pensare formula hash + futuro blockchain)
- grade_at_issue (string, nullable) -> non per Course_settings:grading_methond:completion_based. Deve rispecchiare il format di grade_format (passato, lettera o punteggio)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Categories
# Versione Preview: Sì
- id (UUID, primary key)
- name (string)
- slug (string, unique)
- description (text, nullable)
- parent_category (M2O relazione con Categories, nullable)
- sub_categories (O2M alias, relazione inversa con Categories)
- courses (M2M alias, relazione con Course_Categories)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Course categories (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key)
- course (M2O relazione con Courses)
- category (M2O relazione con Categories)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Notifications
# Versione Preview: Sì
- id (UUID, primary key)
- user (M2O relazione con People)
- type (enum: "course", "assignment", "grade", "enrollment", "certificate", "system", "miscellaneous")
- content (text)
- is_read (boolean)
- is_mandatory (boolean) -> per notifiche critiche che arrivano sempre (le altre filtrabili dalle opzioni)
- link (string, nullable)
- priority (enum: "low", "medium", "high")
- expiry_date (datetime, nullable)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Assignments
# Versione Preview: Sì
- id (UUID, primary key)
- activity (M2O relazione con Activities, unique)
- groups (O2M alias, relazione con Assignment groups)
- title (string)
- type (string: "file_submission", "text_online", "group_project")
- assignment_type (enum: 'all', 'individual', 'group', mixed) -> default all
- max_file_size (integer) -> solo per type: file_submission
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Assignment submissions (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key)
- activity (M2O relazione con Activities)
- assignment (M2O relazione con Assignments)
- student (M2O relazione con People)
- assignment_group (M2O relazione con Assignment_Groups, nullable)
- grades (O2M alias, relazione con Grades)
- submission_date (datetime)
- content (group)
•	text (text)
•	file (file)
- feedback (text, nullable)
- submission_status (enum: "in_progress", "completed", "abandoned") -> prevedere versione di Preview!
- late_submission (boolean) -> impostare malus sul voto?
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Grades
# Versione Preview: Sì
# Legenda per Course settings:grading_method:completion_based = ***
- id (UUID, primary key)
- student (M2O relazione con People)
- course (M2O relazione con Courses)
- activity (M2O relazione con Activities, nullable)
- quiz_attempt (M2O relazione con Quiz attempts, nullable)
- assignment_submission (M2O relazione con Assignment submissions, nullable)
- grader_id (M2O relazione con People, nullable)
- grade_type (enum: 'activity', 'final_course')
- grade_source (enum: "automatic", "manual", null)
- score (float, nullable) -> float perché i gradi finali dei corsi pesati o i quiz average potrebbero avere decimali; registra i valori dei quiz con ***, ma hidden. Non per Assignments con ***.
- is_passing (boolean) -> gli Assignments con *** hanno solo questo booleano.
- score_range (float, nullable) -> registra i valori dei quiz con ***, ma hidden. Non per Assignments con ***.
- graded_at (timestamp)
- comment (text, nullable)
- is_current (boolean)
- previous_grade_id (M2O relazione con Grades, nullable)
- revised_grade_id (O2M alias, relazione inversa con Grades, nullable)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Activities
# Versione Preview: Sì	
-  id (UUID, primary key) 
- title (string) 
- description (text) 
- type (enum: "quiz", "assignment") 
- due_date (datetime, nullable) 
- is_required (boolean) -> Per il completamento della lezione (e quindi del corso)
- is_final_exam (boolean) default false -> solo se Course settings:grade_calculation = weighted. Implica is_required, cioè lo attiva automaticamente.
- visibility_conditions (group)
•	none -> se Course_settings:progression_type:open
•	unlock_date (date, nullable)
•	previous_activity_completed (boolean) 
- allow_late_submissions (boolean)
- late_submission_window (integer, nullable) -> in giorni
- show_submission_window (boolean) -> se è false, mostra che è permesso ritardo ma non quanto
- lesson (M2O relazione con Lessons)
- quizzes (O2M alias, relazione inversa con Quizzes)
- assignments (O2M alias, relazione inversa con Assignments)
- activity_groups (O2M alias, relazione con Activity groups)
- activity_assignments (M2M alias, relazione con People) 
- grades (O2M alias, relazione con Grades) 
- status (string: "draft", "published", "archived") 
- created_by (UUID) 
- created_on (datetime) 
- modified_by (UUID) 
- modified_on (datetime)

## Activity groups
# Versione Preview: Sì
- id (UUID, primary key)
- activity (M2O relazione con Activities)
- name (string)
- description (text, nullable)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Activity group members
# Versione Preview: Sì
- id (UUID, primary key)
- activity_group (M2O relazione con Activity groups)
- person (M2O relazione con People)
- is_leader (boolean)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)

## Activity assignments (Collezione junction)
# Versione Preview: Sì
- id (UUID, primary key)
- activity (M2O relazione con Activities)
- person (M2O relazione con People)
- assigned_at (datetime)
- assigned_by (M2O relazione con People)
- status (string: "draft", "published", "archived")
- created_by (UUID)
- created_on (datetime)
- modified_by (UUID)
- modified_on (datetime)