Form in the portal
- Input
- Discount 40% in the form
- Rule
- quote.discount: 40 > 15, rejected
- Display
- „Over 15% needs approval“
- Result
- Nothing saved
I write a business rule once, in code, and it then holds everywhere.
Someone enters a 40 percent discount. What happens next does not depend on where the number comes in.
Example values. You decide which limit applies in your company. I write it down once.
Here it is, explained line by line. The limit is written once in code, and all three doors read it from there.
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 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);}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 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);});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
04
One feature, one system, one owner.
2–12 weeks, Fixed price after technical review
05
Turn a service into a digital experience.
6–12+ weeks, Build and run, after discovery
Describe the case to me in three sentences. I reply myself, and the call takes 15 minutes.
Or directly: info@coderconda.com
Before that: three sentences, two working days to a reply, a 15-minute call. How it starts