feat: Add comprehensive documentation suite and reorganize project structure

- Created complete documentation in docs/ directory
- Added PROJECT_OVERVIEW.md with feature highlights and getting started guide
- Added ARCHITECTURE.md with system design and technical details
- Added SECURITY.md with comprehensive security implementation guide
- Added DEVELOPMENT.md with development workflows and best practices
- Added DEPLOYMENT.md with production deployment instructions
- Added API.md with complete REST API documentation
- Added CONTRIBUTING.md with contribution guidelines
- Added CHANGELOG.md with version history and migration notes
- Reorganized all documentation files into docs/ directory for better organization
- Updated README.md with proper documentation links and quick navigation
- Enhanced project structure with professional documentation standards
This commit is contained in:
SamiAhmed7777
2025-10-21 00:39:45 -07:00
commit 0b7e2d0a5b
6080 changed files with 1332936 additions and 0 deletions

346
admin.php Normal file
View File

@@ -0,0 +1,346 @@
<?php
require_once __DIR__ . '/admin/includes/data_providers.php';
require_once __DIR__ . '/admin/includes/layout.php';
$pdo = admin_pdo();
if (isset($_GET['action'])) {
header('Content-Type: application/json');
$action = $_GET['action'];
switch ($action) {
case 'stats':
echo json_encode([
'users' => admin_fetch_user_stats($pdo),
'videos' => admin_fetch_video_stats($pdo),
'streams' => admin_fetch_stream_stats($pdo),
'totalViews' => admin_fetch_total_views($pdo),
'health' => admin_fetch_system_health($pdo),
]);
break;
case 'activity':
echo json_encode(['activity' => admin_fetch_recent_activity($pdo, 12)]);
break;
case 'pending':
echo json_encode(['pending' => admin_fetch_pending_videos($pdo, 10)]);
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Unknown action']);
}
exit;
}
$userStats = admin_fetch_user_stats($pdo);
$videoStats = admin_fetch_video_stats($pdo);
$streamStats = admin_fetch_stream_stats($pdo);
$totalViews = admin_fetch_total_views($pdo);
$health = admin_fetch_system_health($pdo);
$recentActivity = admin_fetch_recent_activity($pdo);
$pendingContent = admin_fetch_pending_videos($pdo);
$quickActions = [
['label' => 'User Management', 'description' => 'Review members, roles, and status', 'icon' => '&#128101;', 'url' => '/admin_users.php'],
['label' => 'Content Moderation', 'description' => 'Approve, reject, or feature uploads', 'icon' => '&#127916;', 'url' => '/admin_content_management.php'],
['label' => 'Token Economy', 'description' => 'Monitor purchases and balances', 'icon' => '&#128176;', 'url' => '/admin_token_dashboard.php'],
['label' => 'Background Jobs', 'description' => 'Track queue throughput', 'icon' => '&#9881;', 'url' => '/f_modules/m_backend/queue_management.php'],
['label' => 'System Logs', 'description' => 'Audit platform health and errors', 'icon' => '&#128221;', 'url' => '/f_modules/m_backend/log_viewer.php'],
['label' => 'Security Center', 'description' => 'Manage bans, fingerprints, and IPs', 'icon' => '&#128272;', 'url' => '/f_modules/m_backend/ip_management.php'],
];
admin_page_start('Platform Dashboard', 'dashboard');
?>
<section class="stats-grid">
<article class="stat-card">
<div class="stat-card__icon">&#128101;</div>
<div class="stat-card__label">Total Users</div>
<div class="stat-card__value" id="metric-users-total"><?= admin_format_number($userStats['total']) ?></div>
<div class="stat-card__meta">
<span><strong id="metric-users-today"><?= admin_format_number($userStats['today']) ?></strong> today</span>
<span><strong id="metric-users-active"><?= admin_format_number($userStats['active']) ?></strong> active</span>
</div>
</article>
<article class="stat-card">
<div class="stat-card__icon">&#127916;</div>
<div class="stat-card__label">Video Library</div>
<div class="stat-card__value" id="metric-videos-total"><?= admin_format_number($videoStats['total']) ?></div>
<div class="stat-card__meta">
<span><strong id="metric-videos-approved"><?= admin_format_number($videoStats['approved']) ?></strong> approved</span>
<span><strong id="metric-videos-pending"><?= admin_format_number($videoStats['pending']) ?></strong> awaiting review</span>
</div>
</article>
<article class="stat-card">
<div class="stat-card__icon">&#128225;</div>
<div class="stat-card__label">Live Streams</div>
<div class="stat-card__value" id="metric-streams-total"><?= admin_format_number($streamStats['total']) ?></div>
<div class="stat-card__meta">
<span><strong id="metric-streams-active"><?= admin_format_number($streamStats['active']) ?></strong> live now</span>
<span><strong id="metric-streams-today"><?= admin_format_number($streamStats['today']) ?></strong> started today</span>
</div>
</article>
<article class="stat-card">
<div class="stat-card__icon">&#128200;</div>
<div class="stat-card__label">Total Views</div>
<div class="stat-card__value" id="metric-views-total"><?= admin_format_number($totalViews) ?></div>
<div class="stat-card__meta">
<span>Platform-wide engagement this week</span>
</div>
</article>
</section>
<div class="grid grid--two">
<section class="card">
<div class="card__header">
<h2>Recent Activity</h2>
<div class="card__header-actions">
<span class="spinner" id="activity-spinner" hidden></span>
<button class="admin-button admin-button--ghost" id="refresh-button" type="button">Refresh Data</button>
</div>
</div>
<div id="activity-list" class="timeline">
<?php if (empty($recentActivity)): ?>
<div class="empty-state">No recent activity recorded.</div>
<?php else: ?>
<?php foreach ($recentActivity as $activity): ?>
<article class="timeline__item">
<div class="timeline__icon">&#129517;</div>
<div class="timeline__content">
<div class="timeline__title"><?= admin_escape($activity['request_uri']) ?></div>
<div class="timeline__meta">
<?= admin_escape($activity['ip_address']) ?> · <?= admin_format_datetime($activity['timestamp']) ?>
</div>
<div class="timeline__details"><?= admin_escape($activity['user_agent'] ?? 'Unknown client') ?></div>
</div>
</article>
<?php endforeach; ?>
<?php endif; ?>
</div>
</section>
<section class="card">
<div class="card__header">
<h2>System Health</h2>
</div>
<div id="health-list" class="health-grid">
<?php foreach ($health as $key => $status): ?>
<?php
$state = match ($status['status']) {
'healthy' => 'success',
'warning' => 'warning',
'error' => 'danger',
default => 'muted',
};
$iconEntity = [
'success' => '&#9989;',
'warning' => '&#9888;',
'danger' => '&#10060;',
'muted' => '&#8505;',
][$state];
?>
<div class="health-card health-card--<?= $state ?>">
<div class="health-card__icon"><?= $iconEntity ?></div>
<div>
<div class="health-card__title"><?= admin_escape(ucfirst($key)) ?></div>
<div class="health-card__details"><?= admin_escape($status['details'] ?? 'No data') ?></div>
</div>
</div>
<?php endforeach; ?>
</div>
</section>
</div>
<section class="card">
<div class="card__header">
<h2>Pending Content Review</h2>
<a class="admin-button admin-button--ghost" href="/admin_content_management.php">Moderation center</a>
</div>
<div id="pending-list">
<?php if (empty($pendingContent)): ?>
<div class="empty-state">All submissions are currently reviewed.</div>
<?php else: ?>
<table>
<thead>
<tr>
<th>Title</th>
<th>User</th>
<th>Uploaded</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($pendingContent as $item): ?>
<tr>
<td><?= admin_escape($item['file_title']) ?></td>
<td>#<?= admin_escape((string) $item['usr_id']) ?></td>
<td><?= admin_format_datetime($item['upload_date']) ?></td>
<td>
<span class="badge badge--warning">
<?= admin_escape(ucfirst($item['processing_status'] ?? 'pending')) ?>
</span>
</td>
<td>
<a class="admin-button admin-button--ghost" href="/f_modules/m_backend/files.php?search=<?= urlencode($item['file_key']) ?>">Review</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</section>
<section class="card">
<div class="card__header">
<h2>Quick Actions</h2>
</div>
<div class="quick-actions">
<?php foreach ($quickActions as $action): ?>
<a class="quick-actions__item" href="<?= admin_escape($action['url']) ?>">
<div class="quick-actions__icon"><?= $action['icon'] ?></div>
<div class="quick-actions__content">
<div class="quick-actions__title"><?= admin_escape($action['label']) ?></div>
<div class="quick-actions__desc"><?= admin_escape($action['description']) ?></div>
</div>
</a>
<?php endforeach; ?>
</div>
</section>
<?php
$script = <<<'JS'
const metricMap = {
'metric-users-total': data => data.users.total,
'metric-users-today': data => data.users.today,
'metric-users-active': data => data.users.active,
'metric-videos-total': data => data.videos.total,
'metric-videos-approved': data => data.videos.approved,
'metric-videos-pending': data => data.videos.pending,
'metric-streams-total': data => data.streams.total,
'metric-streams-active': data => data.streams.active,
'metric-streams-today': data => data.streams.today,
'metric-views-total': data => data.totalViews,
};
const healthList = document.getElementById('health-list');
const activityList = document.getElementById('activity-list');
const pendingList = document.getElementById('pending-list');
const refreshButton = document.getElementById('refresh-button');
const activitySpinner = document.getElementById('activity-spinner');
function renderHealth(health) {
if (!healthList) return;
const fragments = [];
const icons = { success: '\u2705', warning: '\u26A0', danger: '\u274C', muted: '\u2139' };
for (const [key, status] of Object.entries(health)) {
const state = status.status === 'healthy' ? 'success'
: status.status === 'warning' ? 'warning'
: status.status === 'error' ? 'danger'
: 'muted';
fragments.push(`
<div class="health-card health-card--${state}">
<div class="health-card__icon">${icons[state]}</div>
<div>
<div class="health-card__title">${key.charAt(0).toUpperCase() + key.slice(1)}</div>
<div class="health-card__details">${status.details ?? 'No data'}</div>
</div>
</div>
`);
}
healthList.innerHTML = fragments.join('');
}
function renderActivity(items) {
if (!activityList) return;
if (!items || !items.length) {
activityList.innerHTML = '<div class="empty-state">No recent activity recorded.</div>';
return;
}
activityList.innerHTML = items.map(item => `
<article class="timeline__item">
<div class="timeline__icon">&#129517;</div>
<div class="timeline__content">
<div class="timeline__title">${item.request_uri ?? '/'}</div>
<div class="timeline__meta">${item.ip_address ?? 'Unknown IP'} · ${item.timestamp ?? ''}</div>
<div class="timeline__details">${item.user_agent ?? 'Unknown client'}</div>
</div>
</article>
`).join('');
}
function renderPending(items) {
if (!pendingList) return;
if (!items || !items.length) {
pendingList.innerHTML = '<div class="empty-state">All submissions are currently reviewed.</div>';
return;
}
pendingList.innerHTML = `
<table>
<thead>
<tr>
<th>Title</th>
<th>User</th>
<th>Uploaded</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
${items.map(item => `
<tr>
<td>${item.file_title ?? 'Untitled'}</td>
<td>#${item.usr_id ?? 'N/A'}</td>
<td>${item.upload_date ?? ''}</td>
<td><span class="badge badge--warning">${(item.processing_status ?? 'pending').toUpperCase()}</span></td>
<td><a class="admin-button admin-button--ghost" href="/f_modules/m_backend/files.php?search=${encodeURIComponent(item.file_key ?? '')}">Review</a></td>
</tr>
`).join('')}
</tbody>
</table>
`;
}
async function refreshData() {
if (activitySpinner) activitySpinner.hidden = false;
try {
const [statsRes, activityRes, pendingRes] = await Promise.all([
fetch('?action=stats').then(r => r.json()),
fetch('?action=activity').then(r => r.json()),
fetch('?action=pending').then(r => r.json()),
]);
Object.entries(metricMap).forEach(([id, getter]) => {
const el = document.getElementById(id);
if (el) {
const value = getter(statsRes);
el.textContent = Number.isFinite(value) ? value.toLocaleString() : value;
}
});
renderHealth(statsRes.health);
renderActivity(activityRes.activity);
renderPending(pendingRes.pending);
} catch (error) {
console.error('Failed to refresh dashboard data', error);
} finally {
if (activitySpinner) activitySpinner.hidden = true;
}
}
if (refreshButton) {
refreshButton.addEventListener('click', refreshData);
}
setInterval(refreshData, 30000);
JS;
admin_page_end($script);