You need to sign in or sign up before continuing.
Commit 1b7c366e authored by Administrator's avatar Administrator

Update 17 files via Son of Anton

parent 6dfa5fed
Pipeline #12 canceled with stage
.git
.gitignore
.env
.env.local
storage/uploads/*
storage/exports/*
storage/logs/*
storage/cache/*
!storage/uploads/.gitkeep
!storage/exports/.gitkeep
!storage/logs/.gitkeep
!storage/cache/templates/.gitkeep
*.md
docker-compose*.yml
.idea
.vscode
node_modules
\ No newline at end of file
APP_URL=https://hr.al-arcade.com
APP_DEBUG=false
APP_KEY=CHANGE-ME-TO-64-CHAR-RANDOM-STRING
DB_HOST=srv-captain--mysql-db
DB_PORT=3306
DB_NAME=al_arcade_hr
DB_USER=root
DB_PASS=CHANGE_ME
SA_USERNAME=mahmoud
SA_PASSWORD=CHANGE_ME
SA_NAME_EN=Mahmoud Aglan
SA_NAME_AR=محمود عجلان
\ No newline at end of file
stages:
- deploy
deploy_production:
stage: deploy
only:
- main
script:
- echo "Deploying to CapRover..."
- apt-get update && apt-get install -y npm || true
- npm install -g caprover || true
- caprover deploy -h $CAPROVER_URL -p $CAPROVER_PASSWORD -a $CAPROVER_APP -b main
variables:
CAPROVER_URL: $CAPROVER_URL
CAPROVER_PASSWORD: $CAPROVER_PASSWORD
CAPROVER_APP: $CAPROVER_APP
\ No newline at end of file
FROM php:8.2-apache
# Install PHP extensions
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libzip-dev \
libicu-dev \
libonig-dev \
libcurl4-openssl-dev \
zip unzip curl \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install \
pdo_mysql \
mbstring \
gd \
zip \
intl \
opcache \
bcmath \
fileinfo \
pcntl \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Apache configuration
RUN a2enmod rewrite headers
COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
# PHP configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
COPY docker/php-custom.ini /usr/local/etc/php/conf.d/99-custom.ini
# Set working directory
WORKDIR /var/www/html
# Copy application files
COPY . /var/www/html/
# Create storage directories
RUN mkdir -p \
/var/www/html/storage/uploads \
/var/www/html/storage/exports \
/var/www/html/storage/logs \
/var/www/html/storage/cache/templates \
&& chown -R www-data:www-data /var/www/html/storage \
&& chmod -R 775 /var/www/html/storage
# Set Apache document root to public/
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN sed -ri -e 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/*.conf \
&& sed -ri -e 's!/var/www/!/var/www/html/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
# Entrypoint for DB initialization
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
EXPOSE 80
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["apache2-foreground"]
\ No newline at end of file
...@@ -3,9 +3,9 @@ declare(strict_types=1); ...@@ -3,9 +3,9 @@ declare(strict_types=1);
spl_autoload_register(function (string $class): void { spl_autoload_register(function (string $class): void {
$prefixes = [ $prefixes = [
'Engine\\' => ROOT_PATH . '/engine/', 'Engine\\' => ROOT_PATH . '/engine/',
'Modules\\' => ROOT_PATH . '/modules/',
'Middleware\\' => ROOT_PATH . '/middleware/', 'Middleware\\' => ROOT_PATH . '/middleware/',
'Modules\\' => ROOT_PATH . '/modules/',
]; ];
foreach ($prefixes as $prefix => $baseDir) { foreach ($prefixes as $prefix => $baseDir) {
...@@ -13,8 +13,10 @@ spl_autoload_register(function (string $class): void { ...@@ -13,8 +13,10 @@ spl_autoload_register(function (string $class): void {
if (strncmp($prefix, $class, $len) !== 0) { if (strncmp($prefix, $class, $len) !== 0) {
continue; continue;
} }
$relativeClass = substr($class, $len); $relativeClass = substr($class, $len);
$file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php'; $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
if (file_exists($file)) { if (file_exists($file)) {
require $file; require $file;
return; return;
......
{
"schemaVersion": 2,
"dockerfilePath": "./Dockerfile"
}
\ No newline at end of file
...@@ -3,51 +3,58 @@ declare(strict_types=1); ...@@ -3,51 +3,58 @@ declare(strict_types=1);
define('ROOT_PATH', dirname(__DIR__)); define('ROOT_PATH', dirname(__DIR__));
require ROOT_PATH . '/bootstrap/autoload.php'; require ROOT_PATH . '/bootstrap/autoload.php';
require ROOT_PATH . '/bootstrap/app.php';
use Engine\Core\Container; $dbConfig = require ROOT_PATH . '/config/database.php';
use Engine\Database\Connection;
use Engine\Auth\PasswordHasher;
$db = Container::getInstance()->resolve(Connection::class); try {
$hasher = Container::getInstance()->resolve(PasswordHasher::class); $dsn = "mysql:host={$dbConfig['host']};port={$dbConfig['port']};dbname={$dbConfig['database']};charset={$dbConfig['charset']}";
$pdo = new PDO($dsn, $dbConfig['username'], $dbConfig['password'], $dbConfig['options']);
echo "=== CREATE SUPER ADMIN ===\n\n"; } catch (PDOException $e) {
echo "DB Connection Failed: {$e->getMessage()}\n";
$username = $argv[1] ?? 'superadmin'; exit(1);
$password = $argv[2] ?? 'Admin@12345'; }
$existing = $db->fetchOne("SELECT id FROM users WHERE username = ?", [$username]); // Check if super admin already exists
if ($existing) { $stmt = $pdo->prepare("SELECT id FROM users WHERE role = 'super_admin' LIMIT 1");
echo "User '{$username}' already exists (ID: {$existing['id']}). Updating password.\n"; $stmt->execute();
$db->update('users', ['password_hash' => $hasher->hash($password)], 'id = ?', [$existing['id']]); if ($stmt->fetch()) {
echo "Password updated.\n"; echo "Super Admin already exists. Skipping.\n";
exit(0); exit(0);
} }
$id = $db->insert('users', [ $username = $_ENV['SA_USERNAME'] ?? 'mahmoud';
'username' => $username, $password = $_ENV['SA_PASSWORD'] ?? 'Admin@12345';
'password_hash' => $hasher->hash($password), $nameEn = $_ENV['SA_NAME_EN'] ?? 'Mahmoud Aglan';
'role' => 'super_admin', $nameAr = $_ENV['SA_NAME_AR'] ?? 'محمود عجلان';
'full_name_en' => 'System Administrator',
'full_name_ar' => 'مدير النظام', $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
'national_id' => '00000000000000',
'date_of_birth' => '1990-01-01', $stmt = $pdo->prepare("
'phone_primary' => '01000000000', INSERT INTO users (
'address' => 'AL-Arcade HQ', username, password_hash, role, full_name_en, full_name_ar,
'emergency_contact_name' => 'Emergency Contact', national_id, date_of_birth, phone_primary, address,
'emergency_contact_phone' => '01000000001', emergency_contact_name, emergency_contact_phone, emergency_contact_relationship,
'emergency_contact_relationship' => 'other', bank_name, bank_account_number, bank_account_holder,
'bank_name' => 'N/A', status, is_active, activation_date, force_password_change
'bank_account_number' => '0000000000', ) VALUES (
'bank_account_holder' => 'System Administrator', ?, ?, 'super_admin', ?, ?,
'status' => 'active', '00000000000000', '1990-01-01', '01000000000', 'AL-Arcade HQ',
'activation_date' => date('Y-m-d'), 'System', '01000000001', 'other',
'is_active' => 1, 'System', '0000000000', ?,
]); 'active', 1, CURDATE(), 1
)
echo "Super Admin created!\n"; ");
echo " ID: {$id}\n";
echo " Username: {$username}\n"; try {
echo " Password: {$password}\n"; $stmt->execute([$username, $hash, $nameEn, $nameAr, $nameEn]);
echo "\nChange this password immediately after first login.\n"; echo "✅ Super Admin created: {$username}\n";
\ No newline at end of file echo " Password: {$password}\n";
echo " ⚠️ Force password change is ON. Change on first login.\n";
} catch (PDOException $e) {
if (str_contains($e->getMessage(), 'Duplicate')) {
echo "Super Admin already exists (duplicate key).\n";
} else {
echo "ERROR: {$e->getMessage()}\n";
exit(1);
}
}
\ No newline at end of file
...@@ -3,109 +3,42 @@ declare(strict_types=1); ...@@ -3,109 +3,42 @@ declare(strict_types=1);
define('ROOT_PATH', dirname(__DIR__)); define('ROOT_PATH', dirname(__DIR__));
require ROOT_PATH . '/bootstrap/autoload.php'; require ROOT_PATH . '/bootstrap/autoload.php';
require ROOT_PATH . '/bootstrap/app.php';
use Engine\Core\Container; $dbConfig = require ROOT_PATH . '/config/database.php';
use Engine\Core\Config;
use Engine\Database\Connection;
$db = Container::getInstance()->resolve(Connection::class); try {
$config = Container::getInstance()->resolve(Config::class); $dsn = "mysql:host={$dbConfig['host']};port={$dbConfig['port']};dbname={$dbConfig['database']};charset={$dbConfig['charset']}";
$pdo = new PDO($dsn, $dbConfig['username'], $dbConfig['password'], $dbConfig['options']);
echo "=== SEEDING DATABASE ===\n\n"; } catch (PDOException $e) {
echo "DB Connection Failed: {$e->getMessage()}\n";
// 1. System Settings exit(1);
$settings = [
['key' => 'full_timer_in_office_day_rate', 'value' => '2400', 'value_type' => 'decimal', 'group' => 'salary'],
['key' => 'full_timer_remote_day_rate', 'value' => '1600', 'value_type' => 'decimal', 'group' => 'salary'],
['key' => 'intern_in_office_day_rate', 'value' => '1000', 'value_type' => 'decimal', 'group' => 'salary'],
['key' => 'intern_remote_day_rate', 'value' => '500', 'value_type' => 'decimal', 'group' => 'salary'],
['key' => 'report_deadline_time', 'value' => '23:59', 'value_type' => 'string', 'group' => 'reports'],
['key' => 'report_grace_hours', 'value' => '24', 'value_type' => 'integer', 'group' => 'reports'],
['key' => 'session_timeout_seconds', 'value' => '28800','value_type' => 'integer', 'group' => 'auth'],
['key' => 'max_login_attempts', 'value' => '5', 'value_type' => 'integer', 'group' => 'auth'],
['key' => 'lockout_duration_seconds', 'value' => '1800', 'value_type' => 'integer', 'group' => 'auth'],
['key' => 'deduction_response_hours', 'value' => '48', 'value_type' => 'integer', 'group' => 'deductions'],
['key' => 'pip_threshold_pct', 'value' => '40', 'value_type' => 'integer', 'group' => 'deductions'],
['key' => 'min_bounty_amount', 'value' => '50', 'value_type' => 'decimal', 'group' => 'bounties'],
['key' => 'admin_bounty_cap', 'value' => '5000', 'value_type' => 'decimal', 'group' => 'bounties'],
['key' => 'admin_monthly_bounty_budget', 'value' => '50000','value_type' => 'decimal', 'group' => 'bounties'],
['key' => 'auto_archive_done_days', 'value' => '30', 'value_type' => 'integer', 'group' => 'boards'],
['key' => 'payroll_calculation_day', 'value' => '25', 'value_type' => 'integer', 'group' => 'payroll'],
['key' => 'show_rank_on_hud', 'value' => '1', 'value_type' => 'boolean', 'group' => 'display'],
['key' => 'dark_mode_available', 'value' => '1', 'value_type' => 'boolean', 'group' => 'display'],
['key' => 'company_name', 'value' => 'AL-Arcade', 'value_type' => 'string', 'group' => 'general'],
['key' => 'max_schedule_changes_per_quarter', 'value' => '1', 'value_type' => 'integer', 'group' => 'schedules'],
['key' => 'schedule_change_notice_days', 'value' => '7', 'value_type' => 'integer', 'group' => 'schedules'],
['key' => 'auto_approval_enabled', 'value' => '1', 'value_type' => 'boolean', 'group' => 'reports'],
];
foreach ($settings as $s) {
$exists = $db->fetchOne("SELECT `key` FROM system_settings WHERE `key` = ?", [$s['key']]);
if (!$exists) {
$db->insert('system_settings', $s);
echo " ✅ Setting: {$s['key']}\n";
}
} }
// 2. Default Labels $seedFile = ROOT_PATH . '/database/seed.sql';
$labels = $config->all('default_labels'); if (!file_exists($seedFile)) {
$sa = $db->fetchOne("SELECT id FROM users WHERE role = 'super_admin' LIMIT 1"); echo "Seed file not found: {$seedFile}\n";
$saId = $sa ? $sa['id'] : 1; exit(1);
foreach ($labels as $label) {
$exists = $db->fetchOne("SELECT id FROM labels WHERE text = ? AND scope = 'organization'", [$label['text']]);
if (!$exists) {
$db->insert('labels', [
'text' => $label['text'],
'bg_color' => $label['bg_color'],
'text_color' => $label['text_color'],
'scope' => 'organization',
'board_id' => null,
'created_by_id' => $saId,
]);
echo " ✅ Label: {$label['text']}\n";
}
} }
// 3. Competency Areas $sql = file_get_contents($seedFile);
$areas = [ $statements = array_filter(array_map('trim', explode(';', $sql)), fn($s) => strlen($s) > 5);
'Device maintenance, debugging, and OS troubleshooting',
'Collaborative work and source control (Git)',
'C# mastery: data structures, algorithms, OOP',
'Design patterns, architecture, parallel/concurrent programming',
'Legacy code: maintenance, debugging, upgrading',
'Unity Game Development and render pipelines',
'Deployment: PC, Android, Web',
'Unity Netcode for GameObjects + Unity multiplayer services',
'Industry-standard Unity assets (DOTween, Feel, TextMeshPro, etc.)',
'Unity + MySQL: basic CRUD',
'Unity + Firebase services',
];
foreach ($areas as $i => $area) { $success = 0;
$exists = $db->fetchOne("SELECT id FROM competency_areas WHERE name = ?", [$area]); $skipped = 0;
if (!$exists) { foreach ($statements as $stmt) {
$db->insert('competency_areas', [ if (stripos($stmt, 'USE ') === 0 || stripos($stmt, '--') === 0 || stripos($stmt, 'SET ') === 0) {
'name' => $area, continue;
'position' => $i + 1,
'is_active' => 1,
]);
echo " ✅ Competency: " . substr($area, 0, 50) . "...\n";
} }
} try {
$pdo->exec($stmt);
// 4. Background Jobs $success++;
$jobs = $config->all('scheduled_jobs'); } catch (PDOException $e) {
foreach (array_keys($jobs) as $key) { if (str_contains($e->getMessage(), 'Duplicate')) {
$exists = $db->fetchOne("SELECT id FROM background_jobs WHERE job_key = ?", [$key]); $skipped++;
if (!$exists) { } else {
$db->insert('background_jobs', [ echo "⚠️ {$e->getMessage()}\n SQL: " . substr($stmt, 0, 80) . "...\n";
'job_key' => $key, }
'is_enabled' => 1,
]);
echo " ✅ Job: {$key}\n";
} }
} }
echo "\n=== SEEDING COMPLETE ===\n"; echo "✅ Seed complete: {$success} executed, {$skipped} skipped (already exist).\n";
\ No newline at end of file \ No newline at end of file
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/**
* Cron entry point. Run every minute:
* * * * * * php /var/www/html/cron/runner.php >> /var/www/html/storage/logs/cron.log 2>&1
*/
define('ROOT_PATH', dirname(__DIR__)); define('ROOT_PATH', dirname(__DIR__));
require ROOT_PATH . '/bootstrap/autoload.php'; require ROOT_PATH . '/bootstrap/autoload.php';
require ROOT_PATH . '/bootstrap/app.php'; require ROOT_PATH . '/bootstrap/app.php';
...@@ -8,9 +13,20 @@ require ROOT_PATH . '/bootstrap/app.php'; ...@@ -8,9 +13,20 @@ require ROOT_PATH . '/bootstrap/app.php';
use Engine\Core\Container; use Engine\Core\Container;
use Engine\Scheduler\JobRunner; use Engine\Scheduler\JobRunner;
$runner = Container::getInstance()->resolve(JobRunner::class); $container = Container::getInstance();
$results = $runner->runDue(); $runner = $container->resolve(JobRunner::class);
echo "[" . date('Y-m-d H:i:s') . "] Cron runner started.\n";
try {
$results = $runner->runDue();
foreach ($results as $key => $result) {
$status = $result['success'] ? '✅' : '❌';
echo " {$status} {$key}: {$result['message']}\n";
}
} catch (\Throwable $e) {
echo " ❌ Runner error: {$e->getMessage()}\n";
error_log("[Cron Error] {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}");
}
foreach ($results as $job => $status) { echo "[" . date('Y-m-d H:i:s') . "] Cron runner finished.\n";
echo "[" . date('Y-m-d H:i:s') . "] {$job}: {$status}\n"; \ No newline at end of file
}
\ No newline at end of file
-- ============================================================================
-- AL-ARCADE HR PLATFORM v3.0 — SEED DATA
-- System Settings, Competency Areas, Default Labels
-- ============================================================================
USE `al_arcade_hr`;
-- ============================================================================
-- SYSTEM SETTINGS
-- ============================================================================
INSERT IGNORE INTO `system_settings` (`key`, `value`, `value_type`, `group`) VALUES
-- Schedule & Time
('working_days', '0,1,2,3,4', 'string', 'schedule'),
('report_deadline_time', '23:59', 'string', 'schedule'),
('report_grace_hours', '24', 'integer', 'schedule'),
('unreported_detection_time', '01:00', 'string', 'schedule'),
('session_timeout_hours', '8', 'integer', 'schedule'),
('max_login_attempts', '5', 'integer', 'schedule'),
('lockout_duration_minutes', '30', 'integer', 'schedule'),
-- Salary
('ft_in_office_day_rate', '2400', 'decimal', 'salary'),
('ft_remote_day_rate', '1600', 'decimal', 'salary'),
('intern_in_office_day_rate', '1000', 'decimal', 'salary'),
('intern_remote_day_rate', '500', 'decimal', 'salary'),
-- Payroll
('payroll_calc_day', '25', 'integer', 'payroll'),
('payment_processing_days', '15', 'integer', 'payroll'),
-- Evaluation
('eval_period_start_day', '1', 'integer', 'evaluation'),
('tech_eval_deadline_days', '5', 'integer', 'evaluation'),
('prof_eval_deadline_days', '7', 'integer', 'evaluation'),
('contractor_response_days', '5', 'integer', 'evaluation'),
-- Deduction
('deduction_response_hours', '48', 'integer', 'deduction'),
('deduction_initiation_window_days', '5', 'integer', 'deduction'),
('pip_threshold_percent', '40', 'integer', 'deduction'),
('auto_apply_on_no_response', '1', 'boolean', 'deduction'),
-- Bounty
('min_bounty_amount', '50', 'decimal', 'bounty'),
('admin_bounty_cap', '5000', 'decimal', 'bounty'),
('admin_monthly_bounty_budget', '50000', 'decimal', 'bounty'),
-- Board
('default_auto_archive_days', '30', 'integer', 'board'),
('default_wip_limit', '0', 'integer', 'board'),
-- Schedule Change
('max_schedule_changes_per_quarter', '1', 'integer', 'schedule_change'),
('schedule_change_notice_days', '7', 'integer', 'schedule_change'),
-- Display
('show_rank_on_hud', '1', 'boolean', 'display'),
('dark_mode_available', '1', 'boolean', 'display'),
('default_theme', 'light', 'string', 'display'),
('company_name', 'AL-Arcade', 'string', 'display'),
-- Reports
('auto_approval_enabled', '1', 'boolean', 'reports');
-- ============================================================================
-- COMPETENCY AREAS (11 default areas)
-- ============================================================================
INSERT IGNORE INTO `competency_areas` (`id`, `name`, `position`, `is_active`) VALUES
(1, 'Device Maintenance, Debugging & OS Troubleshooting', 1, 1),
(2, 'Collaborative Work & Source Control (Git)', 2, 1),
(3, 'C# Mastery: Data Structures, Algorithms, OOP', 3, 1),
(4, 'Design Patterns, Architecture, Parallel/Concurrent Programming', 4, 1),
(5, 'Legacy Code: Maintenance, Debugging, Upgrading', 5, 1),
(6, 'Unity Game Development & Render Pipelines', 6, 1),
(7, 'Deployment: PC, Android, Web', 7, 1),
(8, 'Unity Netcode for GameObjects & Multiplayer Services', 8, 1),
(9, 'Industry-Standard Unity Assets (DOTween, Feel, TMP, etc.)', 9, 1),
(10, 'Unity + MySQL: Basic CRUD', 10, 1),
(11, 'Unity + Firebase Services', 11, 1);
-- ============================================================================
-- BACKGROUND JOBS (seed registry)
-- ============================================================================
INSERT IGNORE INTO `background_jobs` (`job_key`, `is_enabled`) VALUES
('detect_unreported_days', 1),
('auto_archive_done_cards', 1),
('send_deadline_reminders', 1),
('invite_expiry', 1),
('session_cleanup', 1),
('auto_apply_deductions', 1),
('escalate_deadline_deductions', 1),
('open_evaluation_cycle', 1),
('evaluation_reminders', 1),
('compile_evaluations', 1),
('pip_checkin_reminders', 1),
('learning_goal_reminders', 1),
('meeting_reminders', 1),
('contract_expiry_warnings', 1),
('create_recurring_cards', 1);
\ No newline at end of file
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/public
<Directory /var/www/html/public>
AllowOverride All
Require all granted
Options -Indexes +FollowSymLinks
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
\ No newline at end of file
#!/bin/bash
set -e
echo "=== AL-ARCADE HR Platform v3.0 — Starting ==="
# Wait for MySQL to be ready
echo "Waiting for MySQL..."
MAX_TRIES=30
COUNT=0
while ! php -r "try { new PDO('mysql:host=${DB_HOST:-srv-captain--mysql-db};port=${DB_PORT:-3306}', '${DB_USER:-root}', '${DB_PASS:-Alarcade123#}'); echo 'OK'; } catch(Exception \$e) { exit(1); }" 2>/dev/null; do
COUNT=$((COUNT + 1))
if [ $COUNT -ge $MAX_TRIES ]; then
echo "ERROR: MySQL not available after ${MAX_TRIES} attempts. Starting anyway..."
break
fi
echo " MySQL not ready yet... (attempt $COUNT/$MAX_TRIES)"
sleep 2
done
# Run schema if database is empty
TABLE_COUNT=$(php -r "
try {
\$pdo = new PDO('mysql:host=${DB_HOST:-srv-captain--mysql-db};port=${DB_PORT:-3306};dbname=${DB_NAME:-al_arcade_hr}', '${DB_USER:-root}', '${DB_PASS:-Alarcade123#}');
\$r = \$pdo->query(\"SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${DB_NAME:-al_arcade_hr}'\");
echo \$r->fetchColumn();
} catch(Exception \$e) { echo '0'; }
" 2>/dev/null || echo "0")
if [ "$TABLE_COUNT" -lt "70" ]; then
echo "Database has $TABLE_COUNT tables (need 73). Running schema..."
if [ -f /var/www/html/database/schema.sql ]; then
mysql -h "${DB_HOST:-srv-captain--mysql-db}" -P "${DB_PORT:-3306}" -u "${DB_USER:-root}" -p"${DB_PASS:-Alarcade123#}" < /var/www/html/database/schema.sql 2>/dev/null && echo "Schema deployed." || echo "Schema deployment failed or already exists."
fi
echo "Running seed data..."
if [ -f /var/www/html/database/seed.sql ]; then
mysql -h "${DB_HOST:-srv-captain--mysql-db}" -P "${DB_PORT:-3306}" -u "${DB_USER:-root}" -p"${DB_PASS:-Alarcade123#}" "${DB_NAME:-al_arcade_hr}" < /var/www/html/database/seed.sql 2>/dev/null && echo "Seed data applied." || echo "Seed already exists or failed."
fi
echo "Creating super admin..."
php /var/www/html/cli/create-superadmin.php 2>/dev/null || echo "Super admin may already exist."
else
echo "Database has $TABLE_COUNT tables. Skipping schema."
fi
# Fix permissions
chown -R www-data:www-data /var/www/html/storage 2>/dev/null || true
echo "=== Ready. Launching Apache ==="
exec "$@"
\ No newline at end of file
; AL-ARCADE HR Platform — Production PHP Config
upload_max_filesize = 25M
post_max_size = 30M
memory_limit = 512M
max_execution_time = 120
max_input_time = 60
display_errors = Off
log_errors = On
error_log = /var/www/html/storage/logs/php-error.log
date.timezone = Africa/Cairo
session.cookie_httponly = 1
session.cookie_secure = 0
session.use_strict_mode = 1
opcache.enable = 1
opcache.memory_consumption = 128
opcache.max_accelerated_files = 10000
opcache.validate_timestamps = 0
\ No newline at end of file
<?php <?php
use Engine\Core\Router; use Engine\Core\Router;
use Modules\Offboarding\Controllers\OffboardingController;
return function (Router $router) { Router::group('/offboarding', ['middleware' => ['auth', 'csrf']], function () {
$router->post('/offboarding/initiate', [OffboardingController::class, 'initiate']); Router::post('/terminate', [\Modules\Offboarding\Controllers\OffboardingController::class, 'initiate']);
$router->get('/offboarding/settlement/{userId}', [OffboardingController::class, 'calculateFinalSettlement']); Router::get('/settlement/{userId}', [\Modules\Offboarding\Controllers\OffboardingController::class, 'calculateFinalSettlement']);
});
$router->post('/api/offboarding/initiate', [OffboardingController::class, 'initiate']); \ No newline at end of file
$router->get('/api/offboarding/settlement/{userId}', [OffboardingController::class, 'calculateFinalSettlement']);
};
\ No newline at end of file
<?php
use Engine\Core\Router;
Router::group('/invites', ['middleware' => ['auth', 'csrf']], function () {
Router::get('', [\Modules\Onboarding\Controllers\InviteController::class, 'index']);
Router::post('', [\Modules\Onboarding\Controllers\InviteController::class, 'create']);
Router::post('/{inviteId}/revoke', [\Modules\Onboarding\Controllers\InviteController::class, 'revoke']);
Router::delete('/{inviteId}', [\Modules\Onboarding\Controllers\InviteController::class, 'delete']);
});
\ No newline at end of file
<?php <?php
use Engine\Core\Router; use Engine\Core\Router;
use Modules\SavedFilters\Controllers\SavedFilterController;
return function (Router $router) { Router::group('/saved-filters', ['middleware' => ['auth', 'csrf']], function () {
$router->get('/saved-filters', [SavedFilterController::class, 'index']); Router::get('', [\Modules\SavedFilters\Controllers\SavedFilterController::class, 'index']);
$router->post('/saved-filters', [SavedFilterController::class, 'create']); Router::post('', [\Modules\SavedFilters\Controllers\SavedFilterController::class, 'create']);
$router->delete('/saved-filters/{filterId}', [SavedFilterController::class, 'delete']); Router::delete('/{filterId}', [\Modules\SavedFilters\Controllers\SavedFilterController::class, 'delete']);
});
$router->get('/api/saved-filters', [SavedFilterController::class, 'index']); \ No newline at end of file
$router->post('/api/saved-filters', [SavedFilterController::class, 'create']);
$router->delete('/api/saved-filters/{filterId}', [SavedFilterController::class, 'delete']);
};
\ No newline at end of file
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
declare(strict_types=1); declare(strict_types=1);
define('ROOT_PATH', dirname(__DIR__)); define('ROOT_PATH', dirname(__DIR__));
define('START_TIME', microtime(true));
require ROOT_PATH . '/bootstrap/autoload.php'; require ROOT_PATH . '/bootstrap/autoload.php';
require ROOT_PATH . '/bootstrap/app.php'; require ROOT_PATH . '/bootstrap/app.php';
$app = Engine\Core\App::getInstance(); use Engine\Core\App;
use Engine\Core\Container;
$app = Container::getInstance()->resolve(App::class);
$app->run(); $app->run();
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment