Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
401 / 401
100.00% covered (success)
100.00%
26 / 26
CRAP
100.00% covered (success)
100.00%
1 / 1
CreateAcademyFoundation
100.00% covered (success)
100.00%
401 / 401
100.00% covered (success)
100.00%
26 / 26
33
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 up
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
1
 down
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
2
 createRolesTable
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 createUserRolesTable
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 createParentsTable
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 createCoachesTable
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
1
 createCoachAvailabilityTable
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 createAcademyLevelsTable
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 createAcademyGroupsTable
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 createChildrenTable
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
1
 createChildGuardiansTable
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 createChildCoachesTable
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationTypesTable
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationCriteriaTable
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationTypeCriteriaTable
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationRulesTable
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationsTable
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationScoresTable
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 createEvaluationStatusHistoryTable
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 createAttendanceSessionsTable
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
 createAttendanceRecordsTable
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
1
 createJourneyEventsTable
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 createNotificationsTable
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 extendSettingsTable
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
6
 createTable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Database\Migrations;
4
5use CodeIgniter\Database\Forge;
6use CodeIgniter\Database\Migration;
7
8class CreateAcademyFoundation extends Migration
9{
10    private readonly array $attributes;
11
12    public function __construct(?Forge $forge = null)
13    {
14        parent::__construct($forge);
15
16        $this->attributes = $this->db->getPlatform() === 'MySQLi' ? ['ENGINE' => 'InnoDB'] : [];
17    }
18
19    public function up(): void
20    {
21        $this->createRolesTable();
22        $this->createUserRolesTable();
23        $this->createParentsTable();
24        $this->createCoachesTable();
25        $this->createCoachAvailabilityTable();
26        $this->createAcademyLevelsTable();
27        $this->createAcademyGroupsTable();
28        $this->createChildrenTable();
29        $this->createChildGuardiansTable();
30        $this->createChildCoachesTable();
31        $this->createEvaluationTypesTable();
32        $this->createEvaluationCriteriaTable();
33        $this->createEvaluationTypeCriteriaTable();
34        $this->createEvaluationRulesTable();
35        $this->createEvaluationsTable();
36        $this->createEvaluationScoresTable();
37        $this->createEvaluationStatusHistoryTable();
38        $this->createAttendanceSessionsTable();
39        $this->createAttendanceRecordsTable();
40        $this->createJourneyEventsTable();
41        $this->createNotificationsTable();
42        $this->extendSettingsTable();
43    }
44
45    public function down(): void
46    {
47        $this->db->disableForeignKeyChecks();
48
49        $tables = [
50            'notifications',
51            'journey_events',
52            'attendance_records',
53            'attendance_sessions',
54            'evaluation_status_history',
55            'evaluation_scores',
56            'evaluations',
57            'evaluation_rules',
58            'evaluation_type_criteria',
59            'evaluation_criteria',
60            'evaluation_types',
61            'child_coaches',
62            'child_guardians',
63            'children',
64            'academy_groups',
65            'academy_levels',
66            'coach_availability',
67            'coaches',
68            'parents',
69            'user_roles',
70            'roles',
71        ];
72
73        foreach ($tables as $table) {
74            $this->forge->dropTable($table, true);
75        }
76
77        $this->db->enableForeignKeyChecks();
78    }
79
80    private function createRolesTable(): void
81    {
82        $this->forge->addField([
83            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
84            'slug' => ['type' => 'VARCHAR', 'constraint' => 50],
85            'name' => ['type' => 'VARCHAR', 'constraint' => 100],
86            'description' => ['type' => 'TEXT', 'null' => true],
87            'priority' => ['type' => 'INT', 'constraint' => 11, 'default' => 10],
88            'created_at' => ['type' => 'DATETIME', 'null' => true],
89            'updated_at' => ['type' => 'DATETIME', 'null' => true],
90        ]);
91        $this->forge->addPrimaryKey('id');
92        $this->forge->addUniqueKey('slug');
93        $this->createTable('roles');
94    }
95
96    private function createUserRolesTable(): void
97    {
98        $this->forge->addField([
99            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
100            'user_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
101            'role_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
102            'created_at' => ['type' => 'DATETIME', 'null' => true],
103        ]);
104        $this->forge->addPrimaryKey('id');
105        $this->forge->addUniqueKey(['user_id', 'role_id']);
106        $this->forge->addKey('role_id');
107        $this->forge->addForeignKey('user_id', 'users', 'id', '', 'CASCADE');
108        $this->forge->addForeignKey('role_id', 'roles', 'id', '', 'CASCADE');
109        $this->createTable('user_roles');
110    }
111
112    private function createParentsTable(): void
113    {
114        $this->forge->addField([
115            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
116            'user_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
117            'full_name' => ['type' => 'VARCHAR', 'constraint' => 150],
118            'phone' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => true],
119            'email' => ['type' => 'VARCHAR', 'constraint' => 120, 'null' => true],
120            'relationship_type' => ['type' => 'VARCHAR', 'constraint' => 50, 'default' => 'parent'],
121            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'active'],
122            'notes' => ['type' => 'TEXT', 'null' => true],
123            'created_at' => ['type' => 'DATETIME', 'null' => true],
124            'updated_at' => ['type' => 'DATETIME', 'null' => true],
125        ]);
126        $this->forge->addPrimaryKey('id');
127        $this->forge->addKey('user_id');
128        $this->forge->addKey('email');
129        $this->forge->addForeignKey('user_id', 'users', 'id', '', 'SET NULL');
130        $this->createTable('parents');
131    }
132
133    private function createCoachesTable(): void
134    {
135        $this->forge->addField([
136            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
137            'user_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
138            'full_name' => ['type' => 'VARCHAR', 'constraint' => 150],
139            'display_role' => ['type' => 'VARCHAR', 'constraint' => 100],
140            'phone' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => true],
141            'email' => ['type' => 'VARCHAR', 'constraint' => 120, 'null' => true],
142            'avatar_path' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
143            'is_active' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1],
144            'notes' => ['type' => 'TEXT', 'null' => true],
145            'created_at' => ['type' => 'DATETIME', 'null' => true],
146            'updated_at' => ['type' => 'DATETIME', 'null' => true],
147        ]);
148        $this->forge->addPrimaryKey('id');
149        $this->forge->addUniqueKey('user_id');
150        $this->forge->addKey('email');
151        $this->forge->addForeignKey('user_id', 'users', 'id', '', 'SET NULL');
152        $this->createTable('coaches');
153    }
154
155    private function createCoachAvailabilityTable(): void
156    {
157        $this->forge->addField([
158            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
159            'coach_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
160            'day_of_week' => ['type' => 'TINYINT', 'constraint' => 1],
161            'start_time' => ['type' => 'TIME'],
162            'end_time' => ['type' => 'TIME'],
163            'is_available' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1],
164            'created_at' => ['type' => 'DATETIME', 'null' => true],
165        ]);
166        $this->forge->addPrimaryKey('id');
167        $this->forge->addForeignKey('coach_id', 'coaches', 'id', '', 'CASCADE');
168        $this->createTable('coach_availability');
169    }
170
171    private function createAcademyLevelsTable(): void
172    {
173        $this->forge->addField([
174            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
175            'name' => ['type' => 'VARCHAR', 'constraint' => 100],
176            'slug' => ['type' => 'VARCHAR', 'constraint' => 100],
177            'sort_order' => ['type' => 'INT', 'constraint' => 11, 'default' => 0],
178            'color_hex' => ['type' => 'VARCHAR', 'constraint' => 7, 'null' => true],
179            'internal_description' => ['type' => 'TEXT', 'null' => true],
180            'parent_description' => ['type' => 'TEXT', 'null' => true],
181            'benchmark_minimum' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'null' => true],
182            'benchmark_target' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'null' => true],
183            'promotion_rules' => ['type' => 'TEXT', 'null' => true],
184            'created_at' => ['type' => 'DATETIME', 'null' => true],
185            'updated_at' => ['type' => 'DATETIME', 'null' => true],
186        ]);
187        $this->forge->addPrimaryKey('id');
188        $this->forge->addUniqueKey('slug');
189        $this->createTable('academy_levels');
190    }
191
192    private function createAcademyGroupsTable(): void
193    {
194        $this->forge->addField([
195            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
196            'name' => ['type' => 'VARCHAR', 'constraint' => 100],
197            'code' => ['type' => 'VARCHAR', 'constraint' => 50],
198            'academy_level_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
199            'primary_coach_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
200            'schedule_summary' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
201            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'active'],
202            'capacity' => ['type' => 'INT', 'constraint' => 11, 'default' => 12],
203            'created_at' => ['type' => 'DATETIME', 'null' => true],
204            'updated_at' => ['type' => 'DATETIME', 'null' => true],
205        ]);
206        $this->forge->addPrimaryKey('id');
207        $this->forge->addUniqueKey('code');
208        $this->forge->addForeignKey('academy_level_id', 'academy_levels', 'id', '', 'SET NULL');
209        $this->forge->addForeignKey('primary_coach_id', 'coaches', 'id', '', 'SET NULL');
210        $this->createTable('academy_groups');
211    }
212
213    private function createChildrenTable(): void
214    {
215        $this->forge->addField([
216            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
217            'first_name' => ['type' => 'VARCHAR', 'constraint' => 100],
218            'last_name' => ['type' => 'VARCHAR', 'constraint' => 100],
219            'full_name' => ['type' => 'VARCHAR', 'constraint' => 180],
220            'birth_date' => ['type' => 'DATE', 'null' => true],
221            'gender' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
222            'academy_level_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
223            'academy_group_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
224            'primary_coach_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
225            'primary_guardian_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
226            'first_class_at' => ['type' => 'DATE', 'null' => true],
227            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'active'],
228            'has_siblings' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
229            'notes' => ['type' => 'TEXT', 'null' => true],
230            'created_at' => ['type' => 'DATETIME', 'null' => true],
231            'updated_at' => ['type' => 'DATETIME', 'null' => true],
232        ]);
233        $this->forge->addPrimaryKey('id');
234        $this->forge->addKey('academy_level_id');
235        $this->forge->addKey('academy_group_id');
236        $this->forge->addKey('primary_coach_id');
237        $this->forge->addKey('status');
238        $this->forge->addForeignKey('academy_level_id', 'academy_levels', 'id', '', 'SET NULL');
239        $this->forge->addForeignKey('academy_group_id', 'academy_groups', 'id', '', 'SET NULL');
240        $this->forge->addForeignKey('primary_coach_id', 'coaches', 'id', '', 'SET NULL');
241        $this->forge->addForeignKey('primary_guardian_id', 'parents', 'id', '', 'SET NULL');
242        $this->createTable('children');
243    }
244
245    private function createChildGuardiansTable(): void
246    {
247        $this->forge->addField([
248            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
249            'child_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
250            'parent_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
251            'relationship_type' => ['type' => 'VARCHAR', 'constraint' => 50, 'default' => 'parent'],
252            'is_primary' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
253            'created_at' => ['type' => 'DATETIME', 'null' => true],
254        ]);
255        $this->forge->addPrimaryKey('id');
256        $this->forge->addUniqueKey(['child_id', 'parent_id']);
257        $this->forge->addForeignKey('child_id', 'children', 'id', '', 'CASCADE');
258        $this->forge->addForeignKey('parent_id', 'parents', 'id', '', 'CASCADE');
259        $this->createTable('child_guardians');
260    }
261
262    private function createChildCoachesTable(): void
263    {
264        $this->forge->addField([
265            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
266            'child_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
267            'coach_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
268            'is_primary' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
269            'assigned_at' => ['type' => 'DATETIME', 'null' => true],
270            'unassigned_at' => ['type' => 'DATETIME', 'null' => true],
271        ]);
272        $this->forge->addPrimaryKey('id');
273        $this->forge->addUniqueKey(['child_id', 'coach_id']);
274        $this->forge->addForeignKey('child_id', 'children', 'id', '', 'CASCADE');
275        $this->forge->addForeignKey('coach_id', 'coaches', 'id', '', 'CASCADE');
276        $this->createTable('child_coaches');
277    }
278
279    private function createEvaluationTypesTable(): void
280    {
281        $this->forge->addField([
282            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
283            'name' => ['type' => 'VARCHAR', 'constraint' => 100],
284            'slug' => ['type' => 'VARCHAR', 'constraint' => 100],
285            'description' => ['type' => 'TEXT', 'null' => true],
286            'is_quick_check' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
287            'affects_promotion' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
288            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'active'],
289            'created_at' => ['type' => 'DATETIME', 'null' => true],
290            'updated_at' => ['type' => 'DATETIME', 'null' => true],
291        ]);
292        $this->forge->addPrimaryKey('id');
293        $this->forge->addUniqueKey('slug');
294        $this->createTable('evaluation_types');
295    }
296
297    private function createEvaluationCriteriaTable(): void
298    {
299        $this->forge->addField([
300            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
301            'name' => ['type' => 'VARCHAR', 'constraint' => 120],
302            'slug' => ['type' => 'VARCHAR', 'constraint' => 120],
303            'description' => ['type' => 'TEXT', 'null' => true],
304            'is_active' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1],
305            'default_weight' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 1],
306            'is_critical' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
307            'sort_order' => ['type' => 'INT', 'constraint' => 11, 'default' => 0],
308            'min_score' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 1],
309            'max_score' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 5],
310            'created_at' => ['type' => 'DATETIME', 'null' => true],
311            'updated_at' => ['type' => 'DATETIME', 'null' => true],
312        ]);
313        $this->forge->addPrimaryKey('id');
314        $this->forge->addUniqueKey('slug');
315        $this->createTable('evaluation_criteria');
316    }
317
318    private function createEvaluationTypeCriteriaTable(): void
319    {
320        $this->forge->addField([
321            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
322            'evaluation_type_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
323            'evaluation_criteria_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
324            'weight' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 1],
325            'is_required' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1],
326            'sort_order' => ['type' => 'INT', 'constraint' => 11, 'default' => 0],
327        ]);
328        $this->forge->addPrimaryKey('id');
329        $this->forge->addUniqueKey(['evaluation_type_id', 'evaluation_criteria_id']);
330        $this->forge->addForeignKey('evaluation_type_id', 'evaluation_types', 'id', '', 'CASCADE');
331        $this->forge->addForeignKey('evaluation_criteria_id', 'evaluation_criteria', 'id', '', 'CASCADE');
332        $this->createTable('evaluation_type_criteria');
333    }
334
335    private function createEvaluationRulesTable(): void
336    {
337        $this->forge->addField([
338            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
339            'name' => ['type' => 'VARCHAR', 'constraint' => 120],
340            'scope_type' => ['type' => 'VARCHAR', 'constraint' => 50, 'default' => 'global'],
341            'scope_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
342            'almost_ready_threshold' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 3.5],
343            'ready_threshold' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 4.0],
344            'minimum_critical_threshold' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 3.0],
345            'is_active' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 1],
346            'notes' => ['type' => 'TEXT', 'null' => true],
347            'created_at' => ['type' => 'DATETIME', 'null' => true],
348            'updated_at' => ['type' => 'DATETIME', 'null' => true],
349        ]);
350        $this->forge->addPrimaryKey('id');
351        $this->forge->addKey(['scope_type', 'scope_id']);
352        $this->createTable('evaluation_rules');
353    }
354
355    private function createEvaluationsTable(): void
356    {
357        $this->forge->addField([
358            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
359            'child_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
360            'evaluation_type_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
361            'evaluation_date' => ['type' => 'DATE'],
362            'evaluator_user_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
363            'evaluator_coach_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
364            'level_at_time_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
365            'final_score' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 0],
366            'final_status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'HOLD'],
367            'promotion_signal' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
368            'notes' => ['type' => 'TEXT', 'null' => true],
369            'created_at' => ['type' => 'DATETIME', 'null' => true],
370            'updated_at' => ['type' => 'DATETIME', 'null' => true],
371        ]);
372        $this->forge->addPrimaryKey('id');
373        $this->forge->addKey(['child_id', 'evaluation_date']);
374        $this->forge->addKey('final_status');
375        $this->forge->addForeignKey('child_id', 'children', 'id', '', 'CASCADE');
376        $this->forge->addForeignKey('evaluation_type_id', 'evaluation_types', 'id', '', 'CASCADE');
377        $this->forge->addForeignKey('evaluator_user_id', 'users', 'id', '', 'SET NULL');
378        $this->forge->addForeignKey('evaluator_coach_id', 'coaches', 'id', '', 'SET NULL');
379        $this->forge->addForeignKey('level_at_time_id', 'academy_levels', 'id', '', 'SET NULL');
380        $this->createTable('evaluations');
381    }
382
383    private function createEvaluationScoresTable(): void
384    {
385        $this->forge->addField([
386            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
387            'evaluation_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
388            'evaluation_criteria_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
389            'weight' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 1],
390            'score' => ['type' => 'DECIMAL', 'constraint' => '5,2', 'default' => 0],
391            'is_critical' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
392            'notes' => ['type' => 'TEXT', 'null' => true],
393        ]);
394        $this->forge->addPrimaryKey('id');
395        $this->forge->addForeignKey('evaluation_id', 'evaluations', 'id', '', 'CASCADE');
396        $this->forge->addForeignKey('evaluation_criteria_id', 'evaluation_criteria', 'id', '', 'CASCADE');
397        $this->createTable('evaluation_scores');
398    }
399
400    private function createEvaluationStatusHistoryTable(): void
401    {
402        $this->forge->addField([
403            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
404            'evaluation_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
405            'previous_status' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => true],
406            'new_status' => ['type' => 'VARCHAR', 'constraint' => 30],
407            'reason' => ['type' => 'TEXT', 'null' => true],
408            'changed_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
409            'created_at' => ['type' => 'DATETIME', 'null' => true],
410        ]);
411        $this->forge->addPrimaryKey('id');
412        $this->forge->addForeignKey('evaluation_id', 'evaluations', 'id', '', 'CASCADE');
413        $this->forge->addForeignKey('changed_by', 'users', 'id', '', 'SET NULL');
414        $this->createTable('evaluation_status_history');
415    }
416
417    private function createAttendanceSessionsTable(): void
418    {
419        $this->forge->addField([
420            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
421            'academy_group_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
422            'coach_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
423            'session_date' => ['type' => 'DATE'],
424            'start_time' => ['type' => 'TIME', 'null' => true],
425            'end_time' => ['type' => 'TIME', 'null' => true],
426            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'scheduled'],
427            'is_cancelled' => ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0],
428            'cancelled_reason' => ['type' => 'TEXT', 'null' => true],
429            'recovery_for_session_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
430            'notes' => ['type' => 'TEXT', 'null' => true],
431            'created_at' => ['type' => 'DATETIME', 'null' => true],
432            'updated_at' => ['type' => 'DATETIME', 'null' => true],
433        ]);
434        $this->forge->addPrimaryKey('id');
435        $this->forge->addKey(['academy_group_id', 'session_date']);
436        $this->forge->addForeignKey('academy_group_id', 'academy_groups', 'id', '', 'CASCADE');
437        $this->forge->addForeignKey('coach_id', 'coaches', 'id', '', 'SET NULL');
438        $this->forge->addForeignKey('recovery_for_session_id', 'attendance_sessions', 'id', '', 'SET NULL');
439        $this->createTable('attendance_sessions');
440    }
441
442    private function createAttendanceRecordsTable(): void
443    {
444        $this->forge->addField([
445            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
446            'attendance_session_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
447            'child_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
448            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'present'],
449            'checked_in_at' => ['type' => 'DATETIME', 'null' => true],
450            'notes' => ['type' => 'TEXT', 'null' => true],
451            'created_at' => ['type' => 'DATETIME', 'null' => true],
452            'updated_at' => ['type' => 'DATETIME', 'null' => true],
453        ]);
454        $this->forge->addPrimaryKey('id');
455        $this->forge->addUniqueKey(['attendance_session_id', 'child_id']);
456        $this->forge->addKey('status');
457        $this->forge->addForeignKey('attendance_session_id', 'attendance_sessions', 'id', '', 'CASCADE');
458        $this->forge->addForeignKey('child_id', 'children', 'id', '', 'CASCADE');
459        $this->createTable('attendance_records');
460    }
461
462    private function createJourneyEventsTable(): void
463    {
464        $this->forge->addField([
465            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
466            'child_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
467            'event_type' => ['type' => 'VARCHAR', 'constraint' => 60],
468            'title' => ['type' => 'VARCHAR', 'constraint' => 150],
469            'description' => ['type' => 'TEXT', 'null' => true],
470            'metadata' => ['type' => 'TEXT', 'null' => true],
471            'created_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
472            'created_at' => ['type' => 'DATETIME', 'null' => true],
473        ]);
474        $this->forge->addPrimaryKey('id');
475        $this->forge->addKey(['child_id', 'created_at']);
476        $this->forge->addForeignKey('child_id', 'children', 'id', '', 'CASCADE');
477        $this->forge->addForeignKey('created_by', 'users', 'id', '', 'SET NULL');
478        $this->createTable('journey_events');
479    }
480
481    private function createNotificationsTable(): void
482    {
483        $this->forge->addField([
484            'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
485            'user_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
486            'child_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
487            'type' => ['type' => 'VARCHAR', 'constraint' => 50],
488            'title' => ['type' => 'VARCHAR', 'constraint' => 150],
489            'message' => ['type' => 'TEXT'],
490            'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'default' => 'unread'],
491            'action_url' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
492            'created_at' => ['type' => 'DATETIME', 'null' => true],
493            'read_at' => ['type' => 'DATETIME', 'null' => true],
494        ]);
495        $this->forge->addPrimaryKey('id');
496        $this->forge->addKey(['user_id', 'status']);
497        $this->forge->addForeignKey('user_id', 'users', 'id', '', 'SET NULL');
498        $this->forge->addForeignKey('child_id', 'children', 'id', '', 'SET NULL');
499        $this->createTable('notifications');
500    }
501
502    private function extendSettingsTable(): void
503    {
504        $columns = [];
505
506        if (! $this->db->fieldExists('label', 'settings')) {
507            $columns['label'] = ['type' => 'VARCHAR', 'constraint' => 150, 'null' => true, 'after' => 'context'];
508        }
509
510        if (! $this->db->fieldExists('group_name', 'settings')) {
511            $columns['group_name'] = ['type' => 'VARCHAR', 'constraint' => 100, 'default' => 'general', 'after' => 'label'];
512        }
513
514        if (! $this->db->fieldExists('description', 'settings')) {
515            $columns['description'] = ['type' => 'TEXT', 'null' => true, 'after' => 'group_name'];
516        }
517
518        if (! $this->db->fieldExists('is_public', 'settings')) {
519            $columns['is_public'] = ['type' => 'TINYINT', 'constraint' => 1, 'default' => 0, 'after' => 'description'];
520        }
521
522        if ($columns !== []) {
523            $this->forge->addColumn('settings', $columns);
524        }
525    }
526
527    private function createTable(string $tableName): void
528    {
529        $this->forge->createTable($tableName, false, $this->attributes);
530    }
531}