This commit is contained in:
marcus hinz
2026-06-20 14:40:33 +02:00
commit 93bb19abf0
32 changed files with 2827 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
#!/usr/bin/env python3
"""Folie 5 Event Sourcing: das groessere Bild (DEUTSCH).
Quellen differenziert (Publisher / Subsysteme), Event-Prozessoren als Teil des Stores,
Hot Store & Cold Store als Kernfunktion (Coral, CORE-Tag), Projektionen dazwischen,
darunter Cold Store / Monitoring / Reporting. Tech-Impls als Chips. (adesso-Styling)
Hintergrund: solides dunkles Blau (BG) Farbe frei anpassbar."""
import os
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from adesso_style import (WHITE, INK, BLUE, TEAL, GREEN, CORAL, LIGHT, MUTE, RECF,
F, FC, chrome)
# ---- Hintergrundfarbe (solid, keine Transparenz) frei anpassbar ----------
BG = RGBColor(0x0A, 0x3D, 0x6B) # dunkles Blau
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
SW, SH = prs.slide_width, prs.slide_height
s = prs.slides.add_slide(prs.slide_layouts[6])
def shp(kind, x, y, w, h, fill=None, line=None, lw=Pt(1), rot=0, adj=None):
sh = s.shapes.add_shape(kind, x, y, w, h)
if fill is None: sh.fill.background()
else: sh.fill.solid(); sh.fill.fore_color.rgb = fill
if line is None: sh.line.fill.background()
else: sh.line.color.rgb = line; sh.line.width = lw
if rot: sh.rotation = rot
if adj is not None:
try: sh.adjustments[0] = adj
except Exception: pass
sh.shadow.inherit = False
return sh
def txt(x, y, w, h, t, size=16, color=WHITE, bold=False, italic=False,
align=PP_ALIGN.LEFT, font=F, anchor=MSO_ANCHOR.MIDDLE):
tb = s.shapes.add_textbox(x, y, w, h); tf = tb.text_frame
tf.word_wrap = True; tf.vertical_anchor = anchor
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
first = True
for line in t.split("\n"):
p = tf.paragraphs[0] if first else tf.add_paragraph()
first = False
p.alignment = align
r = p.add_run(); r.text = line
r.font.size = Pt(size); r.font.bold = bold; r.font.italic = italic
r.font.name = font; r.font.color.rgb = color
return tb
def chip(cx, y, text, fill=INK, fg=WHITE, size=11):
"""Tech-Impl als kleine Pill, zentriert um cx."""
w = Inches(0.34 + 0.092 * len(text)); h = Inches(0.30)
x = cx - w / 2
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=fill, adj=0.5)
txt(x, y, w, h, text, size=size, color=fg, bold=False,
align=PP_ALIGN.CENTER, font=FC)
def core_tag(x, y):
w, h = Inches(0.62), Inches(0.26)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=INK, adj=0.5)
txt(x, y, w, h, "CORE", size=9.5, color=TEAL, bold=True,
align=PP_ALIGN.CENTER, font=FC)
# ---- solider Hintergrund (zuerst -> liegt hinten) --------------------------
bg = shp(MSO_SHAPE.RECTANGLE, 0, 0, SW, SH, fill=BG)
chrome(s, "System Landscape", 6)
CX = Inches(6.665) # Folienmitte (x)
# ---- Quellen: differenziert ------------------------------------------------
src_y, src_h = Inches(1.36), Inches(0.92)
def source_box(x, w, title, examples):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, src_y, w, src_h, fill=WHITE, adj=0.10)
txt(x + Inches(0.28), src_y + Inches(0.10), w - Inches(0.56), Inches(0.32),
title, size=14.5, color=INK, bold=True, anchor=MSO_ANCHOR.TOP)
txt(x + Inches(0.28), src_y + Inches(0.46), w - Inches(0.56), Inches(0.36),
examples, size=12, color=MUTE, anchor=MSO_ANCHOR.TOP)
pub_x, pub_w = Inches(0.9), Inches(5.6)
sub_x, sub_w = Inches(6.83), Inches(5.6)
pub_cx = pub_x + pub_w / 2
sub_cx = sub_x + sub_w / 2
source_box(pub_x, pub_w, "Publisher (nur publizieren)",
"z. B. AB+M · LabAccess · MDN · Stammdaten — proprietär")
source_box(sub_x, sub_w, "Subsysteme (konsumieren & publizieren)",
"z. B. LIS · Geräte / Analyzer — proprietär")
# ---- Pfeile Quellen -> Hot Store ------------------------------------------
ay, ah = src_y + src_h + Inches(0.02), Inches(0.30)
shp(MSO_SHAPE.DOWN_ARROW, pub_cx - Inches(0.16), ay, Inches(0.32), ah, fill=CORAL)
txt(pub_cx + Inches(0.28), ay - Inches(0.01), Inches(1.6), ah + Inches(0.02),
"publizieren", size=11, color=LIGHT, italic=True)
shp(MSO_SHAPE.UP_DOWN_ARROW, sub_cx - Inches(0.11), ay - Inches(0.05), Inches(0.22),
ah + Inches(0.10), fill=CORAL)
txt(sub_cx - Inches(2.85), ay - Inches(0.01), Inches(2.5), ah + Inches(0.02),
"konsumieren & publizieren", size=11, color=LIGHT, italic=True, align=PP_ALIGN.RIGHT)
# ---- HOT STORE (Kern) + Event-Prozessoren (Teil des Stores) ----------------
hx, hy, hw, hh = Inches(3.4), Inches(2.62), Inches(6.53), Inches(1.50)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx, hy, hw, hh, fill=CORAL, line=INK, lw=Pt(3.5), adj=0.07)
core_tag(hx + Inches(0.16), hy + Inches(0.13))
txt(hx, hy + Inches(0.05), hw, Inches(0.34),
"Event Store — Hot Store", size=20, color=INK, bold=True, align=PP_ALIGN.CENTER)
txt(hx, hy + Inches(0.40), hw, Inches(0.20),
"append-only · kanonische Wahrheit", size=12.5, color=INK, align=PP_ALIGN.CENTER)
chip(CX, hy + Inches(0.62), "z. B. Kafka")
# Event-Prozessoren als eingebetteter Bestandteil des Stores
ep_x, ep_y, ep_w, ep_h = hx + Inches(0.28), hy + Inches(0.98), hw - Inches(0.56), Inches(0.44)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ep_x, ep_y, ep_w, ep_h, fill=WHITE, adj=0.22)
txt(ep_x, ep_y, ep_w, ep_h,
"Event-Prozessoren (konsumieren & publizieren) · z. B. Proben-Routing",
size=11.5, color=INK, bold=True, align=PP_ALIGN.CENTER)
# ---- Hot -> Projektionen ---------------------------------------------------
shp(MSO_SHAPE.DOWN_ARROW, CX - Inches(0.16), hy + hh + Inches(0.03),
Inches(0.32), Inches(0.28), fill=CORAL)
# ---- PROJEKTIONEN ----------------------------------------------------------
px, py, pw, ph = Inches(3.4), Inches(4.46), Inches(6.53), Inches(0.66)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, px, py, pw, ph, fill=WHITE, adj=0.14)
txt(px + Inches(0.3), py, Inches(3.0), ph, "Projektionen", size=16, color=INK, bold=True)
chip(px + pw - Inches(2.0), py + ph / 2 - Inches(0.15), "Kafka Streams → PostgreSQL")
# ---- Verteiler (Projektionen -> 3 Bloecke) --------------------------------
boxes_y = Inches(5.34)
bw = Inches(3.7); bh = Inches(1.56)
cold_x = Inches(0.9); cold_cx = cold_x + bw / 2
mon_x = Inches(4.815); mon_cx = mon_x + bw / 2
rep_x = Inches(8.73); rep_cx = rep_x + bw / 2
bus_y = py + ph + Inches(0.10)
shp(MSO_SHAPE.RECTANGLE, CX - Pt(0.75), py + ph, Pt(1.5), bus_y - (py + ph), fill=LIGHT)
shp(MSO_SHAPE.RECTANGLE, cold_cx, bus_y, rep_cx - cold_cx, Pt(1.5), fill=LIGHT)
for cx in (cold_cx, mon_cx, rep_cx):
shp(MSO_SHAPE.DOWN_ARROW, cx - Inches(0.11), bus_y, Inches(0.22), boxes_y - bus_y,
fill=LIGHT)
def block(x, title, body, tech, core=False):
fill = CORAL if core else WHITE
line = INK if core else None
lw = Pt(3.5) if core else Pt(1)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, boxes_y, bw, bh, fill=fill, line=line, lw=lw, adj=0.07)
ty = boxes_y + (Inches(0.30) if core else Inches(0.20))
if core:
core_tag(x + Inches(0.16), boxes_y + Inches(0.16))
txt(x, ty, bw, Inches(0.42), title, size=17, color=INK, bold=True, align=PP_ALIGN.CENTER)
txt(x + Inches(0.25), ty + Inches(0.46), bw - Inches(0.5), Inches(0.5), body,
size=12.5, color=(INK if core else MUTE), align=PP_ALIGN.CENTER)
chip(x + bw / 2, boxes_y + bh - Inches(0.42), tech)
block(cold_x, "Cold Store",
"Archiv · Audit-Trail · Dokumente", "z. B. PostgreSQL", core=True)
block(mon_x, "Monitoring",
"Auftragsstatus / Auslastung", "z. B. Grafana")
block(rep_x, "Reporting",
"Bericht an Gruppe · KPIs", "z. B. Power BI")
out = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Folie5.pptx")
prs.save(out)
print("saved", out)