| 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 |
3 | namespace App\Database\Migrations;
4 |
5 | use CodeIgniter\Database\Forge;
6 | use CodeIgniter\Database\Migration;
7 |
8 | class 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 | }