feat(site): rewrite public copy around the batch chain
Replace slogan-heavy bilingual copy with concrete industrial prose on home, about, work, notes, and contact, without invented metrics or em dashes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import Link from "next/link";
|
||||
import { getPerson } from "@/content/person";
|
||||
import { getDictionary } from "@/i18n/dictionaries";
|
||||
import { publicPath } from "@/i18n/routes";
|
||||
import { pageMetadata } from "@/lib/metadata";
|
||||
import { requireLocale } from "@/lib/locale";
|
||||
|
||||
@@ -22,7 +24,7 @@ export default async function AboutPage({ params }: PageProps<"/[lang]/about">)
|
||||
<p className="mt-6 font-mono text-xs uppercase tracking-[0.16em] text-mute">
|
||||
{person.role} · {person.location}
|
||||
</p>
|
||||
<div className="mt-16 grid gap-8 border-t border-line pt-12 md:grid-cols-3">
|
||||
<div className="mt-16 grid max-w-2xl gap-6 border-t border-line pt-12">
|
||||
{person.story.map((paragraph) => (
|
||||
<p key={paragraph.slice(0, 24)} className="leading-8 text-mute-strong">
|
||||
{paragraph}
|
||||
@@ -40,6 +42,15 @@ export default async function AboutPage({ params }: PageProps<"/[lang]/about">)
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
<section className="mt-20 border-t border-line pt-12">
|
||||
<p className="max-w-2xl leading-8 text-mute-strong">{dict.about.close}</p>
|
||||
<Link
|
||||
href={publicPath(locale, "contact")}
|
||||
className="mt-8 inline-block border border-copper bg-copper px-6 py-3 text-sm font-medium text-ink"
|
||||
>
|
||||
{dict.actions.startConversation}
|
||||
</Link>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,17 @@ export default async function ContactPage({
|
||||
<p className="kicker">{dict.contact.kicker}</p>
|
||||
<h1 className="display mt-5 text-5xl md:text-6xl">{dict.contact.title}</h1>
|
||||
<p className="mt-8 max-w-xl text-lg leading-8 text-mute-strong">{dict.contact.lede}</p>
|
||||
<p className="mt-4 max-w-xl text-sm leading-7 text-mute">{dict.contact.reply}</p>
|
||||
<div className="mt-8 max-w-xl">
|
||||
<p className="font-mono text-xs uppercase tracking-[0.16em] text-mute">{dict.contact.needTitle}</p>
|
||||
<ul className="mt-4 grid gap-3 text-sm leading-7 text-mute-strong">
|
||||
{dict.contact.need.map((item) => (
|
||||
<li key={item} className="border-l border-line-strong pl-4">
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<p className="mt-6 max-w-xl text-sm leading-7 text-mute">{dict.contact.reply}</p>
|
||||
<p className="mt-3 text-sm">
|
||||
<a className="text-copper" href={`mailto:${site.email}`}>
|
||||
{dict.contact.emailDirect}: {site.email}
|
||||
|
||||
+11
-4
@@ -17,8 +17,8 @@ export async function generateMetadata({ params }: PageProps<"/[lang]">) {
|
||||
locale,
|
||||
"home",
|
||||
locale === "de"
|
||||
? "Jan Wagner — Software für anspruchsvolle Prozesse"
|
||||
: "Jan Wagner — Software for demanding processes",
|
||||
? "Jan Wagner · Software für Satzzettel, Silo und Schichtabschluss"
|
||||
: "Jan Wagner · software for batch tickets, silos and the shift close",
|
||||
dict.home.lede,
|
||||
);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export default async function HomePage({ params }: PageProps<"/[lang]">) {
|
||||
const person = getPerson(locale);
|
||||
const [featured, ...rest] = getProjects(locale);
|
||||
const offers = getOffers(locale);
|
||||
const notes = getNotes(locale).slice(0, 3);
|
||||
const notes = getNotes(locale).slice(0, 4);
|
||||
|
||||
return (
|
||||
<main>
|
||||
@@ -120,9 +120,16 @@ export default async function HomePage({ params }: PageProps<"/[lang]">) {
|
||||
|
||||
<section className="border-t border-line">
|
||||
<div className="mx-auto w-full max-w-6xl px-6 py-20 md:px-10">
|
||||
<div className="flex flex-wrap items-end justify-between gap-6">
|
||||
<div>
|
||||
<p className="kicker">{dict.home.notesKicker}</p>
|
||||
<h2 className="display mt-4 text-4xl md:text-5xl">{dict.home.notesTitle}</h2>
|
||||
<div className="mt-12 grid gap-10 md:grid-cols-3">
|
||||
</div>
|
||||
<Link href={publicPath(locale, "notes")} className="text-sm text-copper">
|
||||
{dict.actions.allNotes} →
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-12 grid gap-10 md:grid-cols-2">
|
||||
{notes.map((note) => (
|
||||
<article key={note.slug}>
|
||||
<time className="font-mono text-xs text-mute" dateTime={note.date}>
|
||||
|
||||
@@ -52,7 +52,13 @@ export default async function CaseStudyPage({ params }: PageProps<"/[lang]/work/
|
||||
|
||||
<section className="grid gap-10 border-b border-line py-16 md:grid-cols-2">
|
||||
<h2 className="font-serif text-3xl">{dict.case.situation}</h2>
|
||||
<p className="leading-8 text-mute-strong">{project.situation}</p>
|
||||
<div className="grid gap-5">
|
||||
{project.situation.map((paragraph) => (
|
||||
<p key={paragraph.slice(0, 32)} className="leading-8 text-mute-strong">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="border-b border-line py-16">
|
||||
@@ -70,7 +76,7 @@ export default async function CaseStudyPage({ params }: PageProps<"/[lang]/work/
|
||||
{project.images.length ? (
|
||||
<section className="border-b border-line py-16">
|
||||
<p className="kicker">{dict.case.proof}</p>
|
||||
<h2 className="mt-4 font-serif text-3xl md:text-4xl">{dict.home.workTitle}</h2>
|
||||
<h2 className="mt-4 font-serif text-3xl md:text-4xl">{dict.case.galleryTitle}</h2>
|
||||
<div className="mt-10 grid gap-8">
|
||||
{project.images.map((image) => (
|
||||
<figure key={image.src} className="overflow-hidden border border-line bg-ink-raised">
|
||||
@@ -90,9 +96,7 @@ export default async function CaseStudyPage({ params }: PageProps<"/[lang]/work/
|
||||
|
||||
<section className="py-16">
|
||||
<p className="kicker">{dict.case.decisions}</p>
|
||||
<h2 className="mt-4 font-serif text-3xl md:text-4xl">
|
||||
{locale === "de" ? "Der fachliche Kern als Modell." : "The domain core as a model."}
|
||||
</h2>
|
||||
<h2 className="mt-4 font-serif text-3xl md:text-4xl">{dict.case.modelTitle}</h2>
|
||||
<div className="mt-10">
|
||||
<ProcessRail stages={project.stages} />
|
||||
</div>
|
||||
@@ -101,7 +105,13 @@ export default async function CaseStudyPage({ params }: PageProps<"/[lang]/work/
|
||||
<section className="grid gap-10 border-t border-line py-16 md:grid-cols-2">
|
||||
<div>
|
||||
<h2 className="font-serif text-3xl">{dict.case.outcome}</h2>
|
||||
<p className="mt-4 leading-8 text-mute-strong">{project.outcome}</p>
|
||||
<div className="mt-4 grid gap-5">
|
||||
{project.outcome.map((paragraph) => (
|
||||
<p key={paragraph.slice(0, 32)} className="leading-8 text-mute-strong">
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="font-serif text-3xl">{dict.case.lesson}</h2>
|
||||
|
||||
+2
-2
@@ -24,11 +24,11 @@ const newsreader = Newsreader({
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(site.url),
|
||||
title: {
|
||||
default: "Jan Wagner — Software für anspruchsvolle Prozesse",
|
||||
default: "Jan Wagner · Software für Satzzettel, Silo und Schichtabschluss",
|
||||
template: "%s · W-MAKE",
|
||||
},
|
||||
description:
|
||||
"Jan Wagner entwickelt robuste digitale Systeme für industrielle Prozesse — mit Domänenverständnis, klarer Architektur und Verantwortung für den Betrieb.",
|
||||
"Jan Wagner entwickelt Software für Rezept, Satzzettel, Siloabzug und Tagesabschluss in der Behälterglas-Produktion. Deutschland, remote und vor Ort.",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
|
||||
@@ -13,7 +13,7 @@ export function HomeJsonLd() {
|
||||
},
|
||||
areaServed: "DE",
|
||||
description:
|
||||
"Software für industrielle und anspruchsvolle Geschäftsprozesse — Domänenverständnis, Architektur, Betrieb.",
|
||||
"Software für Rezept, Satzzettel, Silo und Tagesabschluss in der Behälterglas-Produktion.",
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
+12
-10
@@ -7,13 +7,14 @@ const copy = {
|
||||
"E-Mail: eldov@w-make.de",
|
||||
"Website: https://w-make.com",
|
||||
"Anschrift und Firmierung nach § 5 DDG werden ergänzt, sobald die Unternehmensdaten für den öffentlichen Auftritt feststehen. Bis dahin gilt die genannte E-Mail als Kontakt für redaktionelle und rechtliche Anliegen.",
|
||||
"Inhalte zu Projekten enthalten keine vertraulichen Kundendaten. Externe Links, etwa zur Produkt-Demo unter batch.w-make.com, liegen außerhalb dieser Site.",
|
||||
"Diese Site stellt die öffentliche Arbeit von Jan Wagner dar: Positionierung, zwei Produkte, Notizen und ein Kontaktformular. Sie ist kein Kundenportal und enthält keine vertraulichen Hallendaten.",
|
||||
"Inhalte zu Projekten enthalten keine Kundennamen, keine internen Mengen und keine Betriebsgeheimnisse. Externe Links, etwa zur Produkt-Demo unter batch.w-make.com, liegen außerhalb dieser Site. Für den Inhalt verlinkter Seiten sind deren Betreiber verantwortlich.",
|
||||
],
|
||||
privacy: [
|
||||
"Diese Website speichert Anfragen aus dem Kontaktformular, um sie zu beantworten. Pflichtfelder sind Name, E-Mail und Nachricht. Das optionale Feld Unternehmen hilft bei der Einordnung.",
|
||||
"Die Daten werden in einer lokalen SQLite-Datei auf dem Server abgelegt und per E-Mail an eldov@w-make.de weitergeleitet. Es gibt kein Tracking-Pixel, kein Marketing-Cookie und keine Weitergabe an Werbenetzwerke.",
|
||||
"Server-Logs des Hosters können IP-Adresse und Zeitpunkt einer Anfrage enthalten. Das ist Betrieb, nicht Analyse.",
|
||||
"Sie können Auskunft, Berichtigung oder Löschung Ihrer Anfrage verlangen, indem Sie an eldov@w-make.de schreiben. Eine vollständige Datenschutzerklärung nach DSGVO folgt, sobald Anschrift und Firmierung feststehen.",
|
||||
"Diese Website speichert Anfragen aus dem Kontaktformular, um sie zu beantworten. Pflichtfelder sind Name, E-Mail und Nachricht. Das optionale Feld Unternehmen hilft bei der Einordnung. Das optionale Feld Einstieg ordnet die Anfrage einer der drei Zusammenarbeitsformen zu, falls Sie eine gewählt haben.",
|
||||
"Die Daten werden in einer lokalen SQLite-Datei auf dem Server abgelegt und per E-Mail an eldov@w-make.de weitergeleitet. Es gibt kein Tracking-Pixel, kein Marketing-Cookie und keine Weitergabe an Werbenetzwerke. Es findet keine Profilbildung und keine Reichweitenmessung statt.",
|
||||
"Server-Logs des Hosters können IP-Adresse, Zeitpunkt und aufgerufenen Pfad einer Anfrage enthalten. Das ist Betrieb, nicht Analyse. Die Logs dienen der Störungssuche und der Absicherung, nicht der Werbung.",
|
||||
"Sie können Auskunft, Berichtigung oder Löschung Ihrer Anfrage verlangen, indem Sie an eldov@w-make.de schreiben. Nennen Sie dafür bitte die verwendete E-Mail-Adresse und den ungefähren Zeitpunkt. Eine vollständige Datenschutzerklärung nach DSGVO folgt, sobald Anschrift und Firmierung feststehen.",
|
||||
],
|
||||
},
|
||||
en: {
|
||||
@@ -22,13 +23,14 @@ const copy = {
|
||||
"Email: eldov@w-make.de",
|
||||
"Website: https://w-make.com",
|
||||
"Street address and legal entity under German law will be added once the public company data is final. Until then the email above is the contact for editorial and legal matters.",
|
||||
"Project pages do not include confidential client data. External links, such as the product demo at batch.w-make.com, live outside this site.",
|
||||
"This site presents Jan Wagner’s public work: positioning, two products, notes and a contact form. It is not a client portal and does not hold confidential plant data.",
|
||||
"Project pages do not include client names, internal volumes or trade secrets. External links, such as the product demo at batch.w-make.com, live outside this site. The operators of linked pages are responsible for their content.",
|
||||
],
|
||||
privacy: [
|
||||
"This website stores inquiries from the contact form in order to reply. Required fields are name, email, and message. The optional company field helps with context.",
|
||||
"Data is written to a local SQLite file on the server and forwarded by email to eldov@w-make.de. There is no tracking pixel, no marketing cookie, and no sharing with advertising networks.",
|
||||
"The host’s server logs may include IP address and request time. That is operations, not analytics.",
|
||||
"You can request access, correction, or deletion of your inquiry by writing to eldov@w-make.de. A full GDPR privacy notice will follow once street address and legal entity are final.",
|
||||
"This website stores inquiries from the contact form in order to reply. Required fields are name, email and message. The optional company field helps with context. The optional starting-point field maps the inquiry to one of the three ways of working together, if you chose one.",
|
||||
"Data is written to a local SQLite file on the server and forwarded by email to eldov@w-make.de. There is no tracking pixel, no marketing cookie and no sharing with advertising networks. There is no profiling and no audience measurement.",
|
||||
"The host’s server logs may include IP address, request time and the path requested. That is operations, not analytics. Logs are used for incident response and hardening, not for advertising.",
|
||||
"You can request access, correction or deletion of your inquiry by writing to eldov@w-make.de. Please include the email address you used and the approximate time. A full GDPR privacy notice will follow once street address and legal entity are final.",
|
||||
],
|
||||
},
|
||||
} as const;
|
||||
|
||||
+96
-30
@@ -1,6 +1,6 @@
|
||||
import type { Locale } from "@/i18n/routes";
|
||||
|
||||
export type NoteSlug = "buchungen" | "satzzettel" | "domaene";
|
||||
export type NoteSlug = "buchungen" | "satzzettel" | "domaene" | "betrieb" | "grenzen";
|
||||
|
||||
export type LocalizedNote = {
|
||||
slug: NoteSlug;
|
||||
@@ -11,26 +11,57 @@ export type LocalizedNote = {
|
||||
};
|
||||
|
||||
const notes: Record<NoteSlug, { date: string; de: Omit<LocalizedNote, "slug" | "date">; en: Omit<LocalizedNote, "slug" | "date"> }> = {
|
||||
betrieb: {
|
||||
date: "2026-07-22",
|
||||
de: {
|
||||
title: "Migration, Sicherung, Schichtbeginn: Betrieb ist Teil des Produkts",
|
||||
summary: "Ein Abschluss, den man nur in der Demo hinbekommt, hält der Halle nicht stand. Die gemeinsame Uhr und die Wiederholbarkeit gehören in die Anwendung.",
|
||||
body: [
|
||||
"In vielen Projekten kommt der Betrieb hinterher. Zuerst die Masken, dann irgendwann eine Sicherung, irgendwann eine Migration, irgendwann die Frage, warum der Schichtbeginn auf jedem Rechner anders ist. In der Behälterglas-Produktion ist das keine Nachsorge. Der Tag hat eine Uhr. Der Bestand hat eine Datei. Der Abschluss muss sich wiederholen lassen, wenn um sechs jemand denselben Knopf noch einmal drückt.",
|
||||
"Schichtbeginn als gemeinsamer Zeitpunkt klingt klein. Er ist es nicht. Ohne ihn schreibt die eine Station auf gestern, die andere auf heute, das Protokoll auf eine dritte Variante. Alarme, Satzzettel und Übergabe beziehen sich dann auf verschiedene Tage, obwohl alle im selben Raum stehen. Die Uhr gehört in das System, nicht in die lokale Zeitzone des Browsers und nicht in ein Formularfeld, das jemand einmal gesetzt hat.",
|
||||
"Dasselbe gilt für den Tagesabschluss. Ein Export als CSV ist kein Abschluss. Ein Abschluss ist ein Zustand: welche Sätze gelten, welcher Silostand steht, welche Übergabe die nächste Schicht vorfindet. Wenn dieser Zustand nur unter Laborbedingungen entsteht, weil drei Felder zufällig gefüllt waren, ist er in der Halle wertlos. Man muss denselben Abschluss am nächsten Tag wieder erzeugen können, mit denselben Regeln.",
|
||||
"Migrationen sind der unauffällige Teil. Eine Rezeptversion, ein Buchungstyp, ein neues Feld am Silo: das ändert das, was gestern schon gebucht war. Eine Migration, die alte Sätze umschreibt, macht die Geschichte weich. Eine Migration, die vorwärts gilt und die Vergangenheit in Ruhe lässt, hält den Tag erklärbar. Das ist langsamer zu schreiben. Es spart die Nacht, in der niemand mehr sagen kann, welche Zahl zur Wanne gehört.",
|
||||
"Sicherung ist verwandt. Eine SQLite-Datei, die den Bestand trägt, ist kein Anhängsel. Sie ist der Bestand. Wer sie nicht regelmäßig und prüfbar sichert, hat den Betrieb an die Festplatte eines einzelnen Rechners gebunden. Wiederherstellung muss geübt sein, nicht nur dokumentiert. Ein Wiederanlauf um Schichtbeginn ist der Test, nicht ein Restore am Sonntagnachmittag.",
|
||||
"Für technische Entscheider: nehmen Sie Migration, Sicherung und die gemeinsame Uhr in den Umfang des Produkts auf, bevor die erste Maske festgezogen wird. Was danach nachgerüstet wird, sitzt daneben und wird im Ernstfall umgangen.",
|
||||
],
|
||||
},
|
||||
en: {
|
||||
title: "Migration, backup, shift start: operations are part of the product",
|
||||
summary: "A close that only works in the demo will not hold on the floor. The shared clock and the ability to repeat the close belong in the application.",
|
||||
body: [
|
||||
"In many projects operations come afterwards. Screens first, then a backup at some point, a migration at some point, and eventually the question why shift start differs on every machine. In container-glass production that is not aftercare. The day has a clock. Stock has a file. The close must be repeatable if someone presses the same control again at six.",
|
||||
"Shift start as a shared instant sounds small. It is not. Without it one station writes to yesterday, another to today, the log to a third variant. Alarms, tickets and handover then refer to different days while everyone stands in the same room. The clock belongs in the system, not in the browser’s local timezone and not in a form field someone set once.",
|
||||
"The same holds for the day close. A CSV export is not a close. A close is a state: which batches hold, where the silo stands, what handover the next shift will find. If that state only appears under lab conditions because three fields happened to be filled, it is worthless on the floor. You must be able to produce the same close the next day, with the same rules.",
|
||||
"Migrations are the quiet part. A recipe version, a booking type, a new field on the silo: that changes what was already booked yesterday. A migration that rewrites old batches softens history. A migration that applies forwards and leaves the past alone keeps the day explainable. It is slower to write. It saves the night in which nobody can say which figure belongs to the furnace.",
|
||||
"Backup is related. A SQLite file that carries stock is not an accessory. It is the stock. If you do not back it up regularly and in a way you can check, you have tied operations to one machine’s disk. Restore has to be practised, not only documented. A restart at shift start is the test, not a restore on Sunday afternoon.",
|
||||
"For technical decision-makers: put migration, backup and the shared clock into the product scope before the first screen is locked. What is bolted on later sits beside the flow and will be bypassed when it matters.",
|
||||
],
|
||||
},
|
||||
},
|
||||
buchungen: {
|
||||
date: "2026-08-01",
|
||||
de: {
|
||||
title: "Warum fachliche Buchungen nicht einfach gelöscht werden dürfen",
|
||||
summary: "In einem Produktionsmodell ist Löschen selten die richtige Korrektur. Meist braucht es einen Gegenbeleg.",
|
||||
summary: "Nach dem Wiegen hat eine Buchung Silo und Protokoll schon verändert. Korrektur heißt Gegenbuchung, Storno oder Abgleich, nicht DELETE.",
|
||||
body: [
|
||||
"In vielen Anwendungen ist Delete der schnellste Weg, einen Fehler zu korrigieren. In einem Batch- oder Materialfluss ist das gefährlich: Eine Buchung hat bereits Mengen, Zeiten und nachgelagerte Zustände verändert.",
|
||||
"Die bessere Operation ist eine Gegenbuchung. Sie erhält die Geschichte, macht die Korrektur sichtbar und hält Auswertungen ehrlich. Soft-Delete allein reicht nicht, wenn der fachliche Effekt schon eingetreten ist.",
|
||||
"Das klingt nach mehr Aufwand. Es spart den größeren: nächtliche Differenzen zwischen Silo, Rezept und Protokoll, die niemand mehr erklären kann.",
|
||||
"Für technische Entscheider: Modellieren Sie Irreversibilität dort, wo die Domäne sie verlangt — nicht dort, wo das ORM eine Cascade anbietet.",
|
||||
"In vielen Anwendungen ist Delete der schnellste Weg, einen Fehler zu korrigieren. Der Datensatz war falsch, also verschwindet er. In einem Batch- oder Materialfluss ist das gefährlich. Eine Buchung hat bereits Mengen, Zeiten und nachgelagerte Zustände verändert. Der Silo ist leichter, das Gemengebuch hat eine Zeile, das Tagesprotokoll rechnet mit diesem Satz. Die Zeile zu löschen macht den Fehler unsichtbar. Den Effekt beseitigt sie nicht.",
|
||||
"Ein praktisches Bild: jemand hat den falschen Rohstoff gewählt, die Waage hat gewogen, der Abzug ist gelaufen. Soft-Delete auf dieser Zeile lässt den Silostand stehen, wo er nach dem Abzug ist, während die Maske so tut, als sei nichts geschehen. Die nächste Schicht erbt eine Differenz, die niemand mehr an einem Beleg festmachen kann. Auswertungen werden höflich. Der Bestand wird es nicht.",
|
||||
"Die bessere Operation ist eine Gegenbuchung. Sie erhält die Geschichte, macht die Korrektur sichtbar und hält Auswertungen ehrlich. Storno ist der verwandte Fall, wenn der Satz nicht stattfinden soll, der Abzug aber schon geschrieben hat. Abgleich ist der Fall, in dem Halle und System auseinandergelaufen sind und jemand den Unterschied benennen muss, statt ihn zu überschreiben.",
|
||||
"Das klingt nach mehr Aufwand in der Anwendung. Es spart den größeren: nächtliche Differenzen zwischen Silo, Rezept und Protokoll, die niemand mehr erklären kann. Eine Gegenbuchung kostet eine Maske und eine Regel. Eine unsichtbare Korrektur kostet eine Schichtsuche.",
|
||||
"CRUD hilft hier wenig als Denkmodell. Create und Read passen. Update nach dem Wiegen ist oft schon zu viel. Delete ist fast immer falsch, sobald ein nachgelagerter Zustand geschrieben hat. Wer das ORM eine Cascade anbieten lässt, hat die fachliche Frage an die Bibliothek abgegeben.",
|
||||
"Für technische Entscheider: modellieren Sie Unumkehrbarkeit dort, wo die Halle sie verlangt. Nicht dort, wo das Formular einen Papierkorb-Knopf hergibt. Wenn Sie unsicher sind, fragen Sie, was um sechs noch stimmen muss, wenn jemand um halb drei den falschen Satz angelegt hat.",
|
||||
],
|
||||
},
|
||||
en: {
|
||||
title: "Why domain bookings must not simply be deleted",
|
||||
summary: "In a production model, delete is rarely the right correction. Usually you need a reversing entry.",
|
||||
summary: "After weighing, a booking has already changed silo and log. Correction means a reversing entry, a cancellation or a reconcile, not DELETE.",
|
||||
body: [
|
||||
"In many applications, delete is the fastest way to fix a mistake. In a batch or material flow that is dangerous: a booking has already changed quantities, times, and downstream state.",
|
||||
"The better operation is a reversing entry. It keeps history, makes the correction visible, and keeps reports honest. Soft-delete alone is not enough once the domain effect has occurred.",
|
||||
"It looks like more work. It avoids the larger kind: overnight gaps between silo, recipe, and log that nobody can explain.",
|
||||
"For technical decision-makers: model irreversibility where the domain requires it — not where the ORM offers a cascade.",
|
||||
"In many applications, delete is the fastest way to fix a mistake. The record was wrong, so it disappears. In a batch or material flow that is dangerous. A booking has already changed quantities, times and downstream state. The silo is lighter, the batch book has a line, the daily log is counting on that batch. Deleting the row hides the mistake. It does not undo the effect.",
|
||||
"A practical picture: someone picked the wrong raw material, the scale weighed, the deduction ran. Soft-delete on that row leaves the silo where it is after the deduction, while the screen pretends nothing happened. The next shift inherits a gap that nobody can pin to a voucher. Reports become polite. Stock does not.",
|
||||
"The better operation is a reversing entry. It keeps history, makes the correction visible and keeps reports honest. Cancellation is the related case when the batch should not take place but the deduction has already been written. Reconcile is the case in which hall and system have drifted and someone has to name the difference instead of overwriting it.",
|
||||
"It looks like more work in the application. It avoids the larger kind: overnight gaps between silo, recipe and log that nobody can explain. A reversing entry costs a screen and a rule. An invisible correction costs a shift spent searching.",
|
||||
"CRUD is a weak model here. Create and read still fit. Update after weighing is often already too much. Delete is almost always wrong once a downstream state has been written. If you let the ORM offer a cascade, you have handed the domain question to the library.",
|
||||
"For technical decision-makers: model irreversibility where the hall requires it. Not where the form offers a bin button. If you are unsure, ask what still has to be true at six if someone opened the wrong batch at half past two.",
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -38,22 +69,53 @@ const notes: Record<NoteSlug, { date: string; de: Omit<LocalizedNote, "slug" | "
|
||||
date: "2026-08-10",
|
||||
de: {
|
||||
title: "Vom Satzzettel zum Tagesprotokoll",
|
||||
summary: "Zwei Dokumente, ein Modell. Wenn sie getrennt leben, entsteht der Bruch genau dort, wo die Schicht übergibt.",
|
||||
summary: "Zwei Dokumente, ein Modell. Leben sie getrennt, entsteht der Bruch genau dort, wo die Schicht übergibt.",
|
||||
body: [
|
||||
"Der Satzzettel sagt, was in die Wanne soll. Das Tagesprotokoll sagt, was der Tag daraus gemacht hat. In Papierstapeln sind das zwei Welten. In Software dürfen sie das nicht bleiben.",
|
||||
"Ein durchgängiges Modell verbindet Rezept, Satz, Verbrauch und Abschluss. Nicht, weil Integration modern ist, sondern weil die Schichtübergabe sonst wieder in Kopien und Nebenrechnungen stattfindet.",
|
||||
"Die Oberfläche kann schlank sein. Die Verbindung im Datenmodell darf es nicht. Wer nur Screens liefert, liefert den Bruch mit.",
|
||||
"Lernpunkt: Zeichnen Sie zuerst den Tag eines Schmelzers, nicht die Sitemap der Anwendung.",
|
||||
"Der Satzzettel sagt, was in die Wanne soll: welche Rezeptversion, welcher Zielsatz, welche Redox-Lage. Das Tagesprotokoll sagt, was der Tag daraus gemacht hat: welche Sätze gelaufen sind, was die Schicht der nächsten hinterlässt, ob der Tag geschlossen ist. In Papierstapeln sind das zwei Welten. In Software dürfen sie das nicht bleiben.",
|
||||
"Der Bruch sieht harmlos aus. Labor oder Arbeitsvorbereitung druckt den Zettel. Die Waage arbeitet ihn ab. Jemand überträgt Verbrauch in eine zweite Liste. Schichtende wird in einem dritten Blatt festgehalten, oft mit Zahlen, die unterwegs gerundet oder mündlich korrigiert wurden. Am nächsten Morgen streiten drei Blätter, und niemand hat Unrecht in seinem System. Sie haben nur kein gemeinsames.",
|
||||
"Ein durchgängiges Modell verbindet Rezept, Satz, Verbrauch und Abschluss. Nicht weil Integration modern ist, sondern weil die Schichtübergabe sonst wieder in Kopien und Nebenrechnungen stattfindet. Der Zettel ist dann der Auftrag, das Gemengebuch die Ausführung, das Protokoll der Zustand am Abend. Dieselbe Rezeptversion steht an allen drei Stellen. Ändert sich die Version, gilt das für neue Sätze, nicht für die, die schon gewogen sind.",
|
||||
"Die Oberfläche kann schlank sein. Der Schmelzer braucht keine Architekturzeichnung. Er braucht den nächsten Satz, die Lage von Oxid und Redox, und am Abend eine Übergabe, die ohne Zusatzzettel auskommt. Die Verbindung darf trotzdem nicht nur in der Oberfläche liegen. Wer nur Screens liefert und die Daten getrennt hält, liefert den Bruch mit. Er sieht nur ordentlicher aus.",
|
||||
"Ein Test für das Modell: kann die nächste Schicht den Tag erklären, ohne den Vorgänger anzurufen. Wenn dafür noch eine Nebenrechnung in einem Heft nötig ist, ist die Kette nicht geschlossen. Wenn der Abschluss denselben Tag morgen noch einmal erzeugen lässt, ist sie es eher.",
|
||||
"Lernpunkt für die Architektur: zeichnen Sie zuerst den Tag eines Schmelzers, nicht die Sitemap der Anwendung. Welche Zahl um sechs, welche nach dem Wiegen, welche um Schichtende. Die Masken folgen daraus. Umgekehrt entstehen hübsche Formulare und dieselbe Übergabe wie auf Papier.",
|
||||
],
|
||||
},
|
||||
en: {
|
||||
title: "From batch ticket to daily log",
|
||||
summary: "Two documents, one model. If they live apart, the fracture appears exactly where the shift hands over.",
|
||||
body: [
|
||||
"The batch ticket says what should go into the furnace. The daily log says what the day made of it. On paper these are two worlds. In software they must not stay that way.",
|
||||
"A continuous model connects recipe, batch, consumption, and close. Not because integration is fashionable, but because otherwise the handover happens again in copies and side calculations.",
|
||||
"The interface can stay lean. The connection in the data model cannot. Screens alone ship the fracture with them.",
|
||||
"Takeaway: draw a melter’s day first, not the application sitemap.",
|
||||
"The batch ticket says what should go into the furnace: which recipe version, which target weight, which redox state. The daily log says what the day made of it: which batches ran, what the shift leaves the next, whether the day is closed. On paper these are two worlds. In software they must not stay that way.",
|
||||
"The fracture looks harmless. Lab or planning prints the ticket. The scale works it off. Someone copies consumption into a second list. End of shift is recorded on a third sheet, often with figures rounded or corrected by mouth along the way. The next morning three sheets disagree, and nobody is wrong inside their own system. They simply do not share one.",
|
||||
"A continuous model connects recipe, batch, consumption and close. Not because integration is fashionable, but because otherwise the handover happens again in copies and side calculations. The ticket is then the order, the batch book the execution, the log the state in the evening. The same recipe version stands at all three points. If the version changes, that applies to new batches, not to those already weighed.",
|
||||
"The interface can stay lean. A melter does not need an architecture diagram. He needs the next batch, the oxide and redox position, and in the evening a handover that does not need an extra sheet. The connection still must not live only in the interface. Screens alone, with the data kept apart, ship the fracture with them. It only looks tidier.",
|
||||
"A test for the model: can the next shift explain the day without calling the previous one. If a side calculation in a notebook is still required, the chain is not closed. If the close can produce the same day again tomorrow, it is closer.",
|
||||
"Takeaway for architecture: draw a melter’s day first, not the application sitemap. Which figure at six, which after weighing, which at the end of the shift. The screens follow from that. The other way round you get handsome forms and the same handover as on paper.",
|
||||
],
|
||||
},
|
||||
},
|
||||
grenzen: {
|
||||
date: "2026-08-14",
|
||||
de: {
|
||||
title: "Warum Batch und Studio zwei Produkte sind",
|
||||
summary: "Derselbe Fachkern, zwei Zuschnitte. Wer Rezeptarbeit und Hallenbetrieb in eine Anwendung zwingt, trägt Entwürfe in den Bestand oder den Bestand an den Schreibtisch.",
|
||||
body: [
|
||||
"W-Make Batch und Batchmaker Studio teilen den Kern für Rezept, Rohstoff und Glaschemie. Sie teilen nicht den Zuschnitt. Batch trägt Silos, Schichten, Buchungen und den Tagesabschluss. Studio trägt Versionen, Validierung und den druckfertigen Satzzettel. Die Trennung ist keine Marketinglinie. Sie folgt aus zwei verschiedenen Tagen.",
|
||||
"Der Tag in der Halle beginnt mit einer Uhr, einem Bestand und Sätzen, die nach dem Wiegen nicht mehr Entwurf sind. Der Tag am Schreibtisch beginnt mit einer Rezeptversion, die sich noch ändern darf, einer Oxidrechnung, die man prüfen will, und einem Zettel, der noch nicht gebucht ist. In ein Produkt gezwungen, gelten Hallenregeln für Entwürfe oder Entwurfsregeln für den Bestand. Beides ist falsch.",
|
||||
"Ein Beispiel: in Studio soll eine Rezeptversion scheitern dürfen. Die Validierung ist ein Schritt, den jemand sieht. In Batch darf dieselbe Version, sobald Sätze darauf laufen, nicht still durch eine neue ersetzt werden. Die Kostenrechnung hängt an der Version, die gewogen wurde, nicht an der, die gerade in der Maske offen ist. Vermischt man die Produkte, landet genau diese stille Ersetzung in der Halle.",
|
||||
"Umgekehrt: wer Studio mit Silos und Schichten vollpackt, zwingt die Rezeptarbeit in einen Betriebsmodus, den niemand am Schreibtisch braucht. Man eröffnet eine Schicht, um einen Zettel zu drucken. Man pflegt Bestände, die dort keine sind. Das Werkzeug wird schwer, und der Fachkern verschwindet hinter Masken, die zur Halle gehören.",
|
||||
"Technisch heißt die Grenze: eigener Server, eigene Datei, eigene Oberfläche. Der Kern für Oxid, Redox und Satzgröße kann verwandt sein. Die Buchung darf es nicht. Ein Satzzettel aus Studio ist Entwurf und Druckvorlage. Gebucht wird er erst in Batch, wenn die Waage und der Silo dazukommen.",
|
||||
"Für technische Entscheider: Produktgrenzen sind Architektur. Fragen Sie, welcher Tag in der Anwendung stattfinden soll, bevor Sie Module zusammenlegen, weil der Kern ähnlich aussieht. Ähnliche Rechnung ist kein Grund für dasselbe Betriebsmodell.",
|
||||
],
|
||||
},
|
||||
en: {
|
||||
title: "Why Batch and Studio are two products",
|
||||
summary: "The same domain core, two cuts. Force recipe work and plant operations into one application and you carry drafts into stock, or stock onto the desk.",
|
||||
body: [
|
||||
"W-Make Batch and Batchmaker Studio share the core for recipe, raw material and glass chemistry. They do not share the cut. Batch carries silos, shifts, bookings and the day close. Studio carries versions, validation and the print-ready batch ticket. The split is not a marketing line. It follows from two different days.",
|
||||
"The day in the hall begins with a clock, a stock position and batches that are no longer drafts after weighing. The day at the desk begins with a recipe version that may still change, an oxide calculation you want to inspect, and a ticket that is not yet booked. Forced into one product, hall rules apply to drafts or draft rules apply to stock. Both are wrong.",
|
||||
"An example: in Studio a recipe version is allowed to fail. Validation is a step someone can see. In Batch, once batches are running on that version, it must not be silently replaced by a new one. Cost hangs on the version that was weighed, not on the one currently open in the screen. Mix the products and that silent replacement lands in the hall.",
|
||||
"The other way round: pack Studio with silos and shifts and you force recipe work into an operations mode nobody needs at the desk. You open a shift in order to print a ticket. You maintain stock that is not stock there. The tool gets heavy, and the domain core disappears behind screens that belong to the hall.",
|
||||
"Technically the boundary means: its own server, its own file, its own interface. The core for oxide, redox and batch size can be related. The booking must not. A ticket from Studio is a draft and a print-ready sheet. It is booked in Batch only when the scale and the silo join in.",
|
||||
"For technical decision-makers: product boundaries are architecture. Ask which day is supposed to take place in the application before you merge modules because the core looks similar. Similar calculation is not a reason for the same operating model.",
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -61,22 +123,26 @@ const notes: Record<NoteSlug, { date: string; de: Omit<LocalizedNote, "slug" | "
|
||||
date: "2026-08-16",
|
||||
de: {
|
||||
title: "Was Domänenwissen in der Produktentwicklung verändert",
|
||||
summary: "Wer den Prozess kennt, baut andere Invarianten. Nicht mehr Features — andere Fehler, die man sich nicht leisten kann.",
|
||||
summary: "Wer den Prozess kennt, stellt andere Fragen. Es entstehen andere Regeln, nicht mehr Felder auf derselben Maske.",
|
||||
body: [
|
||||
"In der Behälterglas-Produktion ist ein Rezept keine Liste von Zutaten. Es ist eine Entscheidung über Temperatur, Redox, Kosten und das, was die nächste Schicht vorfindet. Wer das nur als Formularfelder modelliert, verliert die Reihenfolge, in der die Realität zuschlägt.",
|
||||
"Domänenwissen ändert deshalb zuerst die Fragen. Nicht: Welche Maske fehlt? Sondern: Was darf nach dem Wiegen nicht mehr stillschweigend verschwinden? Was muss eine Schicht der nächsten hinterlassen, ohne mündliche Zusatzrechnung?",
|
||||
"Daraus folgen unspektakuläre technische Konsequenzen. Buchungen werden Zustände. Berechnungen bleiben an Versionen gebunden. Validierung ist ein Schritt, den jemand sehen kann. Migrationen und Backups gehören zum Produkt, nicht zur Nachsorge.",
|
||||
"Für technische Entscheider: Stellen Sie jemanden, der den Prozess erklären kann, an den Anfang der Architektur — nicht an das Ende der Abnahme. Der teuerste Fehler ist der, den das System erlaubt, weil niemand ihn für fachlich gehalten hat.",
|
||||
"In der Behälterglas-Produktion ist ein Rezept keine Liste von Zutaten. Es ist eine Entscheidung über Temperatur, Redox, Kosten und das, was die nächste Schicht vorfindet. Wer das nur als Formularfelder modelliert, verliert die Reihenfolge, in der die Realität zuschlägt. Zuerst gilt eine Version. Dann wird gewogen. Dann ist der Silo leichter. Dann muss die Wanne zur Rechnung passen. Dann übergibt die Schicht. Die Maske, die alle Felder gleichzeitig anbietet, kennt diese Folge nicht.",
|
||||
"Domänenwissen ändert deshalb zuerst die Fragen. Nicht welche Maske fehlt, sondern was nach dem Wiegen nicht mehr still verschwinden darf. Was eine Schicht der nächsten hinterlassen muss, ohne mündliche Zusatzrechnung. Welche Zahl am Abend noch zur Halle passt, wenn drei Stationen geschrieben haben. Aus diesen Fragen folgen Invarianten. Aus Invarianten folgt das Modell. Aus dem Modell folgen Masken, nicht umgekehrt.",
|
||||
"Die technischen Konsequenzen sind selten spektakulär. Buchungen werden Zustände. Berechnungen bleiben an Versionen gebunden. Validierung ist ein Schritt, den jemand sehen kann. Migrationen und Sicherungen gehören zum Produkt. Schichtbeginn ist eine Uhr. Nichts davon gewinnt einen Architekturpreis. Alles davon entscheidet, ob um sechs noch jemand den Vortag erklären kann.",
|
||||
"Ohne Domäne entstehen andere Fehler, oft spät. Ein Soft-Delete, das den Silo nicht zurückdreht. Eine Rezeptänderung, die in bereits gewogene Sätze hineinschreibt. Eine Kostenrechnung, die die offene Maske nimmt statt der Version an der Waage. Eine Schichtübergabe, die nur als Kommentarfeld existiert. Jeder einzelne Punkt sieht in der Demo unauffällig aus. In der Halle addieren sie sich zu einer Nacht.",
|
||||
"Deshalb gehört jemand, der den Prozess erklären kann, an den Anfang der Architektur, nicht an das Ende der Abnahme. Abnahme findet den fehlenden Knopf. Sie findet selten die fehlende Unumkehrbarkeit. Der teuerste Fehler ist der, den das System erlaubt, weil niemand ihn für fachlich gehalten hat.",
|
||||
"Für Auftraggeber und Teams: verlangen Sie die Erklärung des Tages, bevor Sie die Erklärung des Stacks verlangen. Wenn der Tag nicht erzählbar ist, wird die Software ihn auch nicht tragen. Wenn er erzählbar ist, wird der Stack vergleichsweise langweilig. Das ist in diesem Feld ein gutes Zeichen.",
|
||||
],
|
||||
},
|
||||
en: {
|
||||
title: "What domain knowledge changes in product development",
|
||||
summary: "Knowing the process produces different invariants. Not more features — different failures you cannot afford.",
|
||||
summary: "Knowing the process changes the questions. You get different rules, not more fields on the same screen.",
|
||||
body: [
|
||||
"In container-glass production a recipe is not a list of ingredients. It is a decision about temperature, redox, cost, and what the next shift will find. Model that as form fields and you lose the order in which reality hits.",
|
||||
"Domain knowledge therefore changes the questions first. Not: which screen is missing? But: what must not silently disappear after weighing? What must one shift leave the next without a side calculation in someone’s head?",
|
||||
"The technical consequences are unspectacular. Bookings become states. Calculations stay bound to versions. Validation is a step someone can see. Migrations and backups belong to the product, not to aftercare.",
|
||||
"For technical decision-makers: put someone who can explain the process at the start of the architecture — not at the end of acceptance. The most expensive defect is the one the system allows because nobody treated it as domain.",
|
||||
"In container-glass production a recipe is not a list of ingredients. It is a decision about temperature, redox, cost and what the next shift will find. Model that as form fields and you lose the order in which reality hits. First a version holds. Then weighing happens. Then the silo is lighter. Then the furnace has to match the calculation. Then the shift hands over. The screen that offers every field at once does not know that sequence.",
|
||||
"Domain knowledge therefore changes the questions first. Not which screen is missing, but what must not silently disappear after weighing. What one shift must leave the next without a side calculation in someone’s head. Which figure still has to match the hall in the evening after three stations have written. Invariants follow from those questions. The model follows from the invariants. Screens follow from the model, not the other way round.",
|
||||
"The technical consequences are rarely spectacular. Bookings become states. Calculations stay bound to versions. Validation is a step someone can see. Migrations and backups belong to the product. Shift start is a clock. None of that wins an architecture prize. All of it decides whether someone can still explain yesterday at six.",
|
||||
"Without the domain, different defects appear, often late. A soft-delete that does not reverse the silo. A recipe change that writes into batches already weighed. A cost calculation that takes the open screen instead of the version at the scale. A shift handover that exists only as a comment field. Each point looks quiet in the demo. On the floor they add up to a night.",
|
||||
"That is why someone who can explain the process belongs at the start of the architecture, not at the end of acceptance. Acceptance finds the missing button. It rarely finds the missing irreversibility. The most expensive defect is the one the system allows because nobody treated it as domain.",
|
||||
"For clients and teams: ask for the explanation of the day before you ask for the explanation of the stack. If the day cannot be told, the software will not carry it either. If it can be told, the stack will look comparatively dull. In this field that is a good sign.",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
+10
-10
@@ -7,34 +7,34 @@ const copy = {
|
||||
{
|
||||
id: "process",
|
||||
title: "Prozessanalyse",
|
||||
text: "Ich analysiere einen bestehenden digitalen Prozess, identifiziere fachliche Bruchstellen und übersetze die Ergebnisse in eine priorisierte technische Roadmap.",
|
||||
text: "Wir gehen den Ablauf durch, der heute in Kopien, Nebenrechnungen oder stillen Korrekturen endet. Das Ergebnis ist eine Karte der Bruchstellen und eine Reihenfolge, in der sich der Aufwand lohnt. Der Gang durch die Halle kommt zuerst. Ein Workshop oder ein Tool-Vergleich ersetzt ihn nicht.",
|
||||
},
|
||||
{
|
||||
id: "product",
|
||||
title: "Produkt- und Backend-Entwicklung",
|
||||
text: "Ich entwickle oder stabilisiere Anwendungen, bei denen Datenmodell, Geschäftslogik und Betrieb wichtiger sind als ein schneller Prototyp.",
|
||||
title: "Produkt und Backend",
|
||||
text: "Ich entwickle oder stabilisiere die Anwendung, in der Datenmodell, Fachlogik und Betrieb zusammenfallen. Typisch sind Buchungsketten, Stammdaten mit Versionen, Berechnungen an der Rezeptversion und ein Abschluss, den eine Schicht wiederholen kann.",
|
||||
},
|
||||
{
|
||||
id: "collaboration",
|
||||
title: "Technische Zusammenarbeit",
|
||||
text: "Ich unterstütze Teams bei Architekturentscheidungen, schwierigen Integrationen und der Überführung von gewachsenem Code in ein wartbares System.",
|
||||
title: "Mitarbeit im Team",
|
||||
text: "Ich sitze an der Stelle, an der Fachbereich und Engineering sich sonst verfehlen: Integrationen, gewachsener Code, Entscheidungen, die nach dem Go-Live teuer werden. Ich liefere nicht nebenher eine zweite Architektur.",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
id: "process",
|
||||
title: "Process analysis",
|
||||
text: "I analyse an existing digital process, make domain fractures visible, and turn the findings into a prioritised technical roadmap.",
|
||||
text: "We walk the flow that currently ends in copies, side calculations or quiet corrections. You get a map of the breaks and an order in which the work is worth doing. The walk through the hall comes first. A workshop or a tool comparison does not replace it.",
|
||||
},
|
||||
{
|
||||
id: "product",
|
||||
title: "Product and backend development",
|
||||
text: "I build or stabilise applications where the data model, domain logic, and operations matter more than a fast prototype.",
|
||||
title: "Product and backend",
|
||||
text: "I build or steady the application where the data model, domain logic and operations meet. Typical work is booking chains, versioned master data, calculations bound to the recipe version, and a close a shift can repeat.",
|
||||
},
|
||||
{
|
||||
id: "collaboration",
|
||||
title: "Technical collaboration",
|
||||
text: "I help teams with architecture decisions, difficult integrations, and turning accumulated code into a maintainable system.",
|
||||
title: "Work inside a team",
|
||||
text: "I sit where operations and engineering otherwise miss each other: integrations, accumulated code, decisions that get expensive after go-live. I do not deliver a second architecture on the side.",
|
||||
},
|
||||
],
|
||||
} as const;
|
||||
|
||||
+34
-20
@@ -3,47 +3,61 @@ import type { Locale } from "@/i18n/routes";
|
||||
const copy = {
|
||||
de: {
|
||||
role: "Software Engineer für industrielle Prozesse",
|
||||
location: "Deutschland · remote und vor Ort",
|
||||
location: "Deutschland, remote und vor Ort",
|
||||
story: [
|
||||
"Mein Ausgangspunkt ist die Behälterglas-Produktion: Rezepte, Rohstoffe, Silos, Schichten, Satzzettel, Tagesprotokolle. Das sind keine abstrakten Entities. Es sind Zustände, die Geld, Material und Sicherheit berühren.",
|
||||
"Daraus folgt, wie ich Software baue. Fachliche Buchungen werden nicht einfach gelöscht. Berechnungen bleiben nachvollziehbar. Fehlerpfade sind Teil des Modells, nicht ein nachträglicher Dialog.",
|
||||
"Für Kunden heißt das: jemand, der den Prozess zuerst versteht und dann ein System hinterlässt, das ein anderer Engineer erklären kann. Für Arbeitgeber heißt das: Ownership statt Ticket-Abarbeitung.",
|
||||
"Ich komme aus der Behälterglas-Produktion. Dort habe ich gelernt, wo ein Rezept aufhört, Zutatenliste zu sein: an der Wanne. Temperatur, Redox, Kosten und das, was die nächste Schicht vorfindet, hängen an derselben Entscheidung. Wer das in voneinander unabhängige Masken zerlegt, baut den Bruch in die Software ein.",
|
||||
"Deshalb beginne ich nicht beim Framework. Ich frage, welche Buchung nach dem Wiegen nicht mehr still verschwinden darf, was eine Schicht der nächsten hinterlassen muss, und welche Zahl am Abend noch zur Halle passt. Erst daraus entsteht ein Datenmodell.",
|
||||
"In der Praxis heißt das oft: Satzzettel, Gemengebuch, Siloabzug, Oxidrechnung und Tagesprotokoll gehören in eine Kette. Eine Rezeptversion, die am Morgen galt, darf am Abend nicht still durch eine andere ersetzt werden, nur weil jemand in der Maske gespeichert hat. Änderungen gelten vorwärts, nicht in die bereits gebuchte Vergangenheit.",
|
||||
"W-Make Batch ist der öffentliche Beleg für diese Haltung. Die Demo unter batch.w-make.com zeigt den Ablauf, nicht einen Kundenstand. Vertrauliche Mengen, Rezepte und Hallendaten bleiben dort, wo sie hingehören. Batchmaker Studio ist die Werkbank daneben: derselbe Fachkern für Rezept und Glaschemie, ohne Silos, ohne Schichten, ohne laufende Buchungen.",
|
||||
"Für Auftraggeber bedeutet das jemanden, der den Prozess erklären kann, bevor er eine Architektur vorschlägt. Für ein Team bedeutet das, dass ich den Teil übernehme, an dem Fachlichkeit, Daten und Betrieb zusammenfallen, und ihn in einem Zustand lasse, den ein anderer Engineer lesen kann.",
|
||||
"Ich arbeite aus Deutschland, remote und vor Ort. Ich nehme Fälle an, bei denen der Ablauf wichtiger ist als die Demo. Casino, Trading und interne Infrastruktur gehören nicht auf diese Site und nicht in ein Erstgespräch mit einem Industriekunden.",
|
||||
],
|
||||
principles: [
|
||||
{
|
||||
title: "Fachlichkeit zuerst",
|
||||
text: "Ich beginne beim realen Prozess, nicht beim Framework. Regeln werden sichtbar, prüfbar und nachvollziehbar.",
|
||||
title: "Die Halle vor der Sitemap",
|
||||
text: "Ich zeichne den Tag eines Schmelzers, eines Mischers, eines Schichtführers. Welche Zahl braucht er um sechs, welche um Schichtende, welche darf er nicht mehr überschreiben. Daraus folgt die Anwendung.",
|
||||
},
|
||||
{
|
||||
title: "Verlässliche Zustände",
|
||||
text: "Buchungen, Migrationen und Fehlerpfade so, dass das System unter realen Bedingungen verständlich bleibt.",
|
||||
title: "Buchungen als Zustände",
|
||||
text: "Ein Verbrauch, der Silo und Protokoll verändert hat, ist kein Datensatz zum Löschen. Korrektur heißt Gegenbuchung, Storno oder Abgleich. Soft-Delete kaschiert den Effekt, beseitigt ihn nicht.",
|
||||
},
|
||||
{
|
||||
title: "Kleine, tragfähige Lösungen",
|
||||
text: "Keine Architektur um ihrer selbst willen. Erst die kleinste Lösung, die den Prozess dauerhaft besser macht.",
|
||||
title: "Rechnung dort, wo man sie prüfen kann",
|
||||
text: "Oxid, Redox, Satzgröße und Kosten gehören in eigene Module, nicht in die Oberfläche und nicht in den Router. Wenn die Zahl später streitet, muss der Weg zur Formel ohne Umweg über drei Schichten Code liegen.",
|
||||
},
|
||||
{
|
||||
title: "Betrieb ist Teil des Produkts",
|
||||
text: "Migrationen, Sicherung, Schichtbeginn als gemeinsame Uhr, ein Abschluss, den man wiederholen kann: das ist keine Nachsorge. Ein System, das nur in der Demo schließt, schließt in der Halle nicht.",
|
||||
},
|
||||
],
|
||||
},
|
||||
en: {
|
||||
role: "Software engineer for industrial processes",
|
||||
location: "Germany · remote and on site",
|
||||
location: "Germany, remote and on site",
|
||||
story: [
|
||||
"I start from container-glass production: recipes, raw materials, silos, shifts, batch tickets, daily logs. These are not abstract entities. They are states that touch money, material, and safety.",
|
||||
"That shapes how I build software. Domain bookings are not simply deleted. Calculations stay traceable. Failure paths belong in the model, not in an afterthought dialog.",
|
||||
"For clients that means someone who understands the process first and leaves a system another engineer can explain. For employers it means ownership, not ticket throughput.",
|
||||
"I come from container-glass production. That is where I learned where a recipe stops being a list of ingredients: at the furnace. Temperature, redox, cost and what the next shift finds all hang on the same decision. Split that into unrelated screens and you ship the fracture with the software.",
|
||||
"So I do not start with the framework. I ask which booking must not vanish quietly after weighing, what one shift must leave the next, and which figure still has to match the hall in the evening. Only then does a data model appear.",
|
||||
"In practice that often means: batch ticket, batch book, silo deduction, oxide calculation and daily log belong in one chain. A recipe version that held in the morning must not be silently replaced in the evening just because someone hit save. Changes apply forwards, not into the booked past.",
|
||||
"W-Make Batch is the public evidence for that stance. The demo at batch.w-make.com shows the flow, not a client installation. Confidential volumes, recipes and plant data stay where they belong. Batchmaker Studio is the workbench beside it: the same domain core for recipes and glass chemistry, without silos, without shifts, without live bookings.",
|
||||
"For a client that means someone who can explain the process before proposing an architecture. For a team it means I take the part where domain, data and operations meet, and leave it in a state another engineer can read.",
|
||||
"I work from Germany, remotely and on site. I take cases where the flow matters more than the demo. Casino, trading and internal infrastructure do not belong on this site, and not in a first conversation with an industrial customer.",
|
||||
],
|
||||
principles: [
|
||||
{
|
||||
title: "Domain first",
|
||||
text: "I start from the real process, not the framework. Rules become visible, testable, and traceable.",
|
||||
title: "The hall before the sitemap",
|
||||
text: "I draw the day of a melter, a mixer, a shift lead. Which figure they need at six, which at the end of the shift, which they must no longer overwrite. The application follows from that.",
|
||||
},
|
||||
{
|
||||
title: "Reliable states",
|
||||
text: "Bookings, migrations, and failure paths designed so the system stays intelligible under real conditions.",
|
||||
title: "Bookings as states",
|
||||
text: "A consumption that has already changed silo and log is not a row you delete. Correction means a reversing entry, a cancellation or a reconcile. Soft-delete hides the effect. It does not undo it.",
|
||||
},
|
||||
{
|
||||
title: "Small, durable solutions",
|
||||
text: "No architecture for its own sake. The smallest design that lastingly improves the process.",
|
||||
title: "Put the calculation where it can be checked",
|
||||
text: "Oxide, redox, batch size and cost belong in their own modules, not in the interface and not in the router. If the figure is later disputed, the path to the formula must not run through three layers of code.",
|
||||
},
|
||||
{
|
||||
title: "Operations are part of the product",
|
||||
text: "Migrations, backup, a shared clock for shift start, a close you can repeat: that is not aftercare. A system that only closes in the demo will not close on the floor.",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+92
-48
@@ -20,9 +20,9 @@ export type LocalizedProject = {
|
||||
stance: string;
|
||||
stack: string;
|
||||
role: string;
|
||||
situation: string;
|
||||
situation: string[];
|
||||
decisions: string[];
|
||||
outcome: string;
|
||||
outcome: string[];
|
||||
proof: string;
|
||||
lesson: string;
|
||||
stages: { title: string; text: string }[];
|
||||
@@ -42,46 +42,70 @@ const projects: Record<ProjectSlug, { number: string; href?: string; images: Pro
|
||||
status: "Öffentliche Produkt-Demo",
|
||||
label: "Industrie-Software · Produktentwicklung",
|
||||
title: "W-Make Batch",
|
||||
summary: "Batchmanagement für die Behälterglas-Produktion — vom Satzzettel bis zum Tagesprotokoll.",
|
||||
stance: "Das Produktionsprodukt. Eine öffentliche Demo zeigt den Ablauf, nicht den Kundenstand.",
|
||||
summary: "Batchmanagement für die Behälterglas-Produktion: vom Satzzettel über den Siloabzug bis zum Tagesprotokoll.",
|
||||
stance: "Das Betriebsprodukt. Die öffentliche Demo zeigt den Ablauf, nicht den Kundenstand.",
|
||||
stack: "Node.js · Express · SQLite · Web Components · native Tests · Playwright",
|
||||
role: "Domänenmodell, Full-Stack-Entwicklung und technische Qualität.",
|
||||
situation: "Ein Produktionsprozess lebt von Rezepten, Materialverbrauch, Silos, Schichten und Berechnungen. Wird das als lose Sammlung von Masken gebaut, gehen fachliche Zusammenhänge verloren — und Buchungen werden zu editierbaren Tabellenzeilen.",
|
||||
situation: [
|
||||
"In der Behälterglas-Produktion ist der Tag eine Kette. Eine Rezeptversion gilt, ein Satzzettel geht an die Waage, der Verbrauch geht vom Silo ab, Oxid und Redox müssen zur Wanne passen, die Schicht übergibt, der Tag schließt. Bricht eines dieser Glieder, stehen am nächsten Morgen drei Zahlen im Raum, die nicht zusammenpassen.",
|
||||
"Wird das als lose Sammlung von Masken gebaut, kopiert jemand die Werte von einem Blatt auf das nächste. Der Satzzettel sagt etwas anderes als der Silostand, das Protokoll etwas anderes als beides. Die schnellste Korrektur in Software ist dann das Löschen oder Überschreiben einer Zeile. Nach dem Wiegen ist das bereits eine Lüge gegenüber Bestand und Schicht.",
|
||||
"Dazu kommt der Druck der Schichtübergabe. Was mündlich nachgereicht wird, steht nirgendwo. Wer morgens übernimmt, erbt eine Halle und eine Tabelle, die sich widersprechen.",
|
||||
],
|
||||
decisions: [
|
||||
"Fachliche Buchungen sind Zustände, keine CRUD-Datensätze zum beliebigen Löschen.",
|
||||
"Der Satzzettel und das Tagesprotokoll gehören in dasselbe Modell, nicht in getrennte Tools.",
|
||||
"Berechnungen und Materialflüsse bleiben nachvollziehbar, auch wenn die Oberfläche schlank bleibt.",
|
||||
"Fachliche Buchungen sind Zustände. Eine Korrektur nach dem Siloabzug ist eine Gegenbuchung, ein Storno oder ein Abgleich, kein DELETE auf der Zeile.",
|
||||
"Satzzettel, Gemengebuch und Tagesprotokoll gehören in dasselbe Modell. Zwei Tools an dieser Naht erzeugen denselben Papierbruch, den die Software ersetzen sollte.",
|
||||
"Oxid, Redox, Satzgröße und Kosten bleiben an der Rezeptversion hängen und liegen in eigenen Modulen. Die Oberfläche zeigt die Zahl, sie erfindet sie nicht.",
|
||||
"Schichtbeginn ist eine gemeinsame Uhr, kein voreingestelltes Feld in einem Formular. Ohne diese Uhr driftet der Tag zwischen Stationen.",
|
||||
"Migrationen, Sicherung und ein Abschluss, den man wiederholen kann, gehören zum Produkt. Ein System, das nur in der Demo schließt, schließt in der Halle nicht.",
|
||||
"Die öffentliche Demo zeigt das Modell. Kundendaten, Mengen und interne Kennzahlen bleiben außen vor.",
|
||||
],
|
||||
outcome: [
|
||||
"Ein betreibbares System mit öffentlicher Demo unter batch.w-make.com. Man kann den Weg von der Rezeptversion über den Satzzettel in das Tagesprotokoll nachgehen, ohne einen Kundenstand zu sehen.",
|
||||
"Vertrauliche Hallendaten, Rezepte und Mengen stehen nicht auf dieser Site. Es gibt keine veröffentlichten Durchsatzzahlen, keine Verfügbarkeitsversprechen und keine Kundennamen.",
|
||||
],
|
||||
outcome: "Ein betreibbares System mit öffentlicher Demo. Vertrauliche Kundendaten, Mengen und interne Kennzahlen bleiben bewusst außen vor.",
|
||||
proof: "Öffentliche Produkt-Demo unter batch.w-make.com. Die Case Study beschreibt das Modell, nicht den Kundenstand.",
|
||||
lesson: "Ein Produktionssystem wird besser, wenn die fachliche Irreversibilität Teil der Architektur ist — nicht eine Validierung im Formular.",
|
||||
lesson: "Ein Produktionssystem wird besser, wenn die fachliche Unumkehrbarkeit im Datenmodell steckt. Eine Validierung im Formular kommt zu spät, sobald Silo und Protokoll schon geschrieben haben.",
|
||||
stages: [
|
||||
{ title: "Rezept", text: "Zusammensetzung und Version bleiben mit dem späteren Verbrauch verbunden." },
|
||||
{ title: "Satz", text: "Der Satzzettel ist ein fachlicher Auftrag, kein Ausdruck einer Tabelle." },
|
||||
{ title: "Protokoll", text: "Der Tag schließt als nachvollziehbarer Zustand, nicht als exportierte Liste." },
|
||||
{ title: "Rezept", text: "Zusammensetzung, Version, Temperatur und Kosten bleiben mit dem späteren Verbrauch verbunden." },
|
||||
{ title: "Satzzettel", text: "Der Zettel ist der Auftrag an die Waage, kein Ausdruck einer Tabelle." },
|
||||
{ title: "Silo", text: "Der Verbrauch geht vom Bestand ab. Danach ist die Buchung Teil der Halle." },
|
||||
{ title: "Gemengebuch", text: "Was eingewogen wurde, bleibt an Satz und Rezeptversion gebunden." },
|
||||
{ title: "Protokoll", text: "Der Tag schließt als Zustand, den die nächste Schicht vorfindet, nicht als exportierte Liste." },
|
||||
],
|
||||
},
|
||||
en: {
|
||||
status: "Public product demo",
|
||||
label: "Industrial software · product development",
|
||||
title: "W-Make Batch",
|
||||
summary: "Batch management for container-glass production — from the batch ticket to the daily log.",
|
||||
stance: "The production product. A public demo shows the flow, not a client installation.",
|
||||
summary: "Batch management for container-glass production: from the batch ticket through silo deduction to the daily log.",
|
||||
stance: "The operations product. The public demo shows the flow, not a client installation.",
|
||||
stack: "Node.js · Express · SQLite · Web Components · native tests · Playwright",
|
||||
role: "Domain model, full-stack development, and technical quality.",
|
||||
situation: "A production process lives on recipes, material use, silos, shifts, and calculations. Built as a loose set of screens, the domain relationships disappear — and bookings become editable table rows.",
|
||||
situation: [
|
||||
"In container-glass production the day is a chain. A recipe version holds, a batch ticket goes to the scale, consumption leaves the silo, oxide and redox have to match the furnace, the shift hands over, the day closes. If one link breaks, three figures that do not agree are waiting the next morning.",
|
||||
"Built as a loose set of screens, someone copies values from one sheet to the next. The ticket says one thing, the silo another, the log a third. The fastest correction in software is then to delete or overwrite a row. After weighing, that is already a lie to stock and to the shift.",
|
||||
"Shift handover adds pressure. What is passed on verbally is written nowhere. Whoever takes over in the morning inherits a hall and a table that contradict each other.",
|
||||
],
|
||||
decisions: [
|
||||
"Domain bookings are states, not CRUD records that can be deleted at will.",
|
||||
"The batch ticket and the daily log belong in one model, not in separate tools.",
|
||||
"Calculations and material flows stay traceable even when the interface stays lean.",
|
||||
"Domain bookings are states. A correction after silo deduction is a reversing entry, a cancellation or a reconcile, not a DELETE on the row.",
|
||||
"Batch ticket, batch book and daily log belong in one model. Two tools at that seam recreate the paper fracture the software was meant to replace.",
|
||||
"Oxide, redox, batch size and cost stay bound to the recipe version and live in their own modules. The interface shows the figure. It does not invent it.",
|
||||
"Shift start is a shared clock, not a default in a form field. Without that clock the day drifts between stations.",
|
||||
"Migrations, backup and a close you can repeat belong to the product. A system that only closes in the demo will not close on the floor.",
|
||||
"The public demo shows the model. Client data, volumes and internal metrics stay off the site.",
|
||||
],
|
||||
outcome: [
|
||||
"An operable system with a public demo at batch.w-make.com. You can follow the path from recipe version through the batch ticket into the daily log without seeing a client installation.",
|
||||
"Confidential plant data, recipes and volumes are not on this site. There are no published throughput figures, no uptime claims and no client names.",
|
||||
],
|
||||
outcome: "An operable system with a public demo. Confidential client data, volumes, and internal metrics stay unpublished.",
|
||||
proof: "Public product demo at batch.w-make.com. This case study describes the model, not a client installation.",
|
||||
lesson: "A production system improves when domain irreversibility is part of the architecture — not a form validation.",
|
||||
lesson: "A production system improves when domain irreversibility lives in the data model. A form validation comes too late once silo and log have already been written.",
|
||||
stages: [
|
||||
{ title: "Recipe", text: "Composition and version stay tied to later consumption." },
|
||||
{ title: "Batch", text: "The ticket is a domain order, not a printout of a table." },
|
||||
{ title: "Log", text: "The day closes as a traceable state, not an exported list." },
|
||||
{ title: "Recipe", text: "Composition, version, temperature and cost stay tied to later consumption." },
|
||||
{ title: "Ticket", text: "The ticket is the order to the scale, not a printout of a table." },
|
||||
{ title: "Silo", text: "Consumption leaves the stock. After that the booking is part of the hall." },
|
||||
{ title: "Batch book", text: "What was weighed stays bound to the batch and the recipe version." },
|
||||
{ title: "Log", text: "The day closes as a state the next shift will find, not as an exported list." },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -96,46 +120,66 @@ const projects: Record<ProjectSlug, { number: string; href?: string; images: Pro
|
||||
status: "Eigenständig betreibbares Produkt",
|
||||
label: "Standalone · Recipe Engineering",
|
||||
title: "Batchmaker Studio",
|
||||
summary: "Schlankes Recipe-Studio für Rezepte, Rohstoffe, Satzzettel und Glaschemie.",
|
||||
stance: "Die Werkbank am Schreibtisch. Derselbe Fachkern, bewusst ohne Silos, Schichten und laufende Buchungen.",
|
||||
summary: "Schlankes Recipe-Studio für Rezepte, Rohstoffe, Satzzettel und Glaschemie, ohne Silos und ohne laufende Schichten.",
|
||||
stance: "Die Werkbank am Schreibtisch. Derselbe Fachkern wie W-Make Batch, ohne den Betrieb der Halle.",
|
||||
stack: "Node.js · Express · node:sqlite · Vanilla JS · Vite · native Tests",
|
||||
role: "Produktarchitektur, Full-Stack-Entwicklung und Calculation Engine.",
|
||||
situation: "Rezeptarbeit braucht denselben fachlichen Kern wie die Produktion — aber nicht Silos, Schichten und laufende Buchungen. Ein volles Betriebssystem ist für die Entwicklung am Schreibtisch zu schwer.",
|
||||
decisions: [
|
||||
"Derselbe Domänenkern, bewusst kleinerer Zuschnitt.",
|
||||
"Eigener Server, eigene SQLite-Datei, eigene schlanke Oberfläche.",
|
||||
"Validierung als sichtbarer Schritt, nicht als versteckte Nebenwirkung.",
|
||||
situation: [
|
||||
"Rezeptarbeit braucht denselben fachlichen Kern wie die Produktion: Rohstoffe, Oxidrechnung, Redox, Satzgröße, Kosten, Versionen. Sie braucht nicht Silos, Schichten und laufende Buchungen. Ein volles Betriebssystem ist für die Entwicklung am Schreibtisch zu schwer. Man will eine Rezeptversion ändern, die Chemie prüfen und einen Satzzettel drucken, ohne eine Schicht zu eröffnen.",
|
||||
"Wer beides in ein Produkt zwingt, belastet die Werkbank mit Hallenregeln und die Halle mit Entwurfszuständen. Entwürfe geraten in den Bestand, oder der Bestand wird am Schreibtisch nachgebaut. Beides ist teuer.",
|
||||
],
|
||||
outcome: "Ein eigenständig betreibbares Werkzeug für Rezeptentwicklung, Glaschemie und druckfertige Satzzettel. Keine unbelegten Effizienzversprechen.",
|
||||
proof: "Öffentliche Case Study und der bewusst getrennte Produktzuschnitt gegenüber W-Make Batch.",
|
||||
lesson: "Produktgrenzen sind Architektur. Ein gutes Werkzeug muss den Nachbarprozess nicht vollständig abbilden.",
|
||||
decisions: [
|
||||
"Derselbe Fachkern für Rezept, Rohstoff und Glaschemie, kleinerer Zuschnitt: keine Silos, keine Schichten, keine laufenden Buchungen.",
|
||||
"Eigener Server, eigene SQLite-Datei, eigene schlanke Oberfläche. Studio hängt nicht am Betriebsprodukt.",
|
||||
"Validierung ist ein sichtbarer Schritt. Eine Rechnung, die still im Speichern mitläuft, wird später niemand mehr finden.",
|
||||
"Satzzettel entstehen hier als Entwurf und Druckvorlage. Gebucht wird erst in W-Make Batch.",
|
||||
"Keine unbelegten Effizienzversprechen. Das Produkt ist die Werkbank, nicht ein Ersatz für den Betrieb.",
|
||||
],
|
||||
outcome: [
|
||||
"Ein eigenständig betreibbares Werkzeug für Rezeptentwicklung, Glaschemie und druckfertige Satzzettel. Man kann am Schreibtisch arbeiten, ohne eine Schicht zu simulieren.",
|
||||
"Die Grenze zu W-Make Batch bleibt sichtbar. Was in Studio entworfen wird, wird in Batch zum Auftrag. Die Case Study belegt den Zuschnitt, nicht einen Kundenstand.",
|
||||
],
|
||||
proof: "Öffentliche Case Study und der getrennte Produktzuschnitt gegenüber W-Make Batch.",
|
||||
lesson: "Produktgrenzen sind Architektur. Ein gutes Werkzeug muss den Nachbarprozess nicht vollständig abbilden. Wer Studio und Betrieb vermischt, trägt Entwürfe in den Bestand oder den Bestand an den Schreibtisch.",
|
||||
stages: [
|
||||
{ title: "Rezepte", text: "Versionieren, vergleichen, importieren und exportieren." },
|
||||
{ title: "Glaschemie", text: "Oxide, Redox, Physik und nachvollziehbare Berechnungen." },
|
||||
{ title: "Rezepte", text: "Versionieren, vergleichen, importieren und exportieren, gebunden an Rohstoffe und Kosten." },
|
||||
{ title: "Rohstoffe", text: "Stammdaten, aus denen Oxid und Satz später gerechnet werden." },
|
||||
{ title: "Glaschemie", text: "Oxide, Redox, Physik und Rechnungen, die man prüfen kann." },
|
||||
{ title: "Satzzettel", text: "Entwurf, Skalierung, Vorschau, druckfertige Ausgabe." },
|
||||
{ title: "Validierung", text: "Ein eigener Schritt, bevor eine Version als brauchbar gilt." },
|
||||
],
|
||||
},
|
||||
en: {
|
||||
status: "Independently operable product",
|
||||
label: "Standalone · recipe engineering",
|
||||
title: "Batchmaker Studio",
|
||||
summary: "A lean recipe studio for recipes, raw materials, batch tickets, and glass chemistry.",
|
||||
stance: "The desk-side workbench. The same domain core, deliberately without silos, shifts, and live bookings.",
|
||||
summary: "A lean recipe studio for recipes, raw materials, batch tickets and glass chemistry, without silos and without live shifts.",
|
||||
stance: "The desk-side workbench. The same domain core as W-Make Batch, without the hall’s operations.",
|
||||
stack: "Node.js · Express · node:sqlite · Vanilla JS · Vite · native tests",
|
||||
role: "Product architecture, full-stack development, and calculation engine.",
|
||||
situation: "Recipe work needs the same domain core as production — but not silos, shifts, and live bookings. A full operations system is too heavy for desk-side development.",
|
||||
decisions: [
|
||||
"The same domain core, deliberately smaller scope.",
|
||||
"Its own server, SQLite file, and lean browser interface.",
|
||||
"Validation as a visible step, not a hidden side effect.",
|
||||
situation: [
|
||||
"Recipe work needs the same domain core as production: raw materials, oxide calculation, redox, batch size, cost, versions. It does not need silos, shifts and live bookings. A full operations system is too heavy for desk-side development. You want to change a recipe version, check the chemistry and print a ticket without opening a shift.",
|
||||
"Force both into one product and the workbench inherits hall rules while the hall inherits draft states. Drafts leak into stock, or stock is rebuilt at the desk. Both are expensive.",
|
||||
],
|
||||
outcome: "An independently operable tool for recipe work, glass chemistry, and print-ready batch tickets. No unverifiable efficiency claims.",
|
||||
proof: "This public case study and the deliberate product boundary against W-Make Batch.",
|
||||
lesson: "Product boundaries are architecture. A good tool does not have to model the neighbouring process in full.",
|
||||
decisions: [
|
||||
"The same domain core for recipe, raw material and glass chemistry, smaller scope: no silos, no shifts, no live bookings.",
|
||||
"Its own server, SQLite file and lean browser interface. Studio does not hang off the operations product.",
|
||||
"Validation is a visible step. A calculation that runs quietly on save will not be found later.",
|
||||
"Batch tickets originate here as draft and print-ready output. Booking happens in W-Make Batch.",
|
||||
"No unverifiable efficiency claims. The product is the workbench, not a substitute for operations.",
|
||||
],
|
||||
outcome: [
|
||||
"An independently operable tool for recipe work, glass chemistry and print-ready batch tickets. You can work at the desk without simulating a shift.",
|
||||
"The boundary with W-Make Batch stays visible. What is drafted in Studio becomes an order in Batch. This case study documents the cut, not a client installation.",
|
||||
],
|
||||
proof: "This public case study and the separate product boundary against W-Make Batch.",
|
||||
lesson: "Product boundaries are architecture. A good tool does not have to model the neighbouring process in full. Mix studio and operations and you carry drafts into stock, or stock onto the desk.",
|
||||
stages: [
|
||||
{ title: "Recipes", text: "Version, compare, import, and export." },
|
||||
{ title: "Chemistry", text: "Oxides, redox, physics, and traceable calculations." },
|
||||
{ title: "Recipes", text: "Version, compare, import and export, bound to raw materials and cost." },
|
||||
{ title: "Materials", text: "Master data from which oxide and batch size are later calculated." },
|
||||
{ title: "Chemistry", text: "Oxides, redox, physics, and calculations you can inspect." },
|
||||
{ title: "Tickets", text: "Draft, scale, preview, print-ready output." },
|
||||
{ title: "Validation", text: "A dedicated step before a version counts as usable." },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
+82
-62
@@ -11,7 +11,7 @@ export const dictionaries = {
|
||||
actions: {
|
||||
viewWork: "Arbeit ansehen",
|
||||
startConversation: "Gespräch beginnen",
|
||||
openCase: "Case Study",
|
||||
openCase: "Fall lesen",
|
||||
openNote: "Notiz lesen",
|
||||
send: "Anfrage senden",
|
||||
sending: "Wird gesendet…",
|
||||
@@ -19,45 +19,53 @@ export const dictionaries = {
|
||||
allNotes: "Alle Notizen",
|
||||
},
|
||||
home: {
|
||||
kicker: "Jan Wagner · Software Engineering",
|
||||
title: "Software für Prozesse, auf die man sich verlassen muss.",
|
||||
lede: "Ich entwickle robuste digitale Systeme für industrielle und anspruchsvolle Geschäftsprozesse — mit Domänenverständnis, klarer Architektur und Verantwortung für den Betrieb.",
|
||||
asideLabel: "Was ich verbinde",
|
||||
asideTitle: "Glass Technology, Full-Stack Engineering und Systems Thinking.",
|
||||
asideBody: "Der gemeinsame Nenner: reale Abläufe in Software übersetzen, ohne die fachliche Wahrheit zu verlieren.",
|
||||
workKicker: "Ausgewählte Arbeit",
|
||||
workTitle: "Nicht Features. Systeme.",
|
||||
workLede: "Jeder Beleg zeigt dieselbe Haltung: Domäne verstehen, Entscheidungen explizit machen, ein System im Alltag betreiben.",
|
||||
kicker: "Jan Wagner · Behälterglas und Software",
|
||||
title: "Software für Satzzettel, Silo und Schichtabschluss.",
|
||||
lede: "Ich baue Systeme, in denen Rezept, Satzzettel, Siloabzug und Tagesabschluss zusammengehören. Der Ausgangspunkt ist die Behälterglas-Produktion. Derselbe Anspruch gilt überall dort, wo Buchungen Geld, Material und die nächste Schicht berühren.",
|
||||
asideLabel: "Herkunft",
|
||||
asideTitle: "Die Reihenfolge kommt aus der Halle.",
|
||||
asideBody: "Rohstoffe, Redox, Schichtbeginn, Gemengebuch. Wer das als Formularstapel behandelt, verliert die Folge, in der die Halle tatsächlich arbeitet.",
|
||||
workKicker: "Veröffentlichbare Arbeit",
|
||||
workTitle: "W-Make Batch und Batchmaker Studio.",
|
||||
workLede: "W-Make Batch ist das Betriebsprodukt mit öffentlicher Demo unter batch.w-make.com. Batchmaker Studio ist die Werkbank für Rezept und Glaschemie, ohne laufende Schichten und ohne Silos.",
|
||||
methodKicker: "Arbeitsweise",
|
||||
methodTitle: "Senior heißt: Entscheidungen verantworten.",
|
||||
methodLede: "Technologie ist Mittel. Entscheidend ist, ob ein System die richtigen fachlichen Zustände abbildet und erklärbar bleibt.",
|
||||
methodTitle: "Zuerst der Schichttag, dann die Maske.",
|
||||
methodLede: "Ich kläre, was um Schichtbeginn gelten muss und was am Abend noch stimmen darf. Erst dann folgt die Technik. Wenn Silo, Rezept und Protokoll nachts auseinanderlaufen, hilft keine neue Oberfläche.",
|
||||
offerKicker: "Zusammenarbeit",
|
||||
offerTitle: "Wo ich am meisten beitragen kann.",
|
||||
notesKicker: "Engineering Notes",
|
||||
notesTitle: "Entscheidungen, nicht News.",
|
||||
ctaKicker: "Gespräch",
|
||||
ctaTitle: "Sie haben einen Prozess, der bessere Software verdient?",
|
||||
ctaBody: "Lassen Sie uns klären, wo der größte Hebel liegt — in einem neuen Produkt, einer bestehenden Anwendung oder einer technischen Entscheidung.",
|
||||
offerTitle: "Drei Formen der Zusammenarbeit.",
|
||||
notesKicker: "Notizen",
|
||||
notesTitle: "Entscheidungen aus dem Betrieb.",
|
||||
ctaKicker: "Kontakt",
|
||||
ctaTitle: "Schreiben Sie, wenn der Ablauf in der Software bricht.",
|
||||
ctaBody: "Schildern Sie den Ablauf, der heute in Kopien, Nebenrechnungen oder stillen Korrekturen endet. Ich antworte in der Regel innerhalb von zwei Werktagen, sofern ich den Fall führen kann.",
|
||||
},
|
||||
about: {
|
||||
kicker: "Über mich",
|
||||
title: "Von der Glaswanne in die Architektur.",
|
||||
lede: "Ich komme aus der Behälterglas-Produktion und baue Software so, wie ein guter Prozess gedacht ist: nachvollziehbar, irreversibel wo nötig, und im Betrieb erklärbar.",
|
||||
title: "Aus der Behälterglas-Produktion.",
|
||||
lede: "Ich bin Jan Wagner. Ich komme aus der Schmelze und entwickle Software für Abläufe, die man am nächsten Morgen noch erklären können muss.",
|
||||
close:
|
||||
"Wenn Sie einen Ablauf haben, der in Kopien oder stillen Korrekturen endet, schreiben Sie den Prozess auf. Ich sage Ihnen, ob ich den Fall führen kann.",
|
||||
},
|
||||
work: {
|
||||
kicker: "Arbeit",
|
||||
title: "Veröffentlichbare Referenzen.",
|
||||
lede: "Nur das, was öffentlich stehen darf. Keine Kundennamen, keine unbelegten Kennzahlen, keine internen Systeme.",
|
||||
title: "W-Make Batch und Batchmaker Studio.",
|
||||
lede: "Keine Kundennamen, keine internen Mengen, keine Verfügbarkeitsversprechen. Die Demo unter batch.w-make.com zeigt das Modell. Ein Kundenstand bleibt beim Kunden.",
|
||||
},
|
||||
notes: {
|
||||
kicker: "Notizen",
|
||||
title: "Was im Betrieb zählt.",
|
||||
lede: "Kurze, substanzielle Texte zu Entscheidungen. Kein Feed, keine Ankündigungen.",
|
||||
title: "Texte für Leute, die den Betrieb verantworten.",
|
||||
lede: "Keine Ankündigungen und keine Tool-Listen. Es geht um Buchungen, Schichtübergabe, Produktgrenzen und das, was nach dem Go-Live übrig bleibt.",
|
||||
},
|
||||
contact: {
|
||||
kicker: "Kontakt",
|
||||
title: "Ein Prozess. Eine klare nächste Frage.",
|
||||
lede: "Beschreiben Sie den Ablauf, der heute reibt. Ich antworte, wenn ich wirklich helfen kann.",
|
||||
title: "Beschreiben Sie den Ablauf, der heute reibt.",
|
||||
lede: "Nützlich sind der Prozess im Alltag, wer ihn trägt, und ob es um eine bestehende Anwendung oder um einen Neubau geht. Eine Folienlage brauche ich nicht.",
|
||||
needTitle: "Was in der ersten Nachricht helfen sollte",
|
||||
need: [
|
||||
"Welcher Ablauf heute in Kopien, Nebenrechnungen oder stillen Korrekturen endet.",
|
||||
"Wer ihn im Alltag trägt: Schmelzer, Mischer, Schichtführer, Labor, IT.",
|
||||
"Ob es um eine bestehende Anwendung geht oder um einen Neubau.",
|
||||
],
|
||||
name: "Name",
|
||||
email: "E-Mail",
|
||||
company: "Unternehmen (optional)",
|
||||
@@ -70,7 +78,7 @@ export const dictionaries = {
|
||||
network: "Senden gerade nicht möglich. Bitte später erneut versuchen oder direkt schreiben.",
|
||||
delivery: "Die Anfrage wurde gespeichert, die E-Mail ist fehlgeschlagen. Bitte schreiben Sie direkt an",
|
||||
rate: "Zu viele Anfragen in kurzer Zeit. Bitte schreiben Sie direkt per E-Mail.",
|
||||
reply: "Ich antworte in der Regel innerhalb von zwei Werktagen — und nur, wenn ich wirklich helfen kann.",
|
||||
reply: "Ich antworte in der Regel innerhalb von zwei Werktagen, und nur wenn ich den Fall wirklich führen kann.",
|
||||
emailDirect: "Direkt per E-Mail",
|
||||
},
|
||||
legal: {
|
||||
@@ -84,11 +92,13 @@ export const dictionaries = {
|
||||
role: "Verantwortung",
|
||||
decisions: "Entscheidungen",
|
||||
outcome: "Ergebnis",
|
||||
proof: "Beweis",
|
||||
lesson: "Lernpunkt",
|
||||
proof: "Was man prüfen kann",
|
||||
lesson: "Was bleibt",
|
||||
modelTitle: "Der Ablauf im Modell.",
|
||||
galleryTitle: "Blick in die Anwendung.",
|
||||
},
|
||||
footer: {
|
||||
line: "Software Engineering · Glass Technology · Systems Thinking",
|
||||
line: "Software für industrielle Prozesse",
|
||||
imprint: "Impressum",
|
||||
privacy: "Datenschutz",
|
||||
},
|
||||
@@ -112,53 +122,61 @@ export const dictionaries = {
|
||||
actions: {
|
||||
viewWork: "See the work",
|
||||
startConversation: "Start a conversation",
|
||||
openCase: "Case study",
|
||||
openNote: "Read note",
|
||||
openCase: "Read the case",
|
||||
openNote: "Read the note",
|
||||
send: "Send inquiry",
|
||||
sending: "Sending…",
|
||||
backToWork: "All work",
|
||||
allNotes: "All notes",
|
||||
},
|
||||
home: {
|
||||
kicker: "Jan Wagner · Software Engineering",
|
||||
title: "Software for processes that have to hold.",
|
||||
lede: "I build durable digital systems for industrial and demanding business processes — with domain understanding, explicit architecture, and ownership of operations.",
|
||||
asideLabel: "What I connect",
|
||||
asideTitle: "Glass technology, full-stack engineering, and systems thinking.",
|
||||
asideBody: "The common thread: translate real operations into software without losing the domain truth.",
|
||||
workKicker: "Selected work",
|
||||
workTitle: "Not features. Systems.",
|
||||
workLede: "Each reference shows the same stance: understand the domain, make decisions explicit, run the system in real conditions.",
|
||||
kicker: "Jan Wagner · container glass and software",
|
||||
title: "Software for batch tickets, silos and the shift close.",
|
||||
lede: "I build systems in which recipe, batch ticket, silo deduction and day close belong together. The starting point is container-glass production. The same standard applies wherever bookings touch money, material and the next shift.",
|
||||
asideLabel: "Background",
|
||||
asideTitle: "The order comes from the hall.",
|
||||
asideBody: "Raw materials, redox, shift start, batch book. Treat that as a pile of forms and you lose the sequence in which the hall actually works.",
|
||||
workKicker: "Work I can publish",
|
||||
workTitle: "W-Make Batch and Batchmaker Studio.",
|
||||
workLede: "W-Make Batch is the operations product with a public demo at batch.w-make.com. Batchmaker Studio is the workbench for recipes and glass chemistry, without live shifts and without silos.",
|
||||
methodKicker: "How I work",
|
||||
methodTitle: "Senior means owning the decision.",
|
||||
methodLede: "Technology is a means. What matters is whether a system models the right domain states and stays explainable.",
|
||||
methodTitle: "The shift day first, then the screen.",
|
||||
methodLede: "I settle what must hold at shift start and what may still be true in the evening. The stack comes after that. If silo, recipe and log drift apart overnight, a new interface will not help.",
|
||||
offerKicker: "Working together",
|
||||
offerTitle: "Where I contribute most.",
|
||||
notesKicker: "Engineering notes",
|
||||
notesTitle: "Decisions, not news.",
|
||||
ctaKicker: "Conversation",
|
||||
ctaTitle: "A process that deserves better software?",
|
||||
ctaBody: "Let’s find the highest-leverage point — a new product, an existing system, or a technical decision.",
|
||||
offerTitle: "Three ways of working together.",
|
||||
notesKicker: "Notes",
|
||||
notesTitle: "Decisions from operations.",
|
||||
ctaKicker: "Contact",
|
||||
ctaTitle: "Write if the process is breaking in the software.",
|
||||
ctaBody: "Describe the flow that currently ends in copies, side calculations or quiet corrections. I usually reply within two working days, if I can take the case.",
|
||||
},
|
||||
about: {
|
||||
kicker: "About",
|
||||
title: "From the glass furnace to the architecture.",
|
||||
lede: "I come from container-glass production and design software the way a good process is designed: traceable, irreversible where it must be, and explainable in operations.",
|
||||
title: "From container-glass production.",
|
||||
lede: "I am Jan Wagner. I come from the melt and build software for flows that still have to make sense the next morning.",
|
||||
close:
|
||||
"If you have a flow that currently ends in copies or quiet corrections, write the process down. I will tell you whether I can take the case.",
|
||||
},
|
||||
work: {
|
||||
kicker: "Work",
|
||||
title: "References I can publish.",
|
||||
lede: "Only what is cleared for the public web. No client names, no unverifiable metrics, no internal systems.",
|
||||
title: "W-Make Batch and Batchmaker Studio.",
|
||||
lede: "No client names, no internal volumes, no uptime claims. The demo at batch.w-make.com shows the model. A client installation stays with the client.",
|
||||
},
|
||||
notes: {
|
||||
kicker: "Notes",
|
||||
title: "What matters in operations.",
|
||||
lede: "Short, substantial writing about decisions. Not a feed, not announcements.",
|
||||
title: "Writing for people who own the plant day.",
|
||||
lede: "No announcements and no tool lists. The subject is bookings, shift handover, product boundaries, and what remains after go-live.",
|
||||
},
|
||||
contact: {
|
||||
kicker: "Contact",
|
||||
title: "One process. One clear next question.",
|
||||
lede: "Describe the flow that is fraying. I reply when I can actually help.",
|
||||
title: "Describe the flow that currently rubs.",
|
||||
lede: "What helps: the process in daily use, who carries it, and whether this is an existing system or a new build. I do not need a slide deck.",
|
||||
needTitle: "What helps in the first message",
|
||||
need: [
|
||||
"Which flow currently ends in copies, side calculations or quiet corrections.",
|
||||
"Who carries it day to day: melter, mixer, shift lead, lab, IT.",
|
||||
"Whether this is an existing application or a new build.",
|
||||
],
|
||||
name: "Name",
|
||||
email: "Email",
|
||||
company: "Company (optional)",
|
||||
@@ -171,7 +189,7 @@ export const dictionaries = {
|
||||
network: "Sending is unavailable right now. Please try again later or write directly.",
|
||||
delivery: "The inquiry was stored, but email delivery failed. Please write directly to",
|
||||
rate: "Too many inquiries in a short time. Please write directly by email.",
|
||||
reply: "I usually reply within two working days — and only when I can actually help.",
|
||||
reply: "I usually reply within two working days, and only if I can actually take the case.",
|
||||
emailDirect: "Email directly",
|
||||
},
|
||||
legal: {
|
||||
@@ -184,12 +202,14 @@ export const dictionaries = {
|
||||
situation: "Situation",
|
||||
role: "Responsibility",
|
||||
decisions: "Decisions",
|
||||
outcome: "Outcome",
|
||||
proof: "Evidence",
|
||||
lesson: "Takeaway",
|
||||
outcome: "Result",
|
||||
proof: "What you can inspect",
|
||||
lesson: "What remains",
|
||||
modelTitle: "The flow as a model.",
|
||||
galleryTitle: "A look at the application.",
|
||||
},
|
||||
footer: {
|
||||
line: "Software Engineering · Glass Technology · Systems Thinking",
|
||||
line: "Software for industrial processes",
|
||||
imprint: "Legal notice",
|
||||
privacy: "Privacy",
|
||||
},
|
||||
|
||||
@@ -35,8 +35,8 @@ async function smtpSend(config: SmtpConfig, inquiry: Inquiry): Promise<void> {
|
||||
const body = [
|
||||
`Name: ${inquiry.name}`,
|
||||
`E-Mail: ${inquiry.email}`,
|
||||
`Unternehmen: ${inquiry.company || "—"}`,
|
||||
`Thema: ${inquiry.topic || "—"}`,
|
||||
`Unternehmen: ${inquiry.company || "-"}`,
|
||||
`Thema: ${inquiry.topic || "-"}`,
|
||||
`Sprache: ${inquiry.locale}`,
|
||||
"",
|
||||
inquiry.message,
|
||||
|
||||
Reference in New Issue
Block a user