Fifteen paper calendars
Krysiak Schoonmaakbedrijf is a cleaning company just outside Haarlem, run by Aneta Krysiak. Fifteen cleaners, regular private clients and offices. Every cleaner had their own paper calendar, in which the owner wrote out their hours and their pay.
This is another project of ours built for a foreign market, and built entirely for a Dutch audience: a site in Dutch only, full local SEO for Haarlem and the neighbouring municipalities, structured data aimed at Dutch search results, and a multilingual system for a team that is still learning the language.
At the end of the month all of it had to be added up by hand. Every day meant a separate phone call with each cleaner: agreeing the schedule, sending it out, settling the work. Up to three hours a day on something that is not cleaning and does not earn anything. On top of that the notebooks had to travel with the owner everywhere, holidays included, because at any moment a client or a cleaner might call asking about a date or a payment.
A bottleneck that never shows up in a spreadsheet
Six months earlier we had set up a Google Business Profile for the client. Cost: 500 zloty, around 117 euro. After six weeks the daily calls about cleaning houses and flats started, and the investment paid for itself within three months.
And that is when the problem appeared, one we only learned about in September 2026: the client could not take on any more jobs. Not for lack of hands, but because every additional job meant another entry in a notebook, another phone call and another line to add up on a sheet of paper. The marketing was working and the company still could not grow, because the admin was the ceiling.
15 paper calendars, one full set, kept by the owner
Up to 3 hours a day on scheduling, calls and counting
Hours and pay added up by hand at month end
Cash collected from clients with no record
Notebooks travel with the owner everywhere, holidays included
No website, clients only from the profile listing and referrals
One online schedule, the same one for the owner and every cleaner
A visit entered once repeats every week on its own
Hours, pay and balance calculated by the system as it goes
Cash collected from a client deducted from wages automatically
Viewable from a phone, anywhere
A Dutch-language site with local SEO for Haarlem and around
The recovered time is not just convenience. It is the ability to take on more clients and hire more people without the admin outgrowing the company. Every new cleaner today is one entry in the system, not another notebook to maintain.
Stage 1: the schoonhaarlem.nl website
The phone call as the only conversion
The owner answers the phone personally and closes every job that way. The entire layout was subordinated to one action: make the call. The number sits in the header of every page, in the hero tile, in the footer and in the service sections. A quote form exists, but as a second path for people who would rather write.
- The phone number visible without scrolling on every page
- Hero tiles with specifics instead of slogans: headcount, service area, payment methods
- 26 pages in Dutch only, written for a Dutch reader
- A quote form handled by a PHP script on the same hosting
Full local SEO for the Dutch market
The entire search layer was built for the Netherlands, not translated from Polish. Copy written in Dutch around the phrases people in Haarlem actually use, a separate page for each municipality with local context, LocalBusiness structured data with a service area and radius, NAP consistent with the company's Dutch address and BTW number, and the Google Business Profile as the foundation underneath all of it.
- Copy and metadata in Dutch only, written for a local reader
- A separate local page for Haarlem, Bloemendaal and Heemstede
- JSON-LD with the service area: central Haarlem and a 10 km radius
- Hyphenation following Dutch rules, so compounds like bedrijfsaansprakelijkheidsverzekering do not blow out the layout on a phone
- The Google Business Profile as the first source of calls, the site as its extension
Local SEO narrowed to the real service area
The first version covered seven towns. After a conversation with the client the area was narrowed to three, Haarlem, Bloemendaal and Heemstede, because the cleaners travel by public transport and bicycle and simply cannot reach anywhere further. The removed local pages got 301 redirects and the structured data was rewritten to a 10 km radius around central Haarlem.
Window cleaning went the same way: withdrawn at the client's request, so that the company would not be associated with washing office facades. Cleaning windows from the inside stayed part of domestic cleaning.
The site shrank from 32 pages to 26 and that was a good change. Every page removed was a query the company could not serve, and a phone call that would have cost time without revenue.
One source of content
All the company data, the phone number, address, opening hours, service descriptions, local copy, price list and FAQ, sits in a single directory of data files. Changing the number in one place propagates to every call to action, the footer, the JSON-LD structured data and the sitemap. There is no way for an old number to be left forgotten in the code of some page.
Stage 2: the system that replaced the notebooks
The system came out of an hour-long conversation in which the client described exactly what they do in the calendar. Nothing was added "just in case" - the system does what the paper did, it just does the arithmetic itself and lives in every cleaner's phone.
A week laid out like the open notebooks
A grid of cleaners against days, exactly the way the client used to spread the calendars out on the table. Empty cells with a plus sign are free slots, and tapping one drops a visit straight into it. Learning to use it took a quarter of an hour, because the layout mirrors what was already in the owner's head
Copying the previous week
A cleaning company's schedule is mostly repetitive. One button rewrites the whole previous week, without the cancelled visits, with cash zeroed out and current rates applied. All that is left is correcting the differences. That alone eats most of the old three hours a day
Recurring visits with clash detection
A regular client is entered once, repeating weekly. If one of the copies overlaps another visit for that cleaner, the system stops the save and shows exactly what it clashes with. Booking someone into two places at once stopped being possible
Client holidays, cleaner time off
One date range instead of cancelling a dozen visits one by one. Deleting the absence restores exactly the visits it cancelled, so the operation is fully reversible
Settlement instead of a sheet of paper
Earnings are hours times rate, and the payout is earnings minus cash collected from clients minus what has already been paid. The balance runs from the start of the working relationship, so an underpayment from a month ago does not vanish. Month end stopped being a separate task, because the summary is ready at all times
The schedule in an iPhone calendar
A calendar subscription on a tokenised URL: the owner sees every visit, a cleaner sees only their own. A change in the system reaches the phone by itself. That is the end of the daily "where am I going today" calls, the most expensive item in the owner's old working day
Four languages and a test that enforces them
The team is international, Polish and Ukrainian, and some of them speak little Dutch. The system speaks Polish, Dutch, English and Ukrainian, and each person picks their language at login. Day and month names inflect, the date order changes too, so "maandag 7 september" and "понеділок, 7 вересня" come out correctly rather than as fragments glued onto an English template.
A test keeps the translations honest: it scans the code and fails when a key is missing from any of the dictionaries, when a dead entry is left behind, or when the placeholders in a translation do not match the original. Deployment stops on a red test, so untranslated text has no way of reaching production.
Deliberately without a framework
The client's shared hosting gives you PHP with directory restrictions and no background processes at all. Rather than fight that constraint, the system was written in plain PHP with PDO, without a single production dependency. The server renders the HTML, the JavaScript is 130 lines of convenience, and the system works with scripting disabled too. There is no build step, nothing to patch for vulnerabilities, and deployment is rsync plus migrations.
The deployment script copies the code into a working directory next to the production one, installs the development dependencies and runs the full set of 50 tests there. Only a green result swaps the production code over. A red test aborts the deployment and the working version stays untouched.
Security
The system holds clients' personal data and cleaners' earnings, so it was treated as a production system rather than an internal notepad.
- bcrypt passwords, constant-time verification even for a login that does not exist
- Login attempt limits per login and per IP address, with a 15 minute lockout
- A CSRF token required on every write request, the session in a
__Host-prefixed cookie - Every query through prepared statements, every value escaped in the template
- HSTS, CSP, X-Frame-Options and Referrer-Policy headers, the whole subdomain set to
noindex - Application code out of HTTP reach, a request for the config file returns 403
- Separated roles: a cleaner only ever receives data tied to their own account
Technology stack
Tailwind CSS 4
Alpine.js
PHP 8.3
MariaDB
PDO
PHPUnit
Schema.org JSON-LD
Google Tag Manager
GA4 with Consent Mode
iCalendar (ICS)
Google Business Profile
Results
What we took from it
This company did not have a problem finding clients - the Google Business Profile brought in as many as it needed and paid for itself in three months. It had a problem serving what was already coming in. Fifteen notebooks and a sheet of paper for the totals was a real ceiling, and the company had hit it.
For us it is also another project run entirely remotely for a client abroad: from keyword research in a foreign language, through copy written for a Dutch reader, to deployment and technical support on local hosting.
The rest of the decisions came down to subtraction, not addition. Four towns removed from the SEO, because the team cannot reach them. A service withdrawn, because it blurred how clients saw the company. A system with no framework, because plain PHP will still run in five years without an update.
A cleaning company of fifteen people does not need an ERP system costing tens of thousands. It needs exactly what it was already doing on paper, only with the arithmetic done for it and the whole thing in every cleaner's phone. From the first conversation to a live site and a working system: one month.