The problem
Decisiv runs a platform where truck OEMs, dealers and fleets manage service events: a truck arrives at a shop, an estimate is written, the fleet approves it, the repair is done and invoiced. Those companies run their own systems and needed to read and write this data without logging into a web app.
The platform had a public REST API, but adding resources required coordination across implementation, documentation and permissions. Input validation lived in ad-hoc “extract and validate” classes with no shared rules, the OpenAPI documentation was edited by hand and drifted from the code, and permissions for a new endpoint were a separate manual step that was easy to forget. Some list endpoints also needed performance work under heavier workloads.
What I did
I am one of the engineers who owns the API layer. Over the last years my part has been: designing and shipping new resources, the performance work on the slow endpoints, the OpenAPI documentation, and the dashboards and monitors that tell the team when something regresses.
How I solved it
Contract-first validation. Every endpoint now starts with a dry-validation contract that declares the parameters, their types and the cross-field rules. The contract is written and tested before the controller exists, and the controller only runs when the contract passes. Shared rules (pagination, sparse fieldsets, filter syntax) live in reusable macros, so two endpoints cannot validate the same thing differently.
Three coordinated changes per resource. A new resource ships as three pull requests that are reviewed together: the API itself, the OpenAPI specification in its own repository, and the permission seed that tells the authorization layer which roles may call it. Without the third one a real client receives a precondition error, so the pattern makes the “forgotten permission” bug impossible to miss.
Database first for performance. I investigate slow endpoints by separating repeated association queries from the cost of the main query. That work includes reading execution plans, checking estimates and available indexes, and comparing query alternatives with representative data. Eager loading and changes to the main query are evaluated separately.
Observability. Request logs carry the OAuth application, tenant, endpoint and timing, so dashboards in Datadog and LogScale show usage and error rates per partner and per endpoint. Monitors page on error-rate and latency changes rather than on fixed thresholds.
What was hard
Multi-tenant scoping. The same endpoint serves fleets, dealers and sponsors, and a filter that is correct for one account shape is wrong for another. Getting the policy right required reading how each caller is related to the data, not just who they are.
Telling a real N+1 apart from a plan regression. Both show up as “the endpoint is slow”, and the fixes have nothing in common. I now always get a query plan from an environment with production-like data before touching application code.
The result
Performance work reduced latency on the affected endpoints. New resources go out with documentation and permissions in the same release, and the review checklist is the pattern itself. Partner-level dashboards mean a client’s integration problem is usually visible before they write in.
Where to see it
The public developer documentation is linked below. The code is private. A separate article on this site uses a fictional example to explain how I investigate query-planner behavior.