Registration Service Refactor
Goal
Research and propose an approach to consolidating the Registration Service APIs so that applications can complete onboarding through a coherent, reduced set of endpoints and new services can be accommodated without introducing additional complexity.
Today the registration data is spread across five entity groups (Client, Application, ClientApplication, Extractor, AllowedExtension), each with its own CRUD endpoints — 21+ endpoints in total. Onboarding a single client requires 4 sequential calls whose inputs depend on the previous response’s IDs, and adding a new pipeline capability (e.g. classifier, splitter) would mean adding yet another set of endpoints.
This spike proposes:
-
A single
registrationresource that wraps Client, ClientApplication, Extractors, and AllowedExtensions into one schema — so the full onboarding payload is sent and returned as a single document. -
A
featuresarray within that registration schema where each pipeline stage (FileIntake, Classifier, Splitter, Extractor) is an independently configured, toggleable feature. New services are added as new feature entries with their ownfeatureConfigshape — no new endpoints. -
A reduced endpoint set (21 → 6) organised around
/v2/registrationsas a CRUD resource, plus a reference-data lookup for allowed file extensions.
Acceptance Criteria
-
Propose a forward-compatible schema that covers current services and can absorb future services
-
Identify Registration-to-Policy Engine integration contract, given that service opt-in decisions made at through registration will likely inform policy evaluation
1. Current State
1.1 Domain Model
The service exposes 21+ endpoints across 5 route groups (/v1/client, /v1/clientApplication, .../extractors, .../extensions, extension lookup). Full endpoint list is in openapi.yaml.
1.2 Problems
-
4 sequential calls to onboard:
POST /client→POST /clientApplication→POST .../extractors→POST .../extensions. Each depends on the previous response’s IDs. Failure at any step leaves partial state. -
Confusing surface: Client/Application are auto-created internally (
createIfNotExists) yet have separate CRUD endpoints — unclear whether consumers should manage them directly. -
No extensibility model: Adding a new pipeline capability (classifier, splitter) would require its own CRUD endpoints, further fragmenting the surface.
1.3 Feature Enablement & Policy Engine
The registration schema includes a features array — four pipeline stages that can be toggled per client:
Registration and Policy Engine are two separate concerns:
The registration spike defines the features array schema and publishes feature-change events. The Policy Engine runtime logic is a separate body of work.
How it fits in the system
1.4 Current vs Proposed Onboarding
Current (v1) — 4 sequential calls:
Proposed (v2) — one registration resource, features-driven extensibility:
Reduced endpoint set:
How this meets the goal:
2. Proposed Registration Schema
2.1 Request Schema (POST /v2/registrations)
2.2 Feature Configuration Shapes
2.3 Example
What the request looks like
One call. The server creates Client, Application, ClientApplication, sets up folders, creates extractors, sets allowed extensions, and returns the full registration with all generated IDs.
Response (201 Created):
3. Feature Storage
New table to persist feature state alongside existing registration data:
Why a new table (not a separate service):
-
GET /v2/registrations/:idneeds to return features — without local storage it would depend on an external call -
Follows existing pattern — every other registration entity is in this DB
-
Registration is the source of truth; Policy Engine subscribes to events
Why FeatureConfig as JSON (not separate columns):
-
Each feature has a different config shape — columns per type would require schema migrations for every new feature
-
AJV validates the shape at the API layer before it hits the DB
-
SQL Server
JSON_VALUE()/OPENJSON()available if querying is needed
Dual-write to existing tables: The controller writes to both the new ClientApplicationFeature table and the existing normalised tables (ClientApplication, ClientApplicationExtractor, ClientApplicationAllowedExtension) — keeping v1 queries and backward compatibility intact.