Service Schedules: The Groundwork Is in the Schema
There is a table in this database with columns for last service and next service. Nothing writes them, nothing reads them, and no screen shows them. That is the sixth thing of its kind found here in a month, and the pattern is more interesting than any of the six.
The most reliable way to be misled about a system is to search it for a word and find one. A column named for the thing you need is not the thing you need, and the difference between those two states is invisible from every angle except one: reading the code that writes to it.
This product has a table for hardware assets. It carries a last-maintenance date, a next-maintenance date, a warranty expiry, an assignee and a location. It has a migration. It has a model class with all of that declared and cast correctly.
It has no controller, no route, no view, no reminder and no reader. Nothing has ever put a value in it and nothing would notice if something did.
Why this is worse than the field not existing
If the column were absent, every check would find it absent. A developer greps and finds nothing. An auditor asks and is told no. A copywriter cannot describe it because there is nothing to describe.
Because it is present, every one of those checks passes. The grep hits. The schema shows the field. And the person writing the product page in good faith describes a service-schedule capability that has never once run.
An inert field survives every audit that greps for a name. That is not a side effect of the problem — it is the problem.
Six of them, in one month
| What it looks like | What it did when found | How it was found | Today |
|---|---|---|---|
| A per-item expiry policy on stock | Nothing reads it. Expiry ordering is unconditional regardless. | Auditing a post that claimed both a working policy and the opposite | Wired 1 October 2026: earliest expiry or earliest received first, per item |
| A frequency on a stock-count plan | Stored, validated, defaulted — and no scheduled job anywhere creates a count from it. | Re-verifying an entry that said the field was missing | Wired 1 October 2026: a daily job opens the count when it is due |
| Value thresholds on the approval engine | Stored. Nothing consumes them; approval is by permission, not by amount. | Auditing approval claims across the corpus | Still inert |
| A supplier performance model | Four score columns, workspace and vendor relations, one unused import. No writer, no reader, no screen. | Reading the procurement module line by line | Wired 1 October 2026: a scorecard stored nightly per supplier |
| A capacity on a storage location | Settable on three screens. No putaway check, no warning, no utilisation view. No unit either. | A module audit for blog copy | Wired 1 October 2026: counted in stock units, with a percentage full and an alert |
| A hardware asset table with service dates | Migration and model only. Not referenced anywhere in routing or HTTP. | Looking for where a service schedule could live | Still inert |
Five of the six are columns. One is an entire table. Four were wired on 1 October 2026 and two are still waiting. All six were found by reading code with a specific question in mind, and not one of them was found by using the product — because using the product cannot find them. There is nothing to see.
The test that actually works
The check is not "does this field exist". It is "what writes it, and what reads it" — two greps, both of which have to return something, and one of which has to be a code path a user can reach.
A writer exists and a reader exists
A feature
Ask what happens when the value is wrong, and whether anything validates it. This is the normal conversation.
A writer exists, no reader
A record
Fine, if that is what it is for. An audit trail is exactly this. Say so rather than implying it drives something.
A reader exists, no writer
A trap
Something displays or branches on a value that is always null. This is where empty filters and permanently-false conditions come from.
Neither
Vocabulary
The word is in the schema and the behaviour is not in the product. It will be described as built by the next person who greps for it.
What we did about it
Two of the six were closed by wiring the field to something. One — a filter offering three actions nothing could write — was fixed by splitting declared values from recorded ones, so users are only ever shown options that can return a row.
The rest are in a public build list with their evidence, their file paths and the pages that mention them, because the honest interim state of an inert field is documented, not quietly deleted. Deleting it makes the next person rebuild it; documenting it makes the decision explicit.
The recommendation that came out of this, which is not the obvious one
For the location capacity field the recommendation was a warning and a utilisation view rather than a hard refusal. Goods that have physically arrived have to go somewhere, and a block would simply be satisfied by lying to the system. An inert setting is bad; a setting that makes people enter false data is worse.
Four questions for any system you are being shown
Show me this field with a value in it, on real data.
A good answer sounds like
They filter a list and rows appear.
What it actually means
The single most useful request in a demonstration, and it costs nothing to make.
What happens when this date passes?
A good answer sounds like
A named notification, to a named person.
What it actually means
A date with no consequence is a note. Useful, but not a control.
Which screen sets this, and which screen reads it?
A good answer sounds like
Two answers, both specific.
What it actually means
One answer means it is a record. No answers means it is vocabulary.
Is there anything in the schema you would not describe as a feature?
A good answer sounds like
Yes, and a list.
What it actually means
Every system that has grown has some. A vendor who says no has either not looked or is not telling you.
What AWRA OpsHub does today
- The nine asset movement actions that are genuinely written, now separated in code from the twelve that are merely declared.
- A public build list recording each inert field with its file path, its evidence and every page that mentions it.
- Document expiry reminders that work — for employee documents, which is the one place the filter permits.
- A per-item stock rotation setting read by every allocation path, wired 1 October 2026.
- Count plans that open their own count when due and tell the assignee, wired 1 October 2026.
- A supplier scorecard stored nightly for every supplier with orders, wired 1 October 2026.
- A storage location capacity counted in stock units, with a percentage full and an over-capacity alert that warns rather than refuses, wired 1 October 2026.
More we can add to your workspace
- A behaviour behind the hardware asset table: a controller, a route, a view and a reminder.
- A service schedule or next-service alert on the main asset register.
- Value-based approval routing, despite thresholds being stored by the approval engine.
Where we point you to a specialist
- This page is about a category of defect rather than about a feature. Four of the six have since been wired; we promise neither of the remaining two here, and one may be better deleted than wired.
- The build list is deliberately public. A prospect can read every one of these before talking to us, which is the point of writing it down.
- This is market-neutral. Douala is here as a port city where equipment arrives, moves inland and has to be found again.
What we can build for Cameroon on top of the standard product
Everything listed above as something we can add describes what ships in the standard product today — it is a starting point for Cameroon, not a limit on what AWRA OpsHub can do there. Kenya's eTIMS integration and its maintained payroll engine are in the product because Kenyan clients needed them and commissioned them; neither appeared by itself. The same door is open here. If a DGI e-invoicing connection, a French interface, a bank or mobile money feed, a statutory return format, a rule specific to how your operation runs, or a link to a system you already have is what stands between you and a decision, tell us and we will scope it as a build — written spec, timeline and price — before you commit to anything.
The DGI platform, once there is something to build against
Real-time issuance through the tax administration's e-Facturation platform or an accredited provider, with the retries, the failure queue and the daily report of invoices carrying no reference. Stated honestly, because it is the whole position today: the 2026 Finance Law creates the obligation, the technical specification and the accreditation route have not been published, and nobody — us included — can build against a specification that does not exist yet. Any vendor claiming Cameroon e-invoicing readiness right now is describing an intention.
MTN MoMo, Orange Money, banks and the transfer file
Mobile money settlement and bank statement feeds into the Payments Register, and — the one that actually matters here — the currency-control file assembled from the purchase record: the domiciliation reference, the customs declaration and the proof of receipt held against the payment instruction rather than in a folder somebody has to rebuild. We would not become your bank's counterparty; we would stop the file being reconstructed by hand every time.
The operational work, which is what most commissions actually are
An extra approval stage in a chain that does not match the standard one, a custom field set on employees or assets that only your sector needs, an expiry that has to block an order rather than send an email, a report your board asks for in a shape nothing produces, or a scanner or weighbridge feeding the goods-in door. These are the commissions we are asked for most often and the smallest ones we quote — and unlike a revenue-authority pipeline, none of them waits on a regulator.
Payroll and statutory returns
Income tax, CNPS contributions and the associated schedules produced in the layout each body expects, generated from live payroll records rather than rebuilt in a spreadsheet each month.
Systems you already run
The accounting package, CRM, online store or custom database you intend to keep — connected through our API so a fact is entered once and appears everywhere it is needed.
How it works: you describe the requirement, we return a written scope, timeline and cost, and once agreed it is built into your environment and maintained as part of the product. No roadmap slide, and no pretending in a demo that something exists when it does not.
Tell us what you need integratedTwo greps, not one
Whatever you are evaluating, and whoever built it: ask what writes the field and what reads it. The answer separates a feature from a word, and no demonstration will surface the difference on its own.
Talk about what is actually wiredFrequently asked questions
Why not just delete the dead table?
Because that is a decision, not a cleanup. If the smallest useful service-schedule feature is ever built, this is the schema it would use — and deleting it means the next person designs it again from scratch. What was wrong was that nothing recorded it as inert. Now something does.
How did six of these appear in one codebase?
The ordinary way: each was added by somebody solving the problem in front of them, and the wiring was the part that got deferred. None of them was a mistake at the time. The mistake was that nothing ever went back and asked which fields had no readers.
Does this mean the asset register is unreliable?
No, and the distinction matters. The nine recorded movement actions are written, read and displayed; custody is the part of the module that works. What is inert is the maintenance vocabulary sitting next to it, which is precisely why it was worth separating the two in code.