Skip to content

Commit 527bfdc

Browse files
committed
Add complete HRMS database with migrations and seeders
1 parent a064f2c commit 527bfdc

23 files changed

+567
-10
lines changed

README.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,26 @@ cp .env.example .env
6060

6161
### 3. Database Setup
6262
```bash
63-
# Import the database schema
63+
# Option 1: Import the complete database schema
6464
mysql -u root -p < app/database/Database.sql
65+
66+
# Option 2: Use migration system (recommended)
67+
php migrate.php fresh # Creates database, runs migrations and seeders
68+
```
69+
70+
#### Migration Commands
71+
```bash
72+
# Run migrations only
73+
php migrate.php migrate
74+
75+
# Run seeders only
76+
php migrate.php seed
77+
78+
# Rollback all migrations
79+
php migrate.php rollback
80+
81+
# Fresh migration (rollback + migrate + seed)
82+
php migrate.php fresh
6583
```
6684

6785
### 4. Start Development Server
@@ -78,6 +96,23 @@ docker-compose up -d
7896
curl http://localhost:8000/api/health
7997
```
8098

99+
### 6. Sample Login Credentials
100+
After running migrations and seeders, use these credentials to test the API:
101+
102+
```bash
103+
# Admin User
104+
Email: admin@hrms.com
105+
Password: admin123
106+
107+
# HR Manager
108+
Email: hr@hrms.com
109+
Password: admin123
110+
111+
# Employees
112+
Email: john@hrms.com, jane@hrms.com, mike@hrms.com
113+
Password: admin123
114+
```
115+
81116
## 📚 API Endpoints
82117

83118
### Authentication
@@ -117,6 +152,20 @@ curl -X GET http://localhost:8000/api/users \
117152
-H "Authorization: Bearer YOUR_JWT_TOKEN"
118153
```
119154

155+
## 🗄️ Database Schema
156+
157+
The HRMS includes the following tables:
158+
159+
- **users** - Employee accounts with roles (admin, hr, employee)
160+
- **departments** - Company departments
161+
- **employee_profiles** - Extended employee information
162+
- **attendance** - Daily attendance tracking
163+
- **leave_types** - Leave categories (Annual, Sick, etc.)
164+
- **leave_requests** - Leave applications with approval workflow
165+
- **payroll** - Monthly salary processing
166+
- **performance_reviews** - Employee performance evaluations
167+
- **tokens** - JWT authentication tokens
168+
120169
## 🏗️ Architecture
121170

122171
### Core Components

app/config/database.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
$servername = "localhost";
33
$username = "root";
44
$password = "";
5-
$database = "test_db";
5+
$database = "hrms_db";
66

77
$conn = new mysqli($servername, $username, $password, $database);
88

app/core/Application.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public function run()
2828

2929
private function loadRoutes()
3030
{
31+
$router = $this->router;
3132
require_once APP_PATH . '/routes/api.php';
3233
}
3334
}

app/core/Autoloader.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
class Autoloader
66
{
7+
public function register()
8+
{
9+
spl_autoload_register([$this, 'autoload']);
10+
}
11+
712
public function autoload($className)
813
{
914
$className = str_replace('\\', DIRECTORY_SEPARATOR, $className);

app/core/Database.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use PDO;
66
use PDOException;
7-
use App\Config\Env;
7+
use App\Core\Config;
88

99
class Database
1010
{
@@ -13,12 +13,12 @@ class Database
1313

1414
private function __construct()
1515
{
16-
$db_connection = Env::get('DB_CONNECTION', 'mysql');
17-
$db_host = Env::get('DB_HOST', '127.0.0.1');
18-
$db_port = Env::get('DB_PORT', '3306');
19-
$db_database = Env::get('DB_DATABASE', 'api_starter_kit');
20-
$db_username = Env::get('DB_USERNAME', 'root');
21-
$db_password = Env::get('DB_PASSWORD', '');
16+
$db_connection = Config::get('DB_CONNECTION', 'mysql');
17+
$db_host = Config::get('DB_HOST', '127.0.0.1');
18+
$db_port = Config::get('DB_PORT', '3306');
19+
$db_database = Config::get('DB_DATABASE', 'hrms_db');
20+
$db_username = Config::get('DB_USERNAME', 'root');
21+
$db_password = Config::get('DB_PASSWORD', '');
2222

2323
$dsn = "{$db_connection}:host={$db_host};port={$db_port};dbname={$db_database}";
2424

@@ -44,4 +44,14 @@ public function getConnection()
4444
{
4545
return $this->connection;
4646
}
47+
48+
public function exec($sql)
49+
{
50+
return $this->connection->exec($sql);
51+
}
52+
53+
public function query($sql)
54+
{
55+
return $this->connection->query($sql);
56+
}
4757
}

app/database/Migrator.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
namespace App\Database;
4+
5+
use App\Core\Database;
6+
7+
class Migrator
8+
{
9+
private $db;
10+
private $migrationsPath;
11+
private $seedersPath;
12+
13+
public function __construct()
14+
{
15+
$this->db = Database::getInstance();
16+
$this->migrationsPath = __DIR__ . '/migrations';
17+
$this->seedersPath = __DIR__ . '/seeders';
18+
}
19+
20+
public function migrate()
21+
{
22+
$migrations = glob($this->migrationsPath . '/*.php');
23+
sort($migrations);
24+
25+
foreach ($migrations as $migration) {
26+
$baseName = basename($migration, '.php');
27+
$className = 'App\\Database\\Migrations\\' . substr($baseName, 4); // Remove number prefix
28+
if (strpos($baseName, '001_') === 0) $className .= '001';
29+
elseif (strpos($baseName, '002_') === 0) $className = 'App\\Database\\Migrations\\CreateDepartmentsTable002';
30+
elseif (strpos($baseName, '003_') === 0) $className = 'App\\Database\\Migrations\\CreateEmployeeProfilesTable003';
31+
elseif (strpos($baseName, '004_') === 0) $className = 'App\\Database\\Migrations\\CreateAttendanceTable004';
32+
elseif (strpos($baseName, '005_') === 0) $className = 'App\\Database\\Migrations\\CreateLeaveTypesTable005';
33+
elseif (strpos($baseName, '006_') === 0) $className = 'App\\Database\\Migrations\\CreateLeaveRequestsTable006';
34+
elseif (strpos($baseName, '007_') === 0) $className = 'App\\Database\\Migrations\\CreatePayrollTable007';
35+
elseif (strpos($baseName, '008_') === 0) $className = 'App\\Database\\Migrations\\CreatePerformanceReviewsTable008';
36+
elseif (strpos($baseName, '009_') === 0) $className = 'App\\Database\\Migrations\\CreateTokensTable009';
37+
38+
require_once $migration;
39+
$sql = $className::up();
40+
$this->db->exec($sql);
41+
echo "Migrated: " . basename($migration) . "\n";
42+
}
43+
}
44+
45+
public function seed()
46+
{
47+
$seeders = glob($this->seedersPath . '/*.php');
48+
sort($seeders);
49+
50+
foreach ($seeders as $seeder) {
51+
$className = 'App\\Database\\Seeders\\' . basename($seeder, '.php');
52+
require_once $seeder;
53+
54+
try {
55+
$sql = $className::run();
56+
$this->db->exec($sql);
57+
echo "Seeded: " . basename($seeder) . "\n";
58+
} catch (\PDOException $e) {
59+
if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
60+
echo "Skipped (already exists): " . basename($seeder) . "\n";
61+
} else {
62+
throw $e;
63+
}
64+
}
65+
}
66+
}
67+
68+
public function rollback()
69+
{
70+
$migrations = glob($this->migrationsPath . '/*.php');
71+
rsort($migrations);
72+
73+
foreach ($migrations as $migration) {
74+
$className = 'App\\Database\\Migrations\\' . basename($migration, '.php');
75+
require_once $migration;
76+
77+
$sql = $className::down();
78+
$this->db->exec($sql);
79+
echo "Rolled back: " . basename($migration) . "\n";
80+
}
81+
}
82+
}

app/database/migrations/CreateUsersTable.php renamed to app/database/migrations/001_CreateUsersTable.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@
22

33
namespace App\Database\Migrations;
44

5-
class CreateUsersTable
5+
class CreateUsersTable001
66
{
77
public static function up()
88
{
99
return "
1010
CREATE TABLE IF NOT EXISTS users (
1111
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
12+
employee_id VARCHAR(20) UNIQUE,
1213
name VARCHAR(255) NOT NULL,
1314
email VARCHAR(255) NOT NULL UNIQUE,
1415
password VARCHAR(255) NOT NULL,
16+
phone VARCHAR(20),
17+
role ENUM('admin', 'hr', 'employee') DEFAULT 'employee',
18+
status ENUM('active', 'inactive') DEFAULT 'active',
1519
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1620
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
1721
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace App\Database\Migrations;
4+
5+
class CreateDepartmentsTable002
6+
{
7+
public static function up()
8+
{
9+
return "
10+
CREATE TABLE IF NOT EXISTS departments (
11+
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
12+
name VARCHAR(255) NOT NULL,
13+
description TEXT,
14+
manager_id INT(11),
15+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
16+
FOREIGN KEY (manager_id) REFERENCES users(id) ON DELETE SET NULL
17+
)
18+
";
19+
}
20+
21+
public static function down()
22+
{
23+
return "DROP TABLE IF EXISTS departments";
24+
}
25+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Database\Migrations;
4+
5+
class CreateEmployeeProfilesTable003
6+
{
7+
public static function up()
8+
{
9+
return "
10+
CREATE TABLE IF NOT EXISTS employee_profiles (
11+
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
12+
user_id INT(11) NOT NULL,
13+
department_id INT(11),
14+
position VARCHAR(255),
15+
salary DECIMAL(10,2),
16+
hire_date DATE,
17+
address TEXT,
18+
emergency_contact VARCHAR(255),
19+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
20+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
21+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
22+
FOREIGN KEY (department_id) REFERENCES departments(id) ON DELETE SET NULL
23+
)
24+
";
25+
}
26+
27+
public static function down()
28+
{
29+
return "DROP TABLE IF EXISTS employee_profiles";
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Database\Migrations;
4+
5+
class CreateAttendanceTable004
6+
{
7+
public static function up()
8+
{
9+
return "
10+
CREATE TABLE IF NOT EXISTS attendance (
11+
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
12+
user_id INT(11) NOT NULL,
13+
date DATE NOT NULL,
14+
check_in TIME,
15+
check_out TIME,
16+
break_time INT DEFAULT 0,
17+
total_hours DECIMAL(4,2),
18+
status ENUM('present', 'absent', 'late', 'half_day') DEFAULT 'present',
19+
notes TEXT,
20+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
21+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
22+
UNIQUE KEY unique_user_date (user_id, date)
23+
)
24+
";
25+
}
26+
27+
public static function down()
28+
{
29+
return "DROP TABLE IF EXISTS attendance";
30+
}
31+
}

0 commit comments

Comments
 (0)