@@ -6,6 +6,8 @@ import "buf/validate/validate.proto";
66import "google/api/annotations.proto" ;
77import "meridian/control_plane/v1/manifest.proto" ;
88import "meridian/control_plane/v1/manifest_history_service.proto" ;
9+ import "meridian/mapping/v1/mapping.proto" ;
10+ import "meridian/party/v1/party.proto" ;
911
1012option go_package = "github.com/meridianhub/meridian/api/proto/meridian/control_plane/v1;controlplanev1" ;
1113
@@ -20,6 +22,18 @@ service ApplyManifestService {
2022 body : "*"
2123 };
2224 }
25+
26+ // ApplyResource applies a granular mutation to a single resource within the manifest.
27+ // It reads the current manifest from the database, patches the specified resource into
28+ // the composite manifest, validates the full dependency graph, computes a diff, and
29+ // executes only the affected phases. A new manifest version is created on success.
30+ // In dry_run mode, returns the diff without applying changes.
31+ rpc ApplyResource (ApplyResourceRequest ) returns (ApplyResourceResponse ) {
32+ option (google.api.http ) = {
33+ post : "/v1/manifests/apply-resource"
34+ body : "*"
35+ };
36+ }
2337}
2438
2539// ApplyManifestRequest contains the manifest to apply and apply options.
@@ -160,3 +174,138 @@ message ValidationError {
160174 // (e.g., the instrument code, account type code, or saga name).
161175 string resource_id = 7 ;
162176}
177+
178+ // ManifestResourceType identifies a category of resource within the manifest.
179+ // Used by ApplyResource to specify which resource type is being mutated.
180+ enum ManifestResourceType {
181+ // MANIFEST_RESOURCE_TYPE_UNSPECIFIED is the default zero value.
182+ MANIFEST_RESOURCE_TYPE_UNSPECIFIED = 0 ;
183+
184+ // MANIFEST_RESOURCE_TYPE_INSTRUMENT targets an InstrumentDefinition.
185+ MANIFEST_RESOURCE_TYPE_INSTRUMENT = 1 ;
186+
187+ // MANIFEST_RESOURCE_TYPE_ACCOUNT_TYPE targets an AccountTypeDefinition.
188+ MANIFEST_RESOURCE_TYPE_ACCOUNT_TYPE = 2 ;
189+
190+ // MANIFEST_RESOURCE_TYPE_VALUATION_RULE targets a ValuationRule.
191+ MANIFEST_RESOURCE_TYPE_VALUATION_RULE = 3 ;
192+
193+ // MANIFEST_RESOURCE_TYPE_SAGA targets a SagaDefinition.
194+ MANIFEST_RESOURCE_TYPE_SAGA = 4 ;
195+
196+ // MANIFEST_RESOURCE_TYPE_PARTY_TYPE targets a PartyTypeDefinition.
197+ MANIFEST_RESOURCE_TYPE_PARTY_TYPE = 5 ;
198+
199+ // MANIFEST_RESOURCE_TYPE_MAPPING targets a MappingDefinition.
200+ MANIFEST_RESOURCE_TYPE_MAPPING = 6 ;
201+
202+ // MANIFEST_RESOURCE_TYPE_PROVIDER_CONNECTION targets a ProviderConnectionConfig.
203+ MANIFEST_RESOURCE_TYPE_PROVIDER_CONNECTION = 7 ;
204+
205+ // MANIFEST_RESOURCE_TYPE_INSTRUCTION_ROUTE targets an InstructionRouteConfig.
206+ MANIFEST_RESOURCE_TYPE_INSTRUCTION_ROUTE = 8 ;
207+
208+ // MANIFEST_RESOURCE_TYPE_MARKET_DATA_SOURCE targets a MarketDataSourceDefinition.
209+ MANIFEST_RESOURCE_TYPE_MARKET_DATA_SOURCE = 9 ;
210+
211+ // MANIFEST_RESOURCE_TYPE_MARKET_DATA_SET targets a MarketDataSetDefinition.
212+ MANIFEST_RESOURCE_TYPE_MARKET_DATA_SET = 10 ;
213+
214+ // MANIFEST_RESOURCE_TYPE_ORGANIZATION targets an OrganizationDefinition.
215+ MANIFEST_RESOURCE_TYPE_ORGANIZATION = 11 ;
216+
217+ // MANIFEST_RESOURCE_TYPE_INTERNAL_ACCOUNT targets an InternalAccountDefinition.
218+ MANIFEST_RESOURCE_TYPE_INTERNAL_ACCOUNT = 12 ;
219+ }
220+
221+ // ApplyResourceRequest contains the resource to apply and apply options.
222+ // The caller specifies the resource type and provides the resource payload
223+ // as a oneof. The server reads the current manifest, patches the resource
224+ // into it, validates the full dependency graph, diffs, and executes only
225+ // the affected phases.
226+ message ApplyResourceRequest {
227+ // resource_type identifies which manifest section is being mutated.
228+ ManifestResourceType resource_type = 1 [(buf.validate.field ).enum = {
229+ defined_only : true
230+ not_in : [0 ]
231+ }];
232+
233+ // resource is the resource payload to apply. Exactly one must be set,
234+ // and it must match the resource_type field.
235+ oneof resource {
236+ option (buf.validate.oneof ).required = true ;
237+
238+ // instrument is an InstrumentDefinition to create or update.
239+ InstrumentDefinition instrument = 2 ;
240+
241+ // account_type is an AccountTypeDefinition to create or update.
242+ AccountTypeDefinition account_type = 3 ;
243+
244+ // valuation_rule is a ValuationRule to create or update.
245+ ValuationRule valuation_rule = 4 ;
246+
247+ // saga is a SagaDefinition to create or update.
248+ SagaDefinition saga = 5 ;
249+
250+ // party_type is a PartyTypeDefinition to create or update.
251+ meridian.party.v1.PartyTypeDefinition party_type = 6 ;
252+
253+ // mapping is a MappingDefinition to create or update.
254+ meridian.mapping.v1.MappingDefinition mapping = 7 ;
255+
256+ // provider_connection is a ProviderConnectionConfig to create or update.
257+ ProviderConnectionConfig provider_connection = 8 ;
258+
259+ // instruction_route is an InstructionRouteConfig to create or update.
260+ InstructionRouteConfig instruction_route = 9 ;
261+
262+ // market_data_source is a MarketDataSourceDefinition to create or update.
263+ MarketDataSourceDefinition market_data_source = 10 ;
264+
265+ // market_data_set is a MarketDataSetDefinition to create or update.
266+ MarketDataSetDefinition market_data_set = 11 ;
267+
268+ // organization is an OrganizationDefinition to create or update.
269+ OrganizationDefinition organization = 12 ;
270+
271+ // internal_account is an InternalAccountDefinition to create or update.
272+ InternalAccountDefinition internal_account = 13 ;
273+ }
274+
275+ // dry_run when true performs validation and planning without committing changes.
276+ bool dry_run = 14 ;
277+
278+ // applied_by identifies who is applying this resource (e.g., user email, API key ID).
279+ string applied_by = 15 [(buf.validate.field ).string = {
280+ min_len : 1
281+ max_len : 255
282+ }];
283+
284+ // expected_sequence_number is the sequence number the caller expects the
285+ // current manifest to have. If it does not match the actual current sequence
286+ // number, the apply is rejected with ABORTED status (ETag semantics).
287+ // Set to 0 to skip the check (first apply or "overwrite" mode).
288+ int64 expected_sequence_number = 16 ;
289+ }
290+
291+ // ApplyResourceResponse contains the result of a single-resource application.
292+ message ApplyResourceResponse {
293+ // status is the outcome of the apply operation.
294+ ApplyManifestStatus status = 1 ;
295+
296+ // step_results contains the result of each execution step.
297+ repeated StepResult step_results = 2 ;
298+
299+ // validation_errors contains structured validation errors if the manifest is invalid.
300+ repeated ValidationError validation_errors = 3 ;
301+
302+ // diff_summary is a human-readable summary of changes detected.
303+ string diff_summary = 4 ;
304+
305+ // sequence_number is the sequence number assigned to the new manifest version.
306+ // Callers should use this value as expected_sequence_number in subsequent applies.
307+ int64 sequence_number = 5 ;
308+
309+ // snapshot is the manifest version record created by this apply, if successful.
310+ ManifestVersion snapshot = 6 ;
311+ }
0 commit comments