diff --git a/report/meetings/260611-final/db.typ b/report/meetings/260611-final/db.typ index baa9cbe..38130cf 100644 --- a/report/meetings/260611-final/db.typ +++ b/report/meetings/260611-final/db.typ @@ -10,6 +10,28 @@ // mqtt->db // db->rest + +== Database & API - Server +#let server = [ + #figure( + image("server.png", width: 100%), + caption: [], + ) +] +#grid( + columns: (1.5fr, 1fr), + column-gutter: 2em, + server, + align(top+left)[ + #v(3em) #pause + - LXC Debian #pause + - @ssh:short certificate by user #pause + - Docker #pause + - Traefik + ], +) + +== Database & API - Save measures in DB #let toDB = { import chronos: * b.display diff --git a/report/meetings/260611-final/gateway.typ b/report/meetings/260611-final/gateway.typ index 579050e..0c5db1c 100644 --- a/report/meetings/260611-final/gateway.typ +++ b/report/meetings/260611-final/gateway.typ @@ -2,11 +2,8 @@ #import "/tail/bibliography.typ": * #import "/tail/glossary.typ": * #import "/main/architecture/description.typ": * - #import "/resources/slides.typ": * - == Gateway — BLE to MQTT Bridge - #slide[ #grid( columns: (1fr, 1fr), @@ -22,18 +19,25 @@ [ *Data flow*\ Thingy:52 - -> BLE advertising + $->$ BLE advertising Raspberry Pi - -> MQTTS (TLS) + $->$ MQTTS (TLS) RabbitMQ broker - -> + $->$ InfluxDB ] ) ] - +== Gateway — Overview +#slide[ + #align(center)[ + #figure( + image("/resources/img/gateway_overview.svg", height: 40%), + caption: [Gateway communication chain — from @ble:short advertising to database storage] + ) + ] +] == Gateway — Key Challenges - #slide[ #grid( columns: (1fr, 1fr), @@ -48,23 +52,15 @@ - Deduplication: 10s cache per MAC address ], [ - *Reliability* + *Reliability — validated in production* - MQTT auto-restart via systemd - `os._exit(1)` on disconnection - Validated with 2 cases: - Network disconnection - Wrong MQTT credentials + - Multiple nodes publishing + simultaneously — confirmed by broker + - No duplicate data ] ) -] - -== Gateway — Data Collection Flow - -#slide[ - #align(center)[ - #figure( - image("/resources/img/gateway_overview.svg", height: 40%), - caption: [Gateway communication chain — from @ble:short advertising to database storage] - ) - ] ] \ No newline at end of file diff --git a/report/meetings/260611-final/nodes.typ b/report/meetings/260611-final/nodes.typ index c6047e1..ed07f7c 100644 --- a/report/meetings/260611-final/nodes.typ +++ b/report/meetings/260611-final/nodes.typ @@ -36,8 +36,10 @@ caption: [Data communicated in the nodes_interface], ) ---- == Nodes | Takeaways +#align(top+left)[ + #v(5em) - Breadboard validation #pause - 28 days later #pause - - Improve @ble:short reliability \ No newline at end of file + - Improve @ble:short reliability +] \ No newline at end of file diff --git a/report/meetings/260611-final/server.png b/report/meetings/260611-final/server.png new file mode 100644 index 0000000..0aefaff Binary files /dev/null and b/report/meetings/260611-final/server.png differ diff --git a/report/meetings/260611-final/server.uxf b/report/meetings/260611-final/server.uxf new file mode 100644 index 0000000..2811b6d --- /dev/null +++ b/report/meetings/260611-final/server.uxf @@ -0,0 +1,13 @@ +10UMLDeployment310280330350ServerUMLGeneric34039010040<<Broker MQTT>> +RabbitMQUMLGeneric49032010040<<Database>> +InfluxDB3UMLGeneric49039010040<<API DB>> +Go serviceRelation4304008030lt=<-60;10;10;10Relation5603503060lt=->10;10;10;40Relation5103503060lt=->10;40;10;10Relation23039013050lt=-() +m2=MQTT +110;20;10;20Relation53043019050lt=-() +m2=REST +10;20;170;20UMLDeployment33051011050<<Dashboard>> +AngularRelation43049014060lt=)- +m1= +110;20;110;40;10;40UMLDeployment33057011050<<Notification>> +JavaRelation43052013090110;10;110;70;10;70Relation5304206090lt=-() +m2=REST10;10;10;70 \ No newline at end of file diff --git a/report/meetings/260611-final/slides.typ b/report/meetings/260611-final/slides.typ index 1991276..873d277 100644 --- a/report/meetings/260611-final/slides.typ +++ b/report/meetings/260611-final/slides.typ @@ -4,7 +4,6 @@ #import "/main/architecture/description.typ": * #import "/resources/slides.typ": * - #show:make-glossary #register-glossary(entry-list) diff --git a/report/meetings/260611-final/ui.typ b/report/meetings/260611-final/ui.typ index d6116fd..b1a2502 100644 --- a/report/meetings/260611-final/ui.typ +++ b/report/meetings/260611-final/ui.typ @@ -5,6 +5,10 @@ #import "/resources/slides.typ": * +// Chemin racine des images — adapter selon ta structure de projet +#let img-root = "../../resources/img/ui_images/images/" + +// ── Palette ─────────────────────────────────────────────────────────────────── #let c-dark = rgb("#0F172A") #let c-teal = rgb("#0EA5E9") #let c-text = rgb("#1E293B") @@ -12,105 +16,180 @@ #let c-white = rgb("#FFFFFF") #let c-border = rgb("#E2E8F0") ---- +// ── Helpers ─────────────────────────────────────────────────────────────────── -───────────────────────────────────────────────────────────────────────────── -// SLIDE 2 — Cycle DevSecOps -// ───────────────────────────────────────────────────────────────────────────── -#let slide-devsecops() = { - // Header custom (subtitle à droite) - block(width: 100%, height: 43.9pt, fill: c-dark, inset: 0pt)[ - #pad(x: 25.5pt)[ - #align(horizon)[ - #grid(columns: (1fr, auto), +#let icon-circle(img-path, size: 38pt, bg: rgb("#0EA5E9")) = { + box( + width: size, height: size, + fill: bg, radius: (size / 2), + inset: 0pt, clip: true, + )[ + #align(center + horizon)[ + #image(img-path, width: (size * 0.62), height: (size * 0.62), fit: "contain") + ] + ] +} + +#let badge(label, fill: rgb("#EF4444")) = { + box(fill: fill, radius: 3pt, inset: (x: 5pt, y: 2pt))[ + #text(size: 6.5pt, weight: "bold", fill: rgb("#FFFFFF"))[#label] + ] +} + +#let devsec-col(phase-title, items) = { + block(width: 100%)[ + #block( + width: 100%, height: 28pt, + fill: c-dark, + radius: (top-left: 5pt, top-right: 5pt, bottom-left: 0pt, bottom-right: 0pt), + inset: 0pt, + )[ + #pad(x: 7pt)[ + #align(horizon + center)[ + #text(size: 8.5pt, weight: "bold", fill: rgb("#FFFFFF"))[#phase-title] + ] + ] + ] + #block( + width: 100%, + fill: rgb("#F1F5F9"), + radius: (top-left: 0pt, top-right: 0pt, bottom-left: 5pt, bottom-right: 5pt), + inset: 8pt, + )[ + #for item in items { + grid(columns: (30pt, 1fr), gutter: 6pt, + icon-circle(item.at("icon"), size: 28pt, bg: item.at("bg", default: c-teal)), align(left + horizon)[ - #text(size: 16pt, weight: "bold", fill: rgb("#FFFFFF"))[Cycle DevSecOps - PI E2EEDA] - ], - align(right + horizon)[ - #text(size: 8pt, fill: rgb("#94A3B8"))[Shift-left · Security by design] + #text(size: 8pt, weight: "bold", fill: c-text)[#item.at("name")] + #linebreak() + #item.at("extra", default: []) ], ) + v(5pt) + } + ] + ] +} + +== Cycle DevSecOps + +#slide[ + #grid(columns: (1fr, 1fr, 1fr, 1fr), gutter: 8pt, + devsec-col("① Code & PR Gate", ( + (icon: img-root + "image10.png", bg: rgb("#3178C6"), name: "TypeScript", + extra: [#text(size: 6.5pt, fill: c-muted)[tsc / ESLint]]), + (icon: img-root + "image11.png", bg: rgb("#DD0031"), name: "Angular CI", + extra: [#text(size: 6.5pt, fill: c-muted)[Build check]]), + (icon: img-root + "image19.png", bg: rgb("#1F2328"), name: "GitHub Actions", + extra: [#text(size: 6.5pt, fill: c-muted)[Coverage]]), + )), + devsec-col("② SAST · SCA", ( + (icon: img-root + "image7.png", bg: rgb("#000000"), name: "SpotBugs", + extra: [#badge("BLOCKING")]), + (icon: img-root + "image13.png", bg: rgb("#1F2328"), name: "CodeQL", + extra: [#badge("BLOCKING")]), + (icon: img-root + "image14.png", bg: rgb("#F97316"), name: "Dep. Check", + extra: [#badge("NON-BLOCK", fill: rgb("#F97316"))]), + )), + devsec-col("③ DAST · Tests", ( + (icon: img-root + "image15.png", bg: rgb("#00549E"), name: "OWASP ZAP", + extra: [#badge("BLOCKING")]), + (icon: img-root + "image16.png", bg: rgb("#DD0031"), name: "Karma Tests", + extra: [#badge("BLOCKING")]), + (icon: img-root + "image17.png", bg: rgb("#64748B"), name: "Runtime check", + extra: [#text(size: 6.5pt, fill: c-muted)[HTTP headers]]), + )), + devsec-col("④ Build · Deploy", ( + (icon: img-root + "image18.png", bg: rgb("#0DB7ED"), name: "Docker", + extra: [#text(size: 6.5pt, fill: c-muted)[SHA-tagged]]), + (icon: img-root + "image19.png", bg: rgb("#1F2328"), name: "GHCR Push", + extra: [#text(size: 6.5pt, fill: c-muted)[main only]]), + (icon: img-root + "image17.png", bg: rgb("#10B981"), name: "SSH Deploy", + extra: [#text(size: 6.5pt, fill: c-muted)[cert-auth]]), + )), + ) + + #v(7pt) + + #rect(width: 100%, height: 26pt, fill: c-dark, radius: 4pt, inset: 0pt)[ + #pad(x: 20pt)[ + #align(horizon)[ + #grid(columns: (1fr, 1fr, 1fr), + align(center + horizon)[#text(size: 8pt, fill: rgb("#FFFFFF"))[🔐 #h(2pt) Shift-left security]], + align(center + horizon)[#text(size: 8pt, fill: rgb("#FFFFFF"))[🔑 #h(2pt) Zero secret in code]], + align(center + horizon)[#text(size: 8pt, fill: rgb("#FFFFFF"))[🔄 #h(2pt) Automated Deployment]], + ) ] ] ] - pad(x: 17pt, top: 11pt, bottom: 9pt)[ - #grid(columns: (1fr, 1fr, 1fr, 1fr), gutter: 10pt, + #v(6pt) +] - // ① Code & PR Gate - // image10 = TypeScript (TS logo), image11 = Angular (grisé) - // image19 = GitHub Actions (GHCR/GitHub logo) - devsec-col("① Code & PR Gate", ( - (icon: "../../resources/img/ui_images/images/image10.png", bg: rgb("#3178C6"), name: "TypeScript", - extra: [#text(size: 7pt, fill: c-muted)[tsc / ESLint]]), - (icon: "../../resources/img/ui_images/images/image11.png", bg: rgb("#DD0031"), name: "Angular CI", - extra: [#text(size: 7pt, fill: c-muted)[Build check]]), - )), - // ② SAST · SCA - // image13 = GitHub octocat (SpotBugs hébergé GitHub), image13 aussi CodeQL (GitHub) - // image14 = checklist hexagone (Dep. Check / OWASP DC) - devsec-col("② SAST · SCA", ( - (icon: "../../resources/img/ui_images/images/image13.png", bg: rgb("#1F2328"), name: "SpotBugs", - extra: [#badge("BLOCKING")]), - (icon: "../../resources/img/ui_images/images/image13.png", bg: rgb("#1F2328"), name: "CodeQL", - extra: [#badge("BLOCKING")]), - (icon: "../../resources/img/ui_images/images/image14.png", bg: rgb("#F97316"), name: "Dep. Check", - extra: [#badge("NON-BLOCK", fill: rgb("#F97316"))]), - )), +// ── SLIDE 3 — Dashboard ─────────────────────────────────────────────────────── +== Dashboard - // ③ DAST · Tests - // image15 = libellule OWASP ZAP, image16 = Karma/Jasmine, image17 = Tux Linux - devsec-col("③ DAST · Tests", ( - (icon: "../../resources/img/ui_images/images/image15.png", bg: rgb("#00549E"), name: "OWASP ZAP", - extra: [#badge("BLOCKING")]), - (icon: "../../resources/img/ui_images/images/image16.png", bg: rgb("#DD0031"), name: "Karma Tests", - extra: [#badge("BLOCKING")]), - (icon: "../../resources/img/ui_images/images/image17.png", bg: rgb("#64748B"), name: "Runtime check", - extra: [#text(size: 7pt, fill: c-muted)[HTTP headers]]), - )), - - // ④ Build · Deploy - // image18 = Docker, image19 = GHCR, image17 = Tux Linux (SSH) - devsec-col("④ Build · Deploy", ( - (icon: "../../resources/img/ui_images/images/image18.png", bg: rgb("#0DB7ED"), name: "Docker", - extra: [#text(size: 7pt, fill: c-muted)[SHA-tagged]]), - (icon: "../../resources/img/ui_images/images/image19.png", bg: rgb("#1F2328"), name: "GHCR Push", - extra: [#text(size: 7pt, fill: c-muted)[main only]]), - (icon: "../../resources/img/ui_images/images/image17.png", bg: rgb("#10B981"), name: "SSH Deploy", - extra: [#text(size: 7pt, fill: c-muted)[cert-auth]]), - )), - ) - - #v(9pt) - - // Barre résumé - #rect(width: 100%, height: 30pt, fill: c-dark, radius: 5pt, inset: 0pt)[ - #pad(x: 30pt)[ - #align(horizon)[ - #grid(columns: (1fr, 1fr, 1fr), - align(center + horizon)[#text(size: 9pt, fill: rgb("#FFFFFF"))[🔐 #h(3pt) Shift-left security]], - align(center + horizon)[#text(size: 9pt, fill: rgb("#FFFFFF"))[🔑 #h(3pt) Zero secret in code]], - align(center + horizon)[#text(size: 9pt, fill: rgb("#FFFFFF"))[🔄 #h(3pt) Automated Deployment]], - ) - ] - ] - ] - - #v(8pt) - - // GitHub Actions — image19 (GitHub/GHCR logo) - #align(center)[ - #grid(columns: (auto, auto, auto), gutter: 7pt, - align(horizon)[#icon-circle("../../resources/img/ui_images/images/image19.png", size: 24pt, bg: rgb("#1F2328"))], - align(horizon)[#text(size: 8.5pt, weight: "bold", fill: c-text)[GitHub Actions]], - align(horizon)[#text(size: 8.5pt, fill: c-muted)[Coverage]], - ) - ] +#slide[ + #align(center + horizon)[ + #figure( + image(img-root + "image20.png", width: 100%, fit: "contain"), + caption: [Dashboard] +) ] +] - v(1fr) - -} +// ── SLIDE 4 — Details Page ──────────────────────────────────────────────────── +== Details Page -// \ No newline at end of file +#slide[ + #align(center + horizon)[ + #figure( + image(img-root + "image21.png", width: 100%, fit: "contain"), + caption: [Details page] +) + ] +] + +// ── SLIDE 5 — Notification ──────────────────────────────────────────────────── +== Notification + +#slide[ + #grid(columns: (1fr, 1fr), gutter: 16pt, + // Screenshot Telegram + align(center + horizon)[ + + #figure( + image(img-root + "image22.png", height: 300pt, fit: "contain"), + caption: [Telegram notification] +) + ], + // Carte descriptive + rect(width: 100%, radius: 6pt, stroke: 0.5pt + c-border, fill: rgb("#FFFFFF"), inset: 12pt)[ + #text(size: 10pt, weight: "bold", fill: c-text)[CO₂ Alerts System] + #v(5pt) + #line(length: 100%, stroke: 0.5pt + c-border) + #v(6pt) + + #let alert-row(col, level, desc) = { + grid(columns: (10pt, 52pt, 1fr), gutter: 5pt, + box(width: 8pt, height: 8pt, fill: col, radius: 4pt), + text(size: 8.5pt, weight: "bold")[#level], + text(size: 8pt, fill: c-muted)[#desc], + ) + v(4pt) + } + #alert-row(rgb("#EF4444"), "Critical", "> 2000 ppm") + #alert-row(rgb("#F97316"), "Poor", "1200–1500 ppm") + #alert-row(rgb("#EAB308"), "Moderate", "1000–1200 ppm") + #alert-row(rgb("#22C55E"), "Good", "< 800 ppm") + + #v(6pt) + #line(length: 100%, stroke: 0.5pt + c-border) + #v(6pt) + + #v(6pt) + + ], + ) +] \ No newline at end of file