# Standard Metadata/Headers **Architecture Approved** ## Overview Standard Message Headers define the required metadata fields for HSOne service communication across HTTP and Kafka protocols. ### Standard Metadata Schema Examples - **Avro Schema Template**: [StandardMetaDataSchema.avsc](https://gitlab.com/scheinone/dental-platform/domains/access/licensing-team/licensing-service/-/blob/main/src/main/avro/StandardMetaDataSchema.avsc) - **Core Object**: [StandardMetadata.java](https://gitlab.com/scheinone/dental-platform/domains/access/licensing-team/licensing-service/-/blob/main/src/main/java/com/henryscheinone/access/licensingservice/core/common/model/StandardMetadata.java) - **Controller Implementation**: [LicenseController.java](https://gitlab.com/scheinone/dental-platform/domains/access/licensing-team/licensing-service/-/blob/main/src/main/java/com/henryscheinone/access/licensingservice/adapter/input/api/LicenseController.java) ## Field Definitions | Field Name | Status | Alias | Requirement Description | Type | HTTP | Kafka | | --- | --- | --- | --- | --- | --- | --- | | **sessionId** | Decided | — | Async routing | String | OPTIONAL | OPTIONAL | | **messageId** | Decided | correlationID, idempotencyID | Origination strategy. To be used for idempotency checks and as the correlation id for related messages. | String (UUID Recommended) | REQUIRED | REQUIRED | | **createdOn** | Decided | — | Generated for each new message | Long (representing epoch in milliseconds) | REQUIRED | REQUIRED | | **tenantIdType** | Decided | — | `[ACCOUNT_ID, SERIAL_NUMBER, CUSTOMER_NUMBER]` *default = `CUSTOMER_NUMBER`. Others should be approved and added to this document. `CUSTOMER_NUMBER` should represent only a child-most account. | String (represents enum) | REQUIRED | REQUIRED | | **tenantId** | Decided | salesforce accountId, customerNumber, SerialNumber | ⚠️ **Warning**: An HSOne OrgId needs to become an engineering/architecture priority and is essential to ensuring data is processed securely. We are currently using salesforce accountId for lack of a better current option but should be considered expensive technical debt. | String | REQUIRED | REQUIRED | | **userId** | REVIEWING | clientId | Auth0 userId or Auth0 clientId for M2M. We should get more clarity on this as the Auth0 projects move forward. Must be provided but can be either a user ID or a machine ID if a user ID is not available. Use the first identifiable system. Get as close to the initial request as possible. Should we add UserIdType? | String | REQUIRED | REQUIRED | | **systemId** | UNDECIDED | — | This is the system user | — | — | — | | **applicationId** | Decided | — | `[DENTRIX_CORE, DENTRIX_ENTERPRISE, ASCEND, etc]` Originating application id (mostly useful for on-prem applications where we do not have proper identity/auth solutions) | String (represents enum) | OPTIONAL | OPTIONAL | | **applicationVersion** | UNDECIDED | — | Version number for originating application | String | OPTIONAL | OPTIONAL | | **isSynthetic** | UNDECIDED | — | A marker for synthetic test data that can be filtered out of the streaming before triggering non-idempotent events. Synthetics can be generated by test and APM tooling to validate continuous uptimes and SLOs. | boolean (default false) | OPTIONAL | OPTIONAL | ## Example Workflow This example demonstrates how standard metadata flows through a multi-service architecture: ### Scenario: Salesforce → CRM-Service → Licensing-Service → Voice-Perio-Service → Bola 1. **Salesforce** triggers event originating from Salesforce by assigning "Voice-Perio" product to a practice's account. Using Confluent Cloud Connector for Salesforce, event is published to: ``` private.crm.salesforce.order_change_delta_event.1 ``` 2. **CRM-Service** consumes Salesforce event, and calls Licensing-Service through sync API call: ``` POST https://licensing-service.dev-dentalapp.cc/api/license ``` 3. **Licensing-Service** receives command request via API then: - Publishes a command to: ``` private.licensing.license.command.1 ``` - Consumes command request, stores event data and publishes event to: ``` public.licensing.license.event.1 ``` 4. **Voice-Perio-Service** consumes `LicenseEvent` then: - Calls Bola API to provision a new Bola Account for the practice - POSTs a `ResourceCommandRequest` to: ``` POST https://licensing-service.dev-dentalapp.cc/api/resource ``` 5. **Licensing-Service** receives command request then: - Publishes a command to: ``` private.licensing.resource.command.1 ``` - Consumes command request, stores event data and publishes `ResourceEvent` to: ``` public.licensing.resource.event.1 ``` 6. **Licensing-Service** receives `ResourceEvent` then: - Publishes a command to update the LicenseStatus from `"PROVISIONING"` to `"PROVISIONED"`: ``` private.licensing.license.command.1 ``` - Consumes command request, makes change, then stores event data and publishes `LicenseEvent` to: ``` public.licensing.license.event.1 ``` ## Key Considerations ### TenantId Warning An HSOne OrgId needs to become an engineering/architecture priority and is essential to ensuring data is processed securely. We are currently using Salesforce accountId for lack of a better current option but should be considered **expensive technical debt**. ### MessageId (Idempotency) The `messageId` field serves dual purposes: - **Idempotency checks**: Prevents duplicate message processing - **Correlation ID**: Links related messages across services Use UUID format for globally unique identifiers. ### Synthetic Data Filtering The `isSynthetic` flag allows test and APM tooling data to be filtered from production event streams before triggering non-idempotent operations.