recreate project

This commit is contained in:
root
2026-02-10 22:11:06 -05:00
commit 663c0cdbda
10149 changed files with 1379710 additions and 0 deletions
View File
@@ -0,0 +1,41 @@
<?php
// 2025-09-10-031001_CreateEmailTemplates.php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use CodeIgniter\Database\RawSql;
class CreateEmailTemplates extends Migration
{
protected $DBGroup = 'default';
public function up()
{
$this->forge->addField([
'id' => ['type'=>'INT','unsigned'=>true,'auto_increment'=>true],
'template_key' => ['type'=>'VARCHAR','constraint'=>64,'null'=>false],
'name' => ['type'=>'VARCHAR','constraint'=>100,'null'=>false],
'subject' => ['type'=>'VARCHAR','constraint'=>255,'null'=>false],
'body' => ['type'=>'MEDIUMTEXT','null'=>false],
'is_active' => ['type'=>'TINYINT','constraint'=>1,'default'=>1,'null'=>false],
'created_at' => ['type'=>'DATETIME','null'=>false,'default'=>new RawSql('CURRENT_TIMESTAMP')],
'updated_at' => ['type'=>'DATETIME','null'=>false,'default'=>new RawSql('CURRENT_TIMESTAMP')],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey('template_key');
$this->forge->createTable('email_templates', true, [
'ENGINE'=>'InnoDB','DEFAULT CHARSET'=>'utf8mb4','COLLATE'=>'utf8mb4_unicode_ci',
]);
// Add ON UPDATE for updated_at after table creation
$this->db->query("ALTER TABLE `email_templates`
MODIFY `updated_at` DATETIME NOT NULL
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP");
}
public function down()
{
$this->forge->dropTable('email_templates', true);
}
}
@@ -0,0 +1,47 @@
<?php
// 2025-09-10-031010_CreateFamilies.php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use CodeIgniter\Database\RawSql;
class CreateFamilies extends Migration
{
protected $DBGroup = 'default';
public function up()
{
$this->forge->addField([
'id' => ['type'=>'INT','unsigned'=>true,'auto_increment'=>true],
'family_code' => ['type'=>'VARCHAR','constraint'=>32,'null'=>true],
'household_name' => ['type'=>'VARCHAR','constraint'=>120,'null'=>true],
'address_line1' => ['type'=>'VARCHAR','constraint'=>150,'null'=>true],
'address_line2' => ['type'=>'VARCHAR','constraint'=>150,'null'=>true],
'city' => ['type'=>'VARCHAR','constraint'=>80,'null'=>true],
'state' => ['type'=>'VARCHAR','constraint'=>40,'null'=>true],
'postal_code' => ['type'=>'VARCHAR','constraint'=>20,'null'=>true],
'country' => ['type'=>'VARCHAR','constraint'=>2,'null'=>true],
'primary_phone' => ['type'=>'VARCHAR','constraint'=>40,'null'=>true],
'preferred_lang' => ['type'=>'VARCHAR','constraint'=>10,'default'=>'en','null'=>false],
'preferred_contact_method' => ['type'=>'ENUM','constraint'=>['email','sms','phone'],'default'=>'email','null'=>false],
'is_active' => ['type'=>'TINYINT','constraint'=>1,'default'=>1,'null'=>false],
'created_at' => ['type'=>'DATETIME','null'=>false,'default'=>new RawSql('CURRENT_TIMESTAMP')],
'updated_at' => ['type'=>'DATETIME','null'=>false,'default'=>new RawSql('CURRENT_TIMESTAMP')],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey('family_code');
$this->forge->createTable('families', true, [
'ENGINE'=>'InnoDB','DEFAULT CHARSET'=>'utf8mb4','COLLATE'=>'utf8mb4_unicode_ci',
]);
$this->db->query("ALTER TABLE `families`
MODIFY `updated_at` DATETIME NOT NULL
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP");
}
public function down()
{
$this->forge->dropTable('families', true);
}
}
@@ -0,0 +1,39 @@
<?php
// 2025-09-10-031020_CreateFamilyStudents.php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateFamilyStudents extends Migration
{
protected $DBGroup = 'default';
public function up()
{
if (! $this->db->tableExists('families') || ! $this->db->tableExists('students')) {
throw new \RuntimeException('CreateFamilyStudents requires families and students tables to exist.');
}
$this->forge->addField([
'id' => ['type'=>'INT','unsigned'=>true,'auto_increment'=>true],
'family_id' => ['type'=>'INT','unsigned'=>true,'null'=>false],
'student_id' => ['type'=>'INT','unsigned'=>true,'null'=>false],
'is_primary_home' => ['type'=>'TINYINT','constraint'=>1,'default'=>1],
'notes' => ['type'=>'VARCHAR','constraint'=>255,'null'=>true],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['family_id','student_id'], 'uq_family_student');
$this->forge->addKey('student_id'); // no name param
$this->forge->addForeignKey('family_id','families','id','CASCADE','CASCADE','fk_fs_family');
$this->forge->addForeignKey('student_id','students','id','CASCADE','CASCADE','fk_fs_student');
$this->forge->createTable('family_students', true, [
'ENGINE'=>'InnoDB','DEFAULT CHARSET'=>'utf8mb4','COLLATE'=>'utf8mb4_unicode_ci',
]);
}
public function down()
{
$this->forge->dropTable('family_students', true);
}
}
@@ -0,0 +1,38 @@
<?php
// 2025-09-10-031030_CreateFamilyCommPrefs.php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateFamilyCommPrefs extends Migration
{
protected $DBGroup = 'default';
public function up()
{
if (! $this->db->tableExists('families')) {
throw new \RuntimeException('CreateFamilyCommPrefs requires families table to exist.');
}
$this->forge->addField([
'id' => ['type'=>'INT','unsigned'=>true,'auto_increment'=>true],
'family_id' => ['type'=>'INT','unsigned'=>true,'null'=>false],
'category' => ['type'=>'ENUM','constraint'=>['attendance','grade','behavior','general'],'null'=>false],
'via_email' => ['type'=>'TINYINT','constraint'=>1,'default'=>1],
'via_sms' => ['type'=>'TINYINT','constraint'=>1,'default'=>0],
'cc_all_guardians' => ['type'=>'TINYINT','constraint'=>1,'default'=>1],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['family_id','category'], 'uq_family_category');
$this->forge->addForeignKey('family_id','families','id','CASCADE','CASCADE','fk_fcp_family');
$this->forge->createTable('family_comm_prefs', true, [
'ENGINE'=>'InnoDB','DEFAULT CHARSET'=>'utf8mb4','COLLATE'=>'utf8mb4_unicode_ci',
]);
}
public function down()
{
$this->forge->dropTable('family_comm_prefs', true);
}
}
@@ -0,0 +1,51 @@
<?php
// 2025-09-10-031040_CreateCommunicationLogs.php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
use CodeIgniter\Database\RawSql;
class CreateCommunicationLogs extends Migration
{
protected $DBGroup = 'default';
public function up()
{
if (! $this->db->tableExists('families')) {
throw new \RuntimeException('CreateCommunicationLogs requires families table to exist.');
}
$this->forge->addField([
'id' => ['type'=>'BIGINT','unsigned'=>true,'auto_increment'=>true],
'student_id' => ['type'=>'INT','unsigned'=>true,'null'=>false],
'family_id' => ['type'=>'INT','unsigned'=>true,'null'=>true], // SET NULL on delete
'student_name' => ['type'=>'VARCHAR','constraint'=>150,'null'=>false],
'template_key' => ['type'=>'VARCHAR','constraint'=>64,'null'=>false],
'subject' => ['type'=>'VARCHAR','constraint'=>255,'null'=>false],
'body' => ['type'=>'MEDIUMTEXT','null'=>false],
'recipients' => ['type'=>'TEXT','null'=>false],
'cc' => ['type'=>'TEXT','null'=>true],
'bcc' => ['type'=>'TEXT','null'=>true],
'attachments' => ['type'=>'TEXT','null'=>true],
'status' => ['type'=>'ENUM','constraint'=>['sent','failed'],'null'=>false],
'error_message' => ['type'=>'TEXT','null'=>true],
'sent_by' => ['type'=>'INT','unsigned'=>true,'null'=>true],
'metadata' => ['type'=>'JSON','null'=>true],
'created_at' => ['type'=>'DATETIME','null'=>false,'default'=>new RawSql('CURRENT_TIMESTAMP')],
]);
$this->forge->addKey('id', true);
$this->forge->addKey('student_id');
$this->forge->addKey('family_id');
$this->forge->addKey('template_key');
$this->forge->addForeignKey('family_id','families','id','SET NULL','CASCADE','fk_comm_family');
$this->forge->createTable('communication_logs', true, [
'ENGINE'=>'InnoDB','DEFAULT CHARSET'=>'utf8mb4','COLLATE'=>'utf8mb4_unicode_ci',
]);
}
public function down()
{
$this->forge->dropTable('communication_logs', true);
}
}
@@ -0,0 +1,97 @@
<?php
// app/Database/Migrations/2025-09-10-031050_CreateFamilyGuardians.php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateFamilyGuardians extends Migration
{
protected $DBGroup = 'default';
public function up()
{
$dbName = $this->db->getDatabase();
// Find exact table names (handles Users/Families casing)
$usersRow = $this->db->query(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = ? AND LOWER(TABLE_NAME) = 'users' LIMIT 1",
[$dbName]
)->getFirstRow();
$familiesRow = $this->db->query(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = ? AND LOWER(TABLE_NAME) = 'families' LIMIT 1",
[$dbName]
)->getFirstRow();
if (!$usersRow || !$familiesRow) {
throw new \RuntimeException("Required tables not found: users or families in {$dbName}.");
}
$usersTable = $usersRow->TABLE_NAME;
$familiesTable = $familiesRow->TABLE_NAME;
// Make sure parents are InnoDB (required for FKs)
foreach ([$usersTable, $familiesTable] as $t) {
$eng = $this->db->query(
"SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA=? AND TABLE_NAME=?",
[$dbName, $t]
)->getFirstRow();
if (!$eng || strcasecmp($eng->ENGINE ?? '', 'InnoDB') !== 0) {
$this->db->query("ALTER TABLE `{$t}` ENGINE=InnoDB");
}
}
// Match child column types to parent id types exactly
$usersIdType = $this->db->query(
"SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=? AND TABLE_NAME=? AND COLUMN_NAME='id' LIMIT 1",
[$dbName, $usersTable]
)->getFirstRow()->COLUMN_TYPE ?? null;
$familiesIdType = $this->db->query(
"SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=? AND TABLE_NAME=? AND COLUMN_NAME='id' LIMIT 1",
[$dbName, $familiesTable]
)->getFirstRow()->COLUMN_TYPE ?? null;
if (!$usersIdType || !$familiesIdType) {
throw new \RuntimeException("Could not read id types from {$usersTable} / {$familiesTable}.");
}
// Clean slate in case a broken table exists
$this->db->query("DROP TABLE IF EXISTS `family_guardians`");
// Create with perfectly matching FK column types
$sql = "
CREATE TABLE `family_guardians` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`family_id` {$familiesIdType} NOT NULL,
`user_id` {$usersIdType} NOT NULL,
`relation` VARCHAR(32) DEFAULT NULL,
`is_primary` TINYINT(1) DEFAULT 0,
`receive_emails` TINYINT(1) DEFAULT 1,
`receive_sms` TINYINT(1) DEFAULT 0,
`custody_notes` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_family_user` (`family_id`,`user_id`),
KEY `idx_fg_family` (`family_id`),
KEY `idx_fg_user` (`user_id`),
CONSTRAINT `fk_fg_family`
FOREIGN KEY (`family_id`) REFERENCES `{$familiesTable}` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_fg_user`
FOREIGN KEY (`user_id`) REFERENCES `{$usersTable}` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;
";
$this->db->query($sql);
}
public function down()
{
$this->db->query("DROP TABLE IF EXISTS `family_guardians`");
}
}
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff