Refactor code structure for improved readability and maintainability

هذا الالتزام موجود في:
2026-07-28 00:15:47 +03:00
الأصل 439a31ba93
التزام 04a73e93fa
14 ملفات معدلة مع 461 إضافات و77 حذوفات

13
Q1/Dashboard/Dockerfile Normal file
عرض الملف

@@ -0,0 +1,13 @@
# Minimal static-file server for just the dashboard, so it can be deployed
# as its own service on Ghaymah, separate from the API container.
FROM nginx:alpine
# nginx's default port is 80; most container platforms (Ghaymah included,
# per its port-configuration step) let you pick which port the service
# listens on, so we keep nginx's default here and just set that port
# when creating the service.
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80

213
Q1/Dashboard/index.html Normal file
عرض الملف

@@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>لوحة مراقبة الـ API</title>
<style>
:root{
--bg:#f4f7f6;
--card:#ffffff;
--border:#e3e8ec;
--text:#25313c;
--muted:#7a8894;
--accent:#0056b3;
--up:#28a745;
--down:#dc3545;
--warn:#f0ad4e;
}
*{ box-sizing:border-box; }
body{
font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background:var(--bg);
display:flex; justify-content:center; align-items:center;
min-height:100vh; margin:0; padding:24px;
}
.dashboard{
background:var(--card);
padding:30px;
border-radius:14px;
box-shadow:0 8px 24px rgba(15,35,55,0.08);
text-align:center;
width:420px;
max-width:100%;
border:1px solid var(--border);
}
h2{
color:var(--text);
margin:0 0 22px;
display:flex;
align-items:center;
justify-content:center;
gap:10px;
font-size:1.25rem;
}
.status-dot{
width:12px; height:12px; border-radius:50%;
background:#9aa5ad;
box-shadow:0 0 0 0 rgba(154,165,173,0.5);
flex-shrink:0;
}
.status-dot.online{ background:var(--up); animation:pulse-up 2s infinite; }
.status-dot.offline{ background:var(--down); animation:pulse-down 2s infinite; }
@keyframes pulse-up{
0%{ box-shadow:0 0 0 0 rgba(40,167,69,0.55); }
70%{ box-shadow:0 0 0 9px rgba(40,167,69,0); }
100%{ box-shadow:0 0 0 0 rgba(40,167,69,0); }
}
@keyframes pulse-down{
0%{ box-shadow:0 0 0 0 rgba(220,53,69,0.55); }
70%{ box-shadow:0 0 0 9px rgba(220,53,69,0); }
100%{ box-shadow:0 0 0 0 rgba(220,53,69,0); }
}
.metric{
background:#eef2f5;
margin:10px 0;
padding:14px 16px;
border-radius:9px;
font-size:1.05rem;
display:flex;
justify-content:space-between;
align-items:center;
}
.metric span{ font-weight:700; color:var(--accent); font-variant-numeric:tabular-nums; }
.metric span.status-online{ color:var(--up); }
.metric span.status-offline{ color:var(--down); }
.meta-row{
margin-top:16px;
font-size:0.75rem;
color:var(--muted);
display:flex;
justify-content:space-between;
}
.api-row{
margin-top:18px;
padding-top:14px;
border-top:1px dashed var(--border);
text-align:right;
}
.api-row label{
display:block;
font-size:0.72rem;
color:var(--muted);
margin-bottom:6px;
}
.api-row .input-group{
display:flex;
gap:6px;
}
.api-row input{
flex:1;
padding:8px 10px;
border:1px solid var(--border);
border-radius:7px;
font-size:0.8rem;
direction:ltr;
text-align:left;
}
.api-row button{
padding:8px 14px;
border:none;
border-radius:7px;
background:var(--accent);
color:#fff;
font-size:0.8rem;
cursor:pointer;
}
.api-row button:hover{ opacity:0.9; }
</style>
</head>
<body>
<div class="dashboard">
<h2>مراقبة النظام <span id="statusDot" class="status-dot"></span></h2>
<div class="metric">
الحالة: <span id="statusText">جاري التحميل...</span>
</div>
<div class="metric">
زمن الاستجابة: <span id="responseTime">— ms</span>
</div>
<div class="metric">
عدد الطلبات الإجمالي: <span id="requestCount"></span>
</div>
<div class="meta-row">
<span id="uptimeText">التشغيل: —</span>
<span id="lastUpdated">آخر تحديث: —</span>
</div>
<div class="api-row">
<label for="apiInput">عنوان الـ API (health endpoint):</label>
<div class="input-group">
<input id="apiInput" type="text" placeholder="https://backend-06febdb2d9f4.hosted.ghaymah.systems/health">
<button id="apiSave">حفظ</button>
</div>
</div>
</div>
<script>
// This copy of the dashboard is meant to be hosted on its own — separately
// from the API — so it needs to be told where the API lives. Resolution
// order:
// 1. ?api=<url> query-string param, e.g. index.html?api=https://foo/health
// 2. the value typed into the input box below (kept only in memory /
// in the URL — nothing is written to disk or browser storage)
// 3. falls back to the hosted backend URL provided for this project.
const POLL_MS = 5000;
const DEFAULT_HEALTH_URL = 'https://backend-06febdb2d9f4.hosted.ghaymah.systems/health';
let healthUrl = new URLSearchParams(window.location.search).get('api') || DEFAULT_HEALTH_URL;
const apiInput = document.getElementById('apiInput');
apiInput.value = healthUrl === '/health' ? '' : healthUrl;
document.getElementById('apiSave').addEventListener('click', () => {
const val = apiInput.value.trim();
if (val) {
healthUrl = val;
const url = new URL(window.location.href);
url.searchParams.set('api', val);
window.history.replaceState({}, '', url); // shareable link, no storage used
fetchMetrics();
}
});
function fmtUptime(seconds){
if (seconds === undefined || seconds === null) return '—';
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = Math.floor(seconds % 60);
return `${h}h ${m}m ${s}s`;
}
async function fetchMetrics(){
try {
const res = await fetch(healthUrl, { cache: 'no-store' });
if (!res.ok) throw new Error('HTTP ' + res.status);
const data = await res.json();
const statusEl = document.getElementById('statusText');
statusEl.innerText = data.status || 'Online';
statusEl.className = 'status-online';
document.getElementById('statusDot').className = 'status-dot online';
document.getElementById('responseTime').innerText = (data.response_time_ms ?? 0) + ' ms';
document.getElementById('requestCount').innerText = data.request_count ?? '—';
document.getElementById('uptimeText').innerText = 'التشغيل: ' + fmtUptime(data.uptime_seconds);
document.getElementById('lastUpdated').innerText =
'آخر تحديث: ' + new Date().toLocaleTimeString('ar-EG');
} catch (error) {
const statusEl = document.getElementById('statusText');
statusEl.innerText = 'انقطاع الاتصال (Offline)';
statusEl.className = 'status-offline';
document.getElementById('statusDot').className = 'status-dot offline';
document.getElementById('responseTime').innerText = '—';
}
}
fetchMetrics();
setInterval(fetchMetrics, POLL_MS);
</script>
</body>
</html>

84
Q1/README.md Normal file
عرض الملف

@@ -0,0 +1,84 @@
# API + Health Monitor + Dashboard (for ghaymah.systems)
This is your uploaded project (`server.js`, `monitor.sh`, `index.html`,
`Dockerfile`) with three functional bugs fixed and a couple of production
hardening tweaks. Nothing about your architecture changed.
## What was wrong and what I changed
1. **`index.html` was fetching the wrong URL.**
`const API_URL = "";` then `fetch(API_URL)` calls the *current page*
(`/`), not `/health` — so it was trying to `JSON.parse()` an HTML page
and always fell into the `catch` block ("Offline"), even when the API
was healthy. Fixed to `fetch('/health')`.
2. **`server.js` had no route serving `index.html`.**
The dashboard needs to be reachable somewhere. I added
`express.static('public')` and moved `index.html` into `public/`, so the
dashboard is served at `/` and the plain-text welcome message moved to
`/api` so the two don't collide.
3. **`monitor.sh` referenced `$response_time`, which was never set** — the
response-time column was always empty. Fixed by measuring it directly
with `curl -w "%{time_total}"`. Also added a fallback JSON parser for
when `jq` isn't installed, and an optional CSV log file.
4. **Dockerfile ran `npm init -y && npm install` on every build**, with no
lockfile/manifest — slow, non-reproducible, and re-downloads
dependencies on every rebuild even if nothing changed. Added a real
`package.json` and split `COPY package.json` from `COPY server.js` so
Docker caches the `npm install` layer. Also switched
`node:20-alpine3.16` (an older, unsupported Alpine point release) to
`node:20-alpine` (current supported tag).
## Files
```
.
├── Dockerfile
├── package.json
├── server.js
├── public/
│ └── index.html ← dashboard, served at /
└── monitor.sh ← external checker, run it against the deployed URL
```
## Run locally
```bash
npm install
npm start
# open http://localhost:3000 -> dashboard
# open http://localhost:3000/health -> raw JSON
```
In another terminal, point the monitor at it:
```bash
chmod +x monitor.sh
./monitor.sh http://localhost:3000 30
```
## Build & run with Docker
```bash
docker build -t api-health-demo .
docker run -d -p 3000:3000 --name api-health-demo api-health-demo
```
## `/health` response shape
```json
{
"status": "Online",
"uptime_seconds": 42,
"request_count": 17,
"response_time_ms": 3,
"timestamp": "2026-07-27T20:10:00.000Z"
}
```
## Deploy to ghaymah.systems
See `DEPLOY_GHAYMAH.md` for the step-by-step (build → push → create
service → set port 3000 → point `monitor.sh` at the live URL).

عرض الملف

@@ -1,60 +0,0 @@
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>لوحة مراقبة الـ API</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f4f7f6; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
.dashboard { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); text-align: center; width: 400px; }
h2 { color: #333; margin-bottom: 20px; }
.metric { background: #eef2f5; margin: 10px 0; padding: 15px; border-radius: 8px; font-size: 1.2em; display: flex; justify-content: space-between; }
.metric span { font-weight: bold; color: #0056b3; }
.status-dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; background: gray; margin-left: 8px; }
.online { background: #28a745; }
.offline { background: #dc3545; }
</style>
</head>
<body>
<div class="dashboard">
<h2>مراقبة النظام <span id="statusDot" class="status-dot"></span></h2>
<div class="metric">
الحالة: <span id="statusText">جاري التحميل...</span>
</div>
<div class="metric">
زمن الاستجابة: <span id="responseTime">0 ms</span>
</div>
<div class="metric">
عدد الطلبات الإجمالي: <span id="requestCount">0</span>
</div>
</div>
<script>
const API_URL = "";
async function fetchMetrics() {
try {
const res = await fetch(API_URL);
const data = await res.json();
document.getElementById('statusText').innerText = data.status;
document.getElementById('statusText').style.color = '#28a745';
document.getElementById('statusDot').className = 'status-dot online';
document.getElementById('responseTime').innerText = data.response_time_ms + ' ms';
document.getElementById('requestCount').innerText = data.request_count;
} catch (error) {
document.getElementById('statusText').innerText = 'انقطاع الاتصال (Offline)';
document.getElementById('statusText').style.color = '#dc3545';
document.getElementById('statusDot').className = 'status-dot offline';
document.getElementById('responseTime').innerText = '-';
}
}
setInterval(fetchMetrics, 5000);
fetchMetrics();
</script>
</body>
</html>

14
Q1/package.json Normal file
عرض الملف

@@ -0,0 +1,14 @@
{
"name": "api-health-monitor-demo",
"version": "1.0.0",
"private": true,
"description": "Simple Express API with /health endpoint, monitored and dashboarded, deployed on ghaymah.systems",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2"
}
}

عرض الملف

@@ -1,35 +1,44 @@
const express = require('express'); const express = require('express');
const cors = require('cors'); const cors = require('cors');
const path = require('path');
const app = express(); const app = express();
app.use(cors()); app.use(cors());
// --- Simple in-memory metrics (reset when the process restarts) ---------
let requestCount = 0; let requestCount = 0;
let lastResponseTime = 0; let lastResponseTime = 0;
app.use((req, res, next) => { app.use((req, res, next) => {
requestCount++; requestCount++;
const start = Date.now(); const start = Date.now();
res.on('finish', () => { res.on('finish', () => {
lastResponseTime = Date.now() - start; lastResponseTime = Date.now() - start;
}); });
next(); next();
}); });
// Serve the dashboard (public/index.html) at the root, plus any static assets
app.use(express.static(path.join(__dirname, 'public')));
// --- Health check used by the monitor script and by ghaymah's platform --
app.get('/health', (req, res) => { app.get('/health', (req, res) => {
res.json({ res.json({
status: 'Online', status: 'Online',
uptime_seconds: process.uptime(), uptime_seconds: Math.round(process.uptime()),
request_count: requestCount, request_count: requestCount,
response_time_ms: lastResponseTime response_time_ms: lastResponseTime,
}); timestamp: new Date().toISOString(),
});
}); });
app.get('/', (req, res) => { // Plain-text info route, separate from the dashboard which now owns '/'
res.send('Welcome to the Backend API!'); app.get('/api', (req, res) => {
res.send('Welcome to the Backend API! Health check available at /health');
}); });
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
app.listen(PORT, () => { app.listen(PORT, '0.0.0.0', () => {
console.log(`API is running on port ${PORT}`); console.log(`API is running on port ${PORT}`);
}); });

113
README.md
عرض الملف

@@ -1,2 +1,113 @@
# Ghaymah-Exam-GamalMohamed-SRE # Ghaymah SRE Project
This repository contains a full set of SRE and DevOps deliverables for the Ghaymah platform. It includes a health-monitoring web app, a containerized dashboard, an incident postmortem, CI/CD guidance, and a high-traffic architecture design.
## Project Overview
The project is organized into five main parts:
- Q1: API health monitoring app and dashboard
- Q2: Incident postmortem and resilience recommendations
- Q3-CICD: CI/CD workflow and deployment strategy
- Q4: High-traffic architecture design for 15,000 RPS
- Q5: Containerized monitoring service for uptime and SSL checks
## Repository Structure
```text
Ghaymah_Task/
├── Q1/
│ ├── Dashboard/
│ ├── Dockerfile
│ ├── monitor.sh
│ ├── package.json
│ ├── README.md
│ └── server.js
├── Q2/
│ └── readme,md
├── Q3-CICD/
│ ├── README.md
│ └── workflow.yml
├── Q4/
│ ├── GhaymahAPI.png
│ └── README.md
├── Q5/
│ ├── Dockerfile
│ ├── Entrypoint.sh
│ ├── README.md
│ ├── index.html
│ └── monitor.py
└── README.md
```
## What Each Part Includes
### Q1 — API Health Monitor and Dashboard
This section provides a lightweight web service that exposes a health endpoint and serves a dashboard for monitoring service status, response time, and request count.
Key files:
- [Q1/server.js](Q1/server.js)
- [Q1/monitor.sh](Q1/monitor.sh)
- [Q1/Dashboard/index.html](Q1/Dashboard/index.html)
### Q2 — Incident Postmortem
This section documents a major outage caused by memory exhaustion and proposes mitigation strategies such as autoscaling, pagination, and observability improvements.
Key file:
- [Q2/readme,md](Q2/readme,md)
### Q3-CICD — Continuous Integration and Deployment
This section outlines the CI/CD workflow for automating build, test, and deployment processes for the platform.
Key files:
- [Q3-CICD/workflow.yml](Q3-CICD/workflow.yml)
- [Q3-CICD/README.md](Q3-CICD/README.md)
### Q4 — High-Traffic Architecture Design
This section explains how to design a scalable architecture for handling 15,000 requests per second, covering load balancing, caching, database replication, and storage planning.
Key files:
- [Q4/README.md](Q4/README.md)
- [Q4/GhaymahAPI.png](Q4/GhaymahAPI.png)
### Q5 — Containerized Monitoring Service
This section contains a Dockerized monitoring solution that checks uptime, latency, SSL expiry, and dashboard availability using a simple Python script.
Key files:
- [Q5/Dockerfile](Q5/Dockerfile)
- [Q5/monitor.py](Q5/monitor.py)
- [Q5/Entrypoint.sh](Q5/Entrypoint.sh)
## How to Use This Repository
1. Review the documentation in each folder.
2. Run the applications locally as described in their own README files.
3. Use the CI/CD workflow from Q3-CICD for deployment automation.
4. Reference Q4 for the large-scale architecture approach.
5. Use Q5 as a container-based monitoring example.
## Technologies Used
- Node.js / Express
- Python
- Docker
- HTML / CSS / JavaScript
- GitHub Actions workflow-based CI/CD
## Summary
This project demonstrates a practical SRE approach covering monitoring, incident response, automation, scalability, and container-based operations for a production-style platform.
---
## Author
**Gamal Mohamed**
DevSecOps Engineer
Qabilah Profile
```
https://qabilah.com/profile/gamalmohammed0909/
```

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 131 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 67 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 9.8 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 19 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 236 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 35 KiB

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 132 KiB