Case study
urzadzeniamatter.pl
An independent Matter device catalogue built for the Polish market
- Role
- product concept, data model, architecture, implementation, editorial. Solo build, executed with an AI agent under tight editorial and engineering control.
- Stack
- Python (static site generator), JavaScript (Cloudflare Worker), YAML as the database, Cloudflare Workers Static Assets.
Role: product concept, data model, architecture, implementation, editorial. Solo build, executed with an AI agent under tight editorial and engineering control. Stack: Python (static site generator), JavaScript (Cloudflare Worker), YAML as the database, Cloudflare Workers Static Assets.
The problem
Matter was meant to unify the smart home. In practice it moved the problem somewhere else. A buyer sees the Matter logo on the box and still cannot answer the three questions that decide whether the device will work in their home:
- Does it need the manufacturer’s own hub? Hardware advertised as “Matter” is often useless without a bridge costing as much as the device itself. Neither the shop listing nor the certification registry says so.
- What actually works in each ecosystem? Apple Home, Google Home, Alexa, SmartThings and Home Assistant support the same device to different depths. Manufacturers publish a row of logos, not a list of functions.
- Will it physically fit? A relay module in a 60 mm back box, a smart plug that blocks the neighbouring socket in a double frame, a schuko plug that fits a Polish earthed socket without actually connecting earth. Datasheets stay silent, because they are written for all of Europe at once.
No Polish-language service answered any of this. English-language catalogues answer the first two partially and know nothing about Polish retail or Polish domestic wiring.
The finding that set the direction
The first measurement decided the shape of the whole project. I tested whether a catalogue could be built from the CSA Distributed Compliance Ledger, the official certification registry. Result: 58% of records carry indistinguishable names such as “WiFi Smart Plug”. The registry cannot be the backbone, because it does not separate products that a buyer sees on the shelf as different things.
A second measurement rescued the commercial pipeline. Matching retail offers to records by
name fails for the same reason, but the manufacturer’s partNumber rescues 56% of records
with useless names. Hence the matching key chain: EAN first, then partNumber, and only
then manufacturer plus model.
The strategic conclusion: the advantage is not record count. It is the ecosystem compatibility matrix and the Polish-market layer, precisely the fields that cannot be pulled from any feed. That is curation work, not an import job.
Architecture
A deliberate minimalism. The project ships with one production dependency (wrangler).
No CMS, no database, no frontend framework.
| Layer | Choice | Reason |
|---|---|---|
| Source of truth | YAML files in the repository, one per device | A data change is a commit: it has an author, a date and an undo. A database gives none of that for free |
| Generator | 3,100 lines of Python, merging and rendering | Deterministic build, no client-side code beyond the catalogue table filters |
| Runtime | Cloudflare Worker, 350 lines | Affiliate /go/ redirects, 301s after a slug change, the 404 page, the submission endpoint |
| Hosting | Workers Static Assets | Pages are served before the Worker runs, so the script only executes on an affiliate click |
The result: 517 static pages, including 467 device pages, generated from 542 records and 465 curated offers across 30 manufacturers and 38 categories.
Record identity
Every device gets a surrogate id (u-0001), assigned once by a human and never reused.
The registry’s VID-PID pair is deliberately not the key: it breaks on white-label
products, regional variants and hardware revisions. Ids come from an append-only register,
because a maximum computed from the files on disk drops the moment a record is deleted,
and saved links and affiliate URLs depend on that number staying stable.
Quality enforced by the build
A commerce catalogue fails quietly. A feed changes format, half the offers vanish, the site still builds, and for a week it serves empty pages. So the quality gates are part of the build rather than a procedure someone has to remember.
- Schema validator (1,200 lines) with three severities: error, warning and incompleteness. Only an error stops the build. Incompleteness is a normal state, because a record under curation is by definition not complete.
- Fixtures, not mocks. Validator tests run against real YAML files each broken in one specific way. A new rule without a fixture that violates it does not ship.
- Merge circuit breaker. A catalogue snapshot halts the build when more than 20% of previously public models disappear, lose all offers, or lose their lowest price.
- Publication gate. The generator refuses to emit a device page without a name, a manufacturer, a category and at least one offer. An unfinished record cannot reach production by accident.
- Closed by default. The generator builds a
noindexversion pointing its canonical at the staging host. Publishing requires an explicit flag, so a forgotten flag hides the catalogue instead of publishing it. - Deploy verification reads the pages, not the manifest. A pre-deploy script inspects the generated HTML, because a file declaring the build mode can drift from what was actually produced. HTML headers cannot.
Together: 156 automated data tests plus a runtime test suite, all behind a single
pre-commit command, and no external test runner. Node’s built-in node:test and plain
Python do the job.
Legal constraints written into the product
The site monetises through affiliate links, which makes compliance a functional requirement rather than a paragraph in the terms:
- Offers are sorted by price ascending, always. Ordering by commission is paid placement, prohibited without disclosure under EU consumer law. The rule lives in the generator, not in good intentions.
- Trademark clearance. I ran a TMView search across EUIPO and the Polish patent office: 862 records for “matter”, none owned by the Connectivity Standards Alliance, with a working control test (ZIGBEE and DOTDOT do appear as CSA word marks). That settled the domain choice. The separate prohibition on using the Matter logo still applies and is respected.
- GDPR and operating entity. A UK company as operator, an Article 27 EU representative appointed for the day analytics goes live, consent captured before any measurement script loads.
- Content Security Policy locked down to
default-src 'none'. The catalogue filters sit in a separate file specifically so the policy can do withoutunsafe-inline.
The configurator: a rules engine, not a questionnaire
The most interesting product decision. The obvious approach is a wizard that asks for floor area and filters the catalogue. The data said floor area barely affects device selection at all: the same bulb suits a studio flat and a house. Five variables actually decide, and all five live in record fields I was curating anyway.
So I inverted the build order: conflict engine first, then an interactive system diagram, and only then the questionnaire. Each rule reads a specific field and explains why a given combination will not work: no Thread border router in the setup, a device that speaks Matter or Zigbee but never both, a module that needs a neutral wire absent from older Polish two-way lighting circuits. A wizard built from the questionnaire is a prettier catalogue filter. A wizard built from the rules answers the question nobody else in this market answers: will the things in my basket actually work together.
How AI was used
The code was written in partnership with an agent (Claude Code), but not by asking it to build a website. Three practices decided the outcome:
Documents before code. The repository holds thirty decision documents, roughly 83,000 words: analyses, measurements, audits of third-party research, and rulings with a date and a rationale. Changing a rule starts by changing the document, never the validator. The reverse order produces a tool that enforces decisions nobody actually made. Those documents double as the agent’s context: the model is handed the reasoning instead of guessing intent from code.
Tests as the transmission belt. An agent writes quickly and confidently, including when it is wrong. Fixtures built from real data plus a single quality gate turn that speed into an advantage, because a mistake surfaces in a minute rather than after deployment.
No AI at runtime. The model helped build the generator, the validator and the rules engine. Production makes no model calls at all: pages are static and decisions are deterministic. A catalogue that invents a back-box depth is worse than no catalogue.
Third-party research treated as evidence, not input. External market reports entered the repository as material to verify, not as a basis for decisions. A dedicated document records which findings survived verification and which overrode earlier plans. Three of them changed the direction of the project.
Outcome
A live service at urzadzeniamatter.pl: the catalogue, category pages, device pages,
a side-by-side comparison view, an eleven-entry glossary explained at the point of use,
a device submission form, and the system configurator.
The numbers: 467 device pages, 465 offers, 30 manufacturers, 38 categories, 218 commits, 156 data tests, one production dependency, zero databases.
What the project demonstrates: taking a product from market measurement through data modelling and regulatory constraints to a working deployment, at the pace an AI agent makes possible, with the rigour that keeps that pace from costing quality.