Files
marcus hinz 93bb19abf0 initial
2026-06-20 14:40:33 +02:00

173 lines
7.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Folie 6 Core / Rationale (DEUTSCH): kompakte Landscape links, Argumente als Karten rechts.
(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, sp=None):
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
if sp is not None: p.space_after = Pt(sp)
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, size=10):
w = Inches(0.30 + 0.085 * len(text)); h = Inches(0.27)
x = cx - w / 2
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=INK, adj=0.5)
txt(x, y, w, h, text, size=size, color=WHITE, align=PP_ALIGN.CENTER, font=FC)
def core_tag(x, y):
w, h = Inches(0.54), Inches(0.23)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h, fill=INK, adj=0.5)
txt(x, y, w, h, "CORE", size=8.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, "Warum Event Sourcing passt", 7)
# ===========================================================================
# LINKS kompakte Landscape
# ===========================================================================
LCX = Inches(3.35)
# Quellen
shp(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(0.7), Inches(1.58), Inches(5.3), Inches(0.7),
fill=WHITE, adj=0.12)
txt(Inches(0.92), Inches(1.66), Inches(4.9), Inches(0.26), "Quellen",
size=12.5, color=INK, bold=True, anchor=MSO_ANCHOR.TOP)
txt(Inches(0.92), Inches(1.94), Inches(4.9), Inches(0.28),
"Publisher (publizieren) · Subsysteme (konsumieren & publizieren)",
size=10.5, color=MUTE, anchor=MSO_ANCHOR.TOP)
shp(MSO_SHAPE.DOWN_ARROW, LCX - Inches(0.13), Inches(2.30), Inches(0.26), Inches(0.26),
fill=CORAL)
# Hot Store (CORE) inkl. Event-Prozessoren
hy, hh = Inches(2.58), Inches(0.98)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(1.35), hy, Inches(4.0), hh,
fill=CORAL, line=INK, lw=Pt(3), adj=0.08)
core_tag(Inches(1.50), hy + Inches(0.12))
txt(Inches(1.35), hy + Inches(0.08), Inches(4.0), Inches(0.34),
"Event Store — Hot Store", size=15, color=INK, bold=True, align=PP_ALIGN.CENTER)
txt(Inches(1.35), hy + Inches(0.40), Inches(4.0), Inches(0.24),
"inkl. Event-Prozessoren", size=10.5, color=INK, align=PP_ALIGN.CENTER)
chip(LCX, hy + hh - Inches(0.34), "Kafka")
shp(MSO_SHAPE.DOWN_ARROW, LCX - Inches(0.13), hy + hh + Inches(0.02),
Inches(0.26), Inches(0.24), fill=CORAL)
# Projektionen
py, ph = Inches(3.82), Inches(0.56)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(1.35), py, Inches(4.0), ph, fill=WHITE, adj=0.16)
txt(Inches(1.55), py, Inches(2.0), ph, "Projektionen", size=12.5, color=INK, bold=True)
chip(Inches(4.25), py + ph / 2 - Inches(0.135), "Kafka Streams → PostgreSQL")
# Verteiler -> 3 Bloecke
boxes_y = Inches(4.72); mbh = Inches(1.28)
mb_w = Inches(1.65)
cold_x = Inches(0.7); cold_cx = cold_x + mb_w / 2
mon_x = Inches(2.55); mon_cx = mon_x + mb_w / 2
rep_x = Inches(4.40); rep_cx = rep_x + mb_w / 2
bus_y = py + ph + Inches(0.10)
shp(MSO_SHAPE.RECTANGLE, LCX - 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.10), bus_y, Inches(0.20), boxes_y - bus_y, fill=LIGHT)
def minibox(x, title, tech, core=False):
fill = CORAL if core else WHITE
line = INK if core else None
lw = Pt(3) if core else Pt(1)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, boxes_y, mb_w, mbh, fill=fill, line=line, lw=lw, adj=0.10)
if core:
core_tag(x + Inches(0.12), boxes_y + Inches(0.12))
txt(x, boxes_y + (Inches(0.42) if core else Inches(0.26)), mb_w, Inches(0.5), title,
size=12, color=INK, bold=True, align=PP_ALIGN.CENTER)
chip(x + mb_w / 2, boxes_y + mbh - Inches(0.36), tech)
minibox(cold_x, "Cold\nStore", "PostgreSQL", core=True)
minibox(mon_x, "Monitoring", "Grafana")
minibox(rep_x, "Reporting", "Power BI")
# ===========================================================================
# RECHTS Argumente als Karten
# ===========================================================================
cards = [
("Bewährte Technologie",
"Erprobt in regulierten Branchen mit hohem Volumen — z. B. ING setzt auf Kafka / Event-Streaming."),
("Flexibel",
"Neues System = neuer Adapter, ohne Eingriff in den Rest. Neue Event-Folgen & Projektionen jederzeit baubar."),
("Skalierbar",
"Selbst massive Lastzunahme wird durch mehr Hardware aufgefangen — horizontal, ohne Redesign."),
("Kosteneffizient",
"Wiederverwendbare Adapter statt Punkt-zu-Punkt. Open Source auf Standard-Hardware — kein Lock-in."),
("Auditierbar & revisionssicher",
"Append-only, vollständige & manipulationssichere Historie — vollständig replay-fähig."),
("Resilient & entkoppelt",
"Systeme fallen aus und holen per Replay auf; ein Log statt N² Schnittstellen."),
]
cw, ch = Inches(3.0), Inches(1.42)
col_x = [Inches(6.55), Inches(9.8)]
row_y = [Inches(1.62), Inches(3.30), Inches(4.98)]
for i, (title, body) in enumerate(cards):
x = col_x[i % 2]; y = row_y[i // 2]
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, cw, ch, fill=WHITE, adj=0.08)
shp(MSO_SHAPE.RECTANGLE, x + Inches(0.0), y + Inches(0.14), Inches(0.11), ch - Inches(0.28),
fill=CORAL)
txt(x + Inches(0.32), y + Inches(0.15), cw - Inches(0.5), Inches(0.36), title,
size=13.5, color=INK, bold=True, anchor=MSO_ANCHOR.TOP)
txt(x + Inches(0.32), y + Inches(0.55), cw - Inches(0.52), ch - Inches(0.68), body,
size=10.5, color=MUTE, anchor=MSO_ANCHOR.TOP)
out = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Folie6.pptx")
prs.save(out)
print("saved", out)