Skip to content
megapromotingLet's talk

Expertise · Custom software

A system built for the way your organisation works, not for the general case.

We build systems from scratch when no product on the market fits: platforms with multiple applications and a shared database, connectors to systems that do not have an API, pipelines that read documents and money movements, and programmes whose output is not a screen, but a manufacturing dossier. At the end we hand over the repository, the commissioning document and the access credentials.

Already builtAm ales patru sisteme proprii din discipline diferite, tocmai ca să nu arate ca patru variante ale aceluiași site, și am rulat testele fiecăruia azi. Un monorepo cu 3 aplicații și 12 pachete, 486 de fișiere TypeScript și 68 de fișiere de test, 151 de comituri, arbore de lucru curat. Un sistem de interogare a două portaluri B2B fără API public: 38 de teste trecute în 0,52 s, pe răspunsuri reale salvate ca fixturi. O conductă care citește notificări bancare din e-mail și PDF și le scrie în Postgres cu deduplicare prin amprentă. Și un generator de documentație de inginerie, în Python, cu 44 de teste trecute în 0,50 s. Cifrele sunt din rulările mele de pe 6 septembrie 2026, nu din README-uri.

“Custom” means the system is written according to the way your people already work, not the other way round. It has a cost that is fair to state up front: someone has to maintain it, and that someone is us or your team. That is why the first question we ask is not what you want to build, but whether there is already a product that does 80% of the job. If there is, we say so, even if that means you do not give us the work. What remains after that question — the part that is not bought — is exactly what we build well.

The scale is seen more clearly from four different systems than from a list of technologies. The first is a platform for a performing arts institution: a monorepo with three applications (public site, administrative cabinet, API) and twelve shared packages — tickets, commerce, content, notifications, refunds, security. The second queries, on demand, the B2B portals of tour operators that publish no API: programmatic authentication, return to login when the session expires, and an analyser tested on real responses captured in files. The third reads bank notifications from email and PDF statements and places them in Postgres. The fourth has no screen at all: it is the programme that generates the model, the bill of materials and the drawings of an industrial machine.

What keeps a system like this upright is not the stack, but the rules written before the first screen. In the platform for the performance institution, the implementation contract fixes in text things that would otherwise be negotiated at every meeting: money is kept in whole minor units, with the currency alongside; the availability of a seat is given only by a durable reservation in the database, never from the cache; critical orders have idempotency keys; P0 and P1 paths fail closed, not open; card data is never stored. These rules are written at the start because, if written at the end, they would mean rewriting the system.

At the end, three things are handed over, not one: the repository with all its history, the document that says how to bring it up on a blank server, and the accesses. Under our project directory there are 150 git repositories, 103 README files and 19 deployment or handover documents — counted today, not estimated. We write the ownership rule into the contract before start and it is simple: the code written especially for you is yours, third-party libraries remain under their licence, and our reusable components and our products are licensed, not assigned. If part of the work is better solved with one of our products, we say so exactly like that, so you know from the start what you are buying and what you receive.

What it covers

The work, by component

We write the domain rules before the first screen

An implementation contract, in text, that fixes the vocabulary and invariants: what a reserved seat means, what an collected payment means, what fails closed when a service does not respond. In the platform for the performance institution the rules are explicit — money in whole minor units plus currency, availability only from durable reservations in the database, idempotency keys on critical orders, cache never a source of truth for stock, card data never stored. These are rules checked in code, not principles.

We build the core on tests that run without the live system

The real responses of external systems are saved as fixtures and the parser is tested against them, not against the portal that may be down exactly on the day you are working. For the flight portal query system, the suite runs in 0.52 seconds and passes in full; the tests that actually touch the portals are marked separately and are requested explicitly. The same separation exists in all four systems: what can be checked on the bench is checked on the bench.

We hand over the repository, deployment and accesses

Not a zip file. The repository with commit history, a document describing how the system is brought up on a blank machine — database, environment variables, system service, web server in front — and the accesses that make it yours. Under our project directory there are today 150 git repositories, 103 README files and 19 DEPLOY or HANDOVER documents; this form of handover is the habit, not the exception.

When the other system has no API, we say what risk you take

The B2B portals we query do not publish a programme interface, so authentication is done as a user, with session cookie and connection key, and is renewed automatically on expiry. The risk is written in the project README, not discovered later: programme authentication is a grey area in relation to the portal's terms of use, and for a heavy production volume the correct solution is to ask the operator for its official API. A client has the right to know that before signing, not after.

Documents are entered only once, even if we read them ten times

Each transaction extracted from a bank notification or from a PDF statement receives an external identifier calculated as a SHA-256 fingerprint over its fields, and insertion into Postgres is done with `ON CONFLICT (external_id) DO NOTHING`. The practical consequence: the mailbox can be re-read as many times as you want, and the balance does not double. Without this rule, any ingestion pipeline ends up producing duplicates, which is an accounting problem.

Classification with the model is done through tools, not free text

The model does not write a sentence that we then guess: it receives seven tools — customer payment, salary, tax, payment to creditor, operating expense, unknown — and must choose one, with a confidence score between 0 and 1. For approximate matching of counterparty names there is a separate reserve, based on vector similarity. 'Unknown' is a legitimate output, with a reason, not a hidden failure.

Sometimes the result is not a screen, but a folder

A proprietary Python system generates the three-dimensional model of an industrial machine, the bill of materials with release status for each position, the verification plan, the cable diagram and the PDF sheets — from a single command, so that nothing in the package can remain behind the model. It has 44 tests that pass in half a second and that check engineering rules, not just code: that the active field is exactly one cubic metre, that no position in the bill of materials is left without a verification line, that the machine never extrudes at rest.

Continuous measurement is a different discipline from on-demand querying

A proprietary system simultaneously captures several radio stations with `ffmpeg`, transcribes locally with an open-source model, then searches for adverts with a transparent score across groups of signals in Romanian and Russian, with a configurable threshold, and groups the same advert broadcast on different stations through a chromaprint-type audio fingerprint — because the transcriptions diverge, but the sound is identical. It has 81 tests that pass in 1.14 seconds. A system that runs unattended needs coverage counters, retries with task leasing, and a self-test, otherwise it goes quiet when it breaks.

We also say what we do not build

We do not build from scratch what can be solved with an existing product, ours or someone else’s, just because the work would be larger. We do not take over systems we cannot run locally, with test data, by the end of the first stage. And we do not start a system that depends on an external provider before we verify that provider’s public port — that check comes first, not last.

What it looks like

The path, step by step.

01

We define the scope and write the rules

A stage of reading systems and talking to the people who do the work today, concluded with a short document with the vocabulary, the invariants, and what closes. We deliver this document even if it does not get to the build — it is useful without us too. It also includes the list of external systems the work depends on and the check of each one’s public port, because that is where surprises come from.

02

We build the core, with its tests, before screens

The domain rules, data models, analyzers, calculations — plus the tests that run without live systems, on fixtures captured from real responses. We deliver the suite and its result, with the run command, so you can run it yourself. A core that cannot be tested without the production environment is a core we cannot fix quickly later.

03

We put the interface and integrations on top of the core

The administrative cabinet, public screens, entry points for other systems. This is where external providers are connected, each with its own adapter and a simulation variant, so the system can be run fully without real accounts. We also deliver the local run mode, with the database and services brought up from containers.

04

We put into operation and hand over

Installation on the agreed infrastructure, system service, web server in front, logs and their rotation, self-test. Then handover: repository, a commissioning document written for an empty machine, accesses, and a review of what remains to be done. What has not yet been started in the work is written as a list, not left unsaid.

IntrareVerificareDeciziePublicareNimic nu trece mai departe neverificat.ORDINEA E ARGUMENTUL
Trei pași și ordinea lor, care e jumătate din lucrare. Întâi regulile domeniului scrise în text — ce înseamnă un loc rezervat, cum se țin banii, ce cade închis când un serviciu tace. Apoi nucleul cu testele lui, care rulează pe răspunsuri reale salvate ca fixturi, fără sistemele vii. La final punerea în funcțiune și predarea: depozit, documentul pentru o mașină goală, accese. Săgeata înapoi de la pasul trei la pasul unu e reală: ce se descoperă la punerea în funcțiune schimbă regulile, nu se ascunde sub ele.

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.

Where it runs and who holds the key
The system runs on the infrastructure agreed in writing at the start: your server, a server managed by us, or a hosting provider chosen together. The four systems above run differently from one another — one as a system service behind a web server, one from containers, one as a scheduled process on a local machine, one only on demand, on the workstation. The choice is made from the data constraints, not from habit.
Credentials do not live in code and, where possible, not on disk either
Passwords and keys are read from environment variables, and the file containing them is restricted to the current user. In a connector to an external system, the session token is kept only in memory and is renewed on expiry or at the first refusal — the password and token are not written to any file. The rule is checked in review: a key that reaches the repository is an incident, not a miss.
Data that enters from documents
When the system reads emails or PDFs, it touches real business data: amounts, calendar dates, counterparty names, account numbers. It is stored in the beneficiary’s database, with its own identifier, which cannot be repeated, per record, and can be reconstructed from the source. What goes to an external model, if one is used, is the transaction description — not the whole document and not the attachment.
What is retained and for how long
The retention period is set by data type, not globally, and is written before go-live: business records according to the beneficiary's legal obligations, technical logs on a short window, intermediate files — audio captures, downloaded attachments — with automatic cleaning. A system with no deletion policy becomes, in six months, a greater risk than the problem it was meant to solve.
What remains with us after handover
After handover, our access to your systems exists only if there is a maintenance contract that requires it, and is withdrawn when that contract ends. Working copies on our workstations are deleted on request. What we keep in any case are the generic components we wrote that do not contain your data — and we declare those from the start, so there is no surprise at the end.

A case

A query system for two portals that have no API

The situation

A travel agency needed, on demand, seat availability and rates on charter flights from the B2B portals of two tour operators. The portals are designed for human eyes: you log in, search, read a table. There is no published programmatic interface, and the information was read manually, several times a day, by a person.

What we built

We wrote a client that authenticates programmatically and refreshes its own session when it expires, an analyser that turns responses into objects, and an identifier layer for airports, where the code is made up of city and port, and some calls require the two parts separately. On top of these: a command-line command that returns a full route with availability and price, a batch request mode with pauses between requests so the account does not get blocked, and two JSON entry points for the case where another platform wants to consume the result. The analyser is tested on real responses, saved as fixtures in the repository, and the tests that actually touch the portals are marked separately and do not run by default.

What came out

The suite passes in full: 38 checks in 0.52 seconds, without touching the portals. One request returns, in a single response, availability in the four states used by the portal and the fare with class and baggage, in the requested currency. The result can be consumed from the command line, as JSON, or through the two HTTP entry points.

What the case does not say

Programmatic authentication remains a grey area against the portals' terms of use, and that is written in the project's README, not discovered after delivery. For heavy production volume, our recommendation is explicit: the official API should be requested from the operators. The system makes targeted requests and pauses between them precisely so it does not become a mass extraction tool.

Questions

What people ask us before they call

Why is there no price on this page?

Because we could not write it honestly. The effort for a custom system is determined by three things we do not know before looking: how many external systems need to be touched and whether any of them has an API, how many business rules are already written somewhere and how many must be discovered from people, and who keeps the system alive after delivery. A number given before seeing the system is a guess with an invoice. What we can do quickly is the first stage — reading, delimiting, writing the rules — which is estimated properly and remains useful even if you stop there.

Who owns the code in the end?

The code written specifically for you is yours, including the repository and history. Third-party libraries remain under their own licences — we cannot assign them to you, because they are not ours. Our reusable components and our existing products are licensed for use, not transferred; if your work relies on one of them, we tell you that in the written offer, before the start, not at the last meeting.

What happens if we want to continue with someone else?

Handover must make that possible without us, otherwise it was not a handover. That is why the go-live document is written for an empty machine and assumes nothing from our side, and the tests remain in the repository so the next team knows what breaks when they change things. What we cannot promise is that a complex system is taken over without effort — we can promise only that nothing needed for it to be taken over is missing.

Can I see a system built by you, to judge the quality?

Partly, and it is fair to say where that stops. Systems built for clients are not ours to show, and internal ones contain real business data. What we can do in front of you, on screen, is different: we open the repository, show you the domain rules written in text, run the test suites — 38 in half a second on one, 81 in just over a second on another, 44 on the third — and read together the code that makes the statement you are questioning. This site is, in turn, our own system that can be inspected from the outside.

Our old system has no API. Can anything be done?

Usually yes, but with declared risk. The order is: first we ask whether the supplier has an official API that they simply have not documented publicly — this happens often. If they do not, it can be done through programmatic authentication, exactly like a user, with an automatically renewed session; we built such a system that queries two B2B portals. Then we state clearly that this is a grey area with respect to the supplier’s terms of use and that, for high volume, the durable solution is to ask for the official API. The decision remains yours, but an informed one.

Do you use artificial intelligence to write code?

Yes, and we do not hide that. What matters are the rules under which it is done: every piece of work is closed with tests that run, with type checking and a review of the differences before commit, and the limits are written in the repository — no production deployments from within the work, no changes in external accounts, vendor adapters only with a simulation variant. Code written quickly and unproven is more expensive than code written slowly. What sells this is speed on the tedious part, not the absence of verification.

What do you do when, halfway through, it turns out the initial idea was wrong?

We say so. In one of our own engineering projects, after evaluation, we arrived at a second architecture completely different for the same problem and wrote it as a documented alternative, with the gates that must be passed before any order, instead of continuing with the first because it had already been started. The cost of a change of direction halfway through is lower than that of a system delivered in the wrong form, and the difference is paid by the beneficiary in both cases.

How large can the work be?

At one end, a system with three applications and twelve shared packages in a single repository, 486 TypeScript files, 68 test files and 151 commits, with a relational database, ephemeral coordination separate from the source of truth and shared contracts between applications. At the other end, a system with a single process and twenty entry points, which is exactly as much as needed. Scope is not a promise about any size — it is the observation that we have worked at both ends.

Do you also provide maintenance after delivery?

Yes, but as a separate agreement, not as an implication. A custom system needs security updates, tracking of changes at external vendors and someone looking at logs. If you prefer to do this with your team, the handover is built so that it can be. If you prefer us to do it, it is written what it covers and what it does not — including what “urgent” means, because without a definition that word means nothing.

What the statements above rest on (15 sources)

15 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