Skip to content

TypeScript & Node.js

I write a business rule once, in code, and it then holds everywhere.

The same rule at three doors

Someone enters a 40 percent discount. What happens next does not depend on where the number comes in.

Form in the portal

Input
Discount 40% in the form
Rule
quote.discount: 40 > 15, rejected
Display
„Over 15% needs approval“
Result
Nothing saved

Interface

Input
POST /quotes with discount 40%
Rule
quote.discount: 40 > 15, rejected
Log
warn quote.discount 40
Result
Reply 422, nothing saved

Spreadsheet import

Input
Row 114: discount 40%
Rule
quote.discount: 40 > 15, rejected
Log
warn quote.discount 40, row 114
Result
Row skipped, 249 of 250 imported

Example values. You decide which limit applies in your company. I write it down once.

The rule behind it

Here it is, explained line by line. The limit is written once in code, and all three doors read it from there.

rules/quote.tsTypeScript, Example, abridged
import { z } from 'zod';// Percent. Above it, a person decides.export const MAX_DISCOUNT = 15;export const QuoteLine = z.object({  item: z.string().min(1),  quantity: z.number().int().min(1),  discount: z.number().max(MAX_DISCOUNT),});

The rule is written once.

The limit of 15 percent is on line 4 and nowhere else. If it changes, I change that one line, and the form, the interface and the import follow.

Lines 1 to 10

// Form, interface and import:const result = QuoteLine.safeParse(input);if (!result.success) {  return reject(result.error);}

Wrong input stops at the door.

Every place that accepts data calls the same check. A wrong number never reaches the database, so nobody has to hunt for it in a report later.

Lines 11 to 15

function reject(error: z.ZodError) {  log.warn('quote.discount', error.issues);  return {    status: 422,    message: 'Over 15% needs approval',  };}

The error goes to the log.

The check writes the incident to the log with the rule and the value. The user gets a sentence they understand, and no technical error page.

Lines 16 to 22

test('above the limit fails', () => {  const line = { item: 'A', quantity: 1 };  const bad = { ...line, discount: 16 };  expect(QuoteLine.safeParse(bad).success)    .toBe(false);});

A test pins the limit.

The test checks the value just above the limit, not the forms in front of it. Whoever moves the limit later runs into this test and has to confirm the change on purpose.

Lines 23 to 28

What I use it for

  • Custom business logic behind a portal
  • Pricing and quoting logic for sales processes
  • Import and export paths for existing data
  • Role and permission models for several tenants
  • MVPs that an in-house team takes over later

Where it already runs

  • 2026

    KI-Exposé-Generator

    Proposals in about 3 minutes

    Next.js, TypeScript, AI, PostgreSQL, PDF

  • 2025

    Snipeflip

    up to 2,500 operations per day

    Next.js, Node.js, PostgreSQL, Docker, Cloud

  • 2025

    RecRobot

    from 3 to 12 automated steps

    TypeScript, AI, Automation, APIs, Cloud

All projects

It is part of these offers

Which rule drifts apart at your company?

Describe the case to me in three sentences. I reply myself, and the call takes 15 minutes.

Before that: three sentences, two working days to a reply, a 15-minute call. How it starts