Skip to content

Commit 790dce6

Browse files
committed
feat(service): fixes #12 - mise en place du service http
1 parent 1a32937 commit 790dce6

5 files changed

Lines changed: 81 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Changelog
2+
3+
## [0.1.0] — 2026-04-27
4+
5+
### Phase 1 — MVP : API Docker + Frontend minimal
6+
7+
#### Added
8+
9+
- Backend Node.js + Express servant les fichiers statiques et l'API REST
10+
- `GET /api/status` : liste tous les containers Docker avec nom, statut, image, ports et uptime
11+
- Connexion au socket Docker via `dockerode` (`/var/run/docker.sock`)
12+
- Calcul du `globalStatus` global (`OK` / `KO`) selon l'état des containers
13+
- Frontend statique vanilla (HTML + CSS + JS) sans framework ni build
14+
- Rafraîchissement automatique du dashboard toutes les 5 secondes
15+
- Indicateurs visuels par statut : vert (running), rouge (exited), orange (restarting)
16+
- `Dockerfile` basé sur `node:20-alpine`
17+
- Intégration dans le `docker-compose.yml` du VPS avec montage du socket Docker
18+
- Script `npm run dev` via `nodemon` pour le développement local
19+
- Pipeline CI GitHub Actions (`ci.yml`) : lint ESLint + tests Jest sur toutes les branches et PRs
20+
- Pipeline CD GitHub Actions (`staging.yml`) : déploiement automatique sur le VPS via SSH au push sur `staging`
21+
- Tests unitaires avec `jest` + `supertest` (mock du socket Docker)

vps-monitor-app/api/server.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
const express = require('express');
22
const path = require('path');
33
const { getContainers } = require('./services/docker');
4+
const { checkWebsites } = require('./services/http');
45

56
const app = express();
67

78
const PORT = process.env.PORT;
89
const URI = process.env.URI;
10+
const BASE_URL = process.env.BASE_URL || `http://localhost:${PORT}`;
911

1012
app.use(express.static(path.join(__dirname, '../public')));
1113

1214
app.get('/api/status', async (req, res) => {
1315
try {
14-
const containers = await getContainers();
16+
const [containers, websites] = await Promise.all([
17+
getContainers(),
18+
checkWebsites(BASE_URL),
19+
]);
20+
1521
const allRunning = containers.every((c) => c.status === 'running');
22+
const allUp = websites.every((w) => w.status === 'OK');
1623

1724
res.json({
1825
containers,
19-
websites: [],
20-
globalStatus: allRunning ? 'OK' : 'KO',
26+
websites,
27+
globalStatus: allRunning && allUp ? 'OK' : 'KO',
2128
});
2229
} catch (err) {
2330
res.status(500).json({ error: err.message });

vps-monitor-app/api/server.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ jest.mock('./services/docker', () => ({
66
]),
77
}));
88

9+
jest.mock('./services/http', () => ({
10+
checkWebsites: jest.fn().mockResolvedValue([
11+
{ name: 'SaintBarth Volley', url: '/saintbarthvolley/', httpCode: 200, status: 'OK' },
12+
]),
13+
}));
14+
915
const app = require('./server');
1016

1117
describe('GET /api/status', () => {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const TIMEOUT_MS = 5000;
2+
3+
const WEBSITES = [
4+
{ name: 'TP Vue', path: '/B3dev-TP_VUE/' },
5+
{ name: 'SaintBarth Volley', path: '/saintbarthvolley/' },
6+
{ name: 'Lucky7', path: '/lucky7/' },
7+
{ name: 'College La Boussole', path: '/collegelaboussole/' },
8+
{ name: 'Cinemap', path: '/cinemap/' },
9+
];
10+
11+
async function checkWebsite(baseUrl, site) {
12+
const url = `${baseUrl}${site.path}`;
13+
const controller = new AbortController();
14+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
15+
16+
try {
17+
const res = await fetch(url, { signal: controller.signal });
18+
return {
19+
name: site.name,
20+
url: site.path,
21+
httpCode: res.status,
22+
status: res.status === 200 ? 'OK' : 'DOWN',
23+
};
24+
} catch {
25+
return {
26+
name: site.name,
27+
url: site.path,
28+
httpCode: null,
29+
status: 'DOWN',
30+
};
31+
} finally {
32+
clearTimeout(timer);
33+
}
34+
}
35+
36+
async function checkWebsites(baseUrl) {
37+
return Promise.all(WEBSITES.map((site) => checkWebsite(baseUrl, site)));
38+
}
39+
40+
module.exports = { checkWebsites };

vps-monitor-app/eslint.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ module.exports = [
1111
__dirname: 'readonly',
1212
process: 'readonly',
1313
console: 'readonly',
14+
fetch: 'readonly',
15+
AbortController: 'readonly',
16+
setTimeout: 'readonly',
17+
clearTimeout: 'readonly',
1418
},
1519
},
1620
rules: {

0 commit comments

Comments
 (0)