Skip to content
megapromotingLet's talk

Expertise · Maintenance

Maintenance means knowing that the form delivers today, not that the server returns 200.

Monitoring that checks the full path of a request to a person, updates with a gate before production and an acceptance check run after each publication. All three run on this site and can be opened from outside.

Already builtThree in-house implementations, all in this site's repository and all verifiable today: `src/app/api/health/contact/route.ts` (the delivery probe, returns 200 on live right now), `src/lib/lead-store.ts` (the append-only log with retention applied on write) and `scripts/verify-redesign.ts` (the acceptance check run after publication). We wrote them because on 06.09.2026 the proprietary form failed silently: the bot token was revoked, the endpoint returned 500, and the requests disappeared without a trace. This is not a sales story — it is the commit that produced the files above.

“The site works” is a statement about the homepage. A visitor who filled in the form and received an error was not stopped by a broken page, but by a delivery channel that expired quietly. The difference between the two is everything that serious maintenance means: we do not track whether the server responds, but whether a request from one person reaches another person.

On 6 September 2026 exactly that happened on this site. The bot token that carried requests from the form to the team was revoked; the Telegram interface responded `401 Unauthorized`, our route returned 500, and the visitor saw “the message could not be sent”. The request was written nowhere. In the process error log there were three real failures in the approximately seven hours since the previous publication. Nobody was watching.

What came out of that are three pieces we now mount in every project we maintain. An append-only log written *before* the delivery attempt, so a broken channel degrades into “we need to look in the file” instead of “the request never existed”. A health probe that answers a single request if a lead can reach a person right now. And an acceptance check that runs after every publication and fails if a canonical address has disappeared, a question anchor is missing, or addresses that cannot be opened have appeared in the site map.

The rest is boring and verifiable discipline: updates with an audit gate before touching production, automatic restart with a memory threshold and a limit for unstable restarts, retention enforced by code, not declared in policy, and IP addresses truncated to the network prefix before being written anywhere.

What it covers

The work, by component

Probe that checks delivery, not availability

`GET /api/health/contact` returns 200 if a lead can reach a person now and 503 if not. It checks two things separately: that the notification channel token is still valid (a real request to the provider, with an 8-second timeout) and that the request log is writable. The response is made up only of boolean values — never the token, the channel identifier or the bot name. The result is kept in memory for 60 seconds, so an external probe pressed often does not become traffic itself. When the provider is unreachable, the field becomes `null`, not `false`: “I do not know” and “invalid” are different states.

Log written before delivery, not after

Each request receives an identifier and is written to an append-only log, one JSON line per event, *before* notification is attempted. The second line, with the same identifier, says what actually happened: `delivered` or `failed`, with the reason truncated to 300 characters. The directory is created with `0700` permissions, the files with `0600`, and the path is deliberately placed outside the versioned directory, so the history survives a publication.

Acceptance check run after publication

A verification script opens each product page, in groups of three, and fails if the 200 code, the questions anchor, the example anchor or the canonical address is missing. It then checks the site map — that it does not contain language variants that cannot be opened and that it contains every product — and `robots.txt`, so that it does not block the resources needed for rendering. It also fails if content from an old client reappears on the page. It is a list of things that have already broken once.

Updates with a gate, not with hope

The deployment script refuses to start if the server has less than 500 MB free memory, runs `npm audit --audit-level=high` and stops at high-level vulnerabilities if you do not confirm explicitly, then builds from clean — `.next` and `node_modules` deleted, installation from the lock file. If the process does not appear `online` after startup, the script displays the last 50 log lines and exits with an error, instead of reporting success.

Restart with thresholds, not at random

The process restarts automatically above 500 MB memory, with a 4-second delay between attempts, exponential backoff and a stop after 10 unstable restarts — so that a crash loop becomes visible instead of consuming the server in silence. Grace period on shutdown: 5 seconds, then forced termination. Logs have date and time zone, in a single stream.

Duplicates handled, not counted twice

The same person, the same message, twice — a double click, a page reload — used to produce two identical notifications for a single request. Now the `sha256` fingerprint of the address + message pair is kept in memory for 10 minutes; the second submission receives the same request identifier and the `duplicate` tag, and the notification is not repeated. Only duplicates of a successful delivery are suppressed; a failed one is allowed through again.

Error codes that say what broke

400 for invalid data, 405 for the wrong method, 500 for a broken request body, 502 when the delivery channel responded badly, 503 when credentials are missing. The difference matters at 3 a.m.: 502 means “the provider”, 503 means “our configuration”. The visitor is told distinctly “we received the request, but could not notify” — not a false success.

Retention enforced by code, not promised in policy

The published privacy note says that form requests are kept for 24 months. The code applies exactly the same number: `LEAD_RETENTION_DAYS` defaults to 730, and files older than the threshold are deleted on each write, without a scheduler that can be forgotten. The IP address is truncated to the network prefix — `/24` for IPv4, `/48` for IPv6 — and the last hop is read from the header, not the first, because the first is sent by the client.

We find what nobody complained about either

The same code pass uncovered two things that no user had reported: the limit of 10 requests per minute could be bypassed entirely, because the first element was read from the forwarded address header — the one controlled by the client — and a phone-call initiation route was open anonymously, at our expense and from our number, although the component that used it was no longer mounted anywhere. Both fixed and verified in production.

What it looks like

The path, step by step.

01

The inventory of the paths a request takes to reach a person

The first delivery is not a tool, it is a list: what a request passes through from the button press to someone reading it, what breaks at each step and what should happen when it breaks. On this site the list had three links and one was invisible.

02

The probe and the log, mounted before anything else

We ship a health address that checks the full path, not the process, and the log that writes before delivery. From here on, a failure is a question with an answer, not a dig through logs. The address can be queried from any external monitoring service, because it returns nothing sensitive.

03

The acceptance check, written from real defects

Every thing that has ever broken once goes into the verification script run after release. We do not write tests for hypothetical cases; we write them for the ones that have already cost us. We deliver the script, not just its result — you can run it too.

04

The update cadence and the gate before production

We establish what updates automatically, what goes through human verification, and what is not touched without an announced window. The gate includes the security audit of dependencies and the server resource check, both run before touching production.

05

Handover, with the list of gaps

At the end we hand over the publishing procedure, the rollback procedure, the health endpoints, and the written list of what is not covered. On this site, for example, the supplier request timeout branch is implemented and falls under the same handling as the network error, but the abort itself was not triggered in test — that is written in the execution log, not in an internal note.

1The verification probedelivery by aom2jurnalul scrisbefore the attempt3verificarea derolled acceptance afterfiecare publicareThree parts, all in the store of this site.
The path, in 3 steps

The data

What we touch, where it lives, and how long it stays

The questions anyone with a data protection officer would ask — asked here before they do.

Request log
Name, email address, phone, company, selected service, message, the page from which it was sent, the host of the referring page (host only, not the full address) and the visitor’s network prefix. JSON files by day, on the own server, outside the version directory. Term: 24 months, applied on write.
Process and server logs
Standard output and process errors, with date and time zone, plus the web server logs. This is where a silent failure is visible: the three delivery failures from the reference incident were in the error log, not in any alert. Rotation and term are set for each server; they are technical data, not account content.
What never leaves the server
Tokens, channel identifiers and supplier keys. The health probe responds exclusively with boolean values, precisely so it can be called by an external tool without disclosing anything. The same rule applies in notifications: the message contains the request identifier and the page, not credentials.
Traffic statistics
Traffic measurement goes through the analytics tool configured on the project and is activated after consent. The actual retention setting in the analytics account is a value we read from the account, not one we assume — the processing register for this site marks it explicitly as an item to clarify, not as an established fact.
Processing register
Every type of data touched by the site has an entry with purpose, basis, categories and term, in a versioned document alongside the code. When the code changes a term, the document changes in the same commit — otherwise the policy and the programme say different things, and the one that is wrong is usually the document.

A case

A form that delivered 500 instead of leads, seven hours

The situation

A presentation site with a contact form, recently released. All pages respond 200, the dashboard is green, nobody reports anything. The only channel through which a request reached the team was a notification in a messaging app.

What we built

The notification bot token had been revoked; the supplier interface responded `401 Unauthorized`. The form route returned 500 and wrote nothing. The first fix was not the token, but the order of operations: the request is now written to an append-only log, with its own identifier, *before* delivery is attempted, and the delivery result is added as a second line. On top of that were mounted a public health probe that checks the token and write access, distinct error codes for “the supplier responded badly” and “we are missing credentials”, a 10 second timeout on delivery, and duplicate suppression over a 10 minute window. The same code pass also removed a request limit that could be bypassed, and a telephone call route left open anonymously.

What came out

The probe now responds 200 with the valid token and a writable log; it can be queried from any external monitoring service without disclosing anything. Production tests covered every response code — 400, 405, 500, 502, 503 — and two identical submissions returned the same request identifier, the second marked as a duplicate, with two lines in the log, not four. A future failure of the notification channel no longer erases the request: it remains in the log, with the reason written down.

What the case does not say

The probe says delivery is possible now, not that anyone reads the notifications. Who looks at them and how quickly is a team decision, not a function of the code. And the supplier request timeout branch, although implemented, was not triggered in test — it falls under the same handling as the network error, which was tested; we note it as unexercised, not as verified.

Questions

What people ask us before they call

What exactly do you monitor?

The path of a request to a person, not server availability. `GET /api/health/contact` checks two things in a single request: that the notification channel token is still valid — through a real call to the provider, with an 8-second timeout — and that the request log can be written. It returns 200 when both are true and 503 when they are not. You can call it right now on this site: it is public, precisely because it returns only logical values.

Why would a form fail without anyone noticing?

Because the visible part keeps working. The page loads, the button responds, the server returns 200 on all pages — only the final link breaks, and it has no interface. On this site the notification bot token was revoked: the provider responded `401 Unauthorized`, the route returned 500, and the request was not written anywhere. Three real failures in about seven hours, visible only in the process error log. That is why the log is now written before delivery: even if the notification fails, the request exists.

What happens if the notification fails after you have fixed it?

The request is already written in the log with its own identifier, and the second line in the log says `failed` and the reason. The visitor gets a distinct reply — “we received the request, but could not notify” — not a false success. The response code distinguishes the cause: 502 means the provider responded badly, 503 that we are missing credentials. At 3 a.m., the difference between the two decides whether you call someone or not.

Do you update dependencies automatically?

Not without a gate. Publishing runs `npm audit` at `high` level and stops on vulnerabilities at this level if continuation is not explicitly confirmed; it first checks the server’s available memory too, with a 500 MB threshold, because a build started on a cramped server leaves the application stopped. The build is done from scratch: the build directory and dependencies are deleted, installation is done from the lock file. What updates automatically and what goes through human review is decided per project, not by default.

How do you know a publication has not broken something else?

Through a verification script run after publication, which opens each product page and fails if the 200 code, the questions anchor, the example anchor or the canonical address is missing. It then checks the sitemap — that it contains every product and does not contain language variants that cannot be opened — and `robots.txt`, so it does not block rendering resources. Each check in the list corresponds to something that has already broken once. The script is delivered with the project.

What do you do when the application freezes or consumes memory?

The process is restarted automatically above the 500 MB threshold, with a 4-second delay between attempts and exponential backoff, but it stops after 10 unstable restarts in a short interval. That is important: a crash loop that restarts forever looks healthy in a dashboard and quietly consumes the server. We prefer the process to remain stopped and visible.

How long do you keep form data and who can read it?

24 months, enforced by code, not just stated: the threshold is a variable with the default value of 730 days, and older files are deleted on every new write, without a scheduler that can be forgotten. The directory has `0700` permissions, the files `0600`, and the path is kept outside the version directory, so the history survives publication. The IP address is not kept in full: it is truncated to `/24` for IPv4 and `/48` for IPv6, reading the last hop from the header, not the first — the first is sent by the client and means nothing.

Do you also find issues we did not report?

It happens, and usually those are the expensive ones. The same pass through the code that fixed the form exposed two things nobody had reported: the request limit could be bypassed completely, because the first element from the forwarded address header was read — exactly the one sent by the client; and a route that initiated phone calls was open anonymously, on our cost, although the component that used it had been removed. Both were fixed and verified in production. What we cannot promise is that we find everything; what we can promise is that we also report what you did not ask for.

What is not covered by maintenance?

It is not a 24/7 security monitoring service and it is not an operations centre. We do not guarantee an uptime percentage without a measurement to support it — and, to be clear, at this moment we do not publish such a figure for our own site. We do not take responsibility for a third-party platform to which we do not have access. And we do not treat a page that returns 200 as proof that everything works: that was exactly the problem from which everything written above started.

What the statements above rest on (13 sources)
  1. The delivery probe responds 200 in production: `{"ok":true,"telegram":{"configured":true,"credentialsValid":true},"leadJournal":{"writable":true}}`https://www.megapromoting.com/api/health/contact · 2026-09-06
  2. Active security headers in production: HSTS `max-age=63072000; includeSubDomains; preload`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin`, `Permissions-Policy` with `microphone=(self)`https://www.megapromoting.com/servicii · 2026-09-06

11 of them are code and files from our repositories. We don't publish their name or line: together, on a single page, they would describe too precisely how systems that aren't only ours are built. We go through them with you, in the repository, on request — verification stays possible, it just happens in a conversation.

What would you want to work better?

Tell us about your process. Together we decide what is worth building, what we can connect, and how we check the result.

Let's talk