An internal workspace for finding software, understanding its ownership and creating new services.
Open a service entry in this internal developer portal and it shows the owner, the documentation and the links to other systems. An engineer can follow those links out to the APIs, the systems and the team behind the service.
We also tied the catalog to service creation. A developer fills in a template's guided form, and the portal records the setup task and shows its steps as they run.
The challenge
A catalog is hard to trust when creating a service and registering it are two separate jobs. Ownership turns murky, and documentation drifts away from the software it describes. Keeping the entries current means checking several sources, and most of them have usually not changed.
The portal had to make registering a service part of the setup workflow, and stop rewriting records for no reason. Its access rules also had to reach the database query, so the interface would show only the records a user is allowed to see.
What we built
The catalog describes components, APIs, resources, systems and domains, each linked to the groups and users responsible for it. Configuration kept beside a service supplies its description. Providers can add entries from cloud and directory systems too.
When a developer submits a service template, the portal checks the answers before it stores a task. A worker then claims that task, runs its steps and streams the progress and logs to the screen. Conditions and loops let a template handle variations. Registration can run as one of those steps, so the new service ends up with its own catalog entry.
Documentation sits with the service record, and search helps engineers find it. Plugins extend this shared catalog, which keeps ownership information on hand for the capabilities built around it.
Database-backed task execution
Setup tasks stay in the portal database, which avoids a separate message broker for this workflow. Workers claim tasks and report heartbeats while they run. Dry runs, cancellation and retries give the platform team ways to check or stop a template.
Actions can save checkpoints as they go. A retry can then reuse the values from a successful checkpoint, instead of repeating every step that already finished. A failed checkpoint records a failure state for a later look. Automatic recovery of stale tasks is optional and follows the recovery policy the team sets.
Incremental catalog processing
Incoming entries land in a refresh table first. The processing engine fingerprints each result and compares it with the previous version. An unchanged result skips another database write and the relationship work that would follow.
Relationship changes move through a separate queue. Workers take out expiring leases while they assemble the final record and refresh the search data. If a worker stops, its lease can expire, which makes that work available again.
Defined plugin and permission boundaries
Dependency injection hands each backend plugin the shared services it needs. Through defined extension points, a smaller module can add behaviour to a plugin it does not own. Each one is reached at its own API route, and a separate logical database is set up for it by default.
Signing in establishes who the user is, and permission checks decide what they can see. For catalog queries, the supported conditions become SQL filters, so the database returns only the rows they are allowed. The installation still needs an explicit access policy. Plugins run as trusted application code, and catalog namespaces do not give tenant isolation.
Project success
Service creation and service information now meet in one catalog. Engineers can find an owner and the documentation that goes with a service. A template run can register a new service as part of setup.
Recorded tasks, checkpoints and streamed logs make that setup work easy to inspect. The incremental step keeps catalog updates focused on what actually changed. Query-level permission conditions let the client control which entries a user can retrieve.
Technology stack
Application
TypeScript, Node.js, React
Backend
Express, dependency-injected plugins
Data access
Knex, PostgreSQL or SQLite
Search
Lunr, optional database and search-service modules
Documentation storage
Local or compatible object storage
Other engagements
Recognize the pattern?
If one of these looks like your situation, the discovery call is where we find out how close.