Skip to main content

Registry Service

Service Type: Core REST Microservice with Asynchronous Job Processing Language: Kotlin / Micronaut Framework Database: PostgreSQL (owned) Async Processing: JobRunr (scheduled and background tasks) Status: Implemented (v1.32.0)


Overview

Registry Service (internally branded as "Governance Service") manages the complete lifecycle of bond issuance, company governance, and market participants within DEUSS. It orchestrates companies (issuers/investors), bonds, guarantees, scoring, and associated documents while coordinating asynchronous blockchain operations and document storage. This is a complex, stateful service with integration to blockchain and external file storage.


Business Responsibilities

  • Company Management — Lifecycle of issuer and investor companies, roles, profiles, wallet addresses, AML verification states
  • Bond Lifecycle — Creation, drafting, publishing, issuance of bonds; tracking ISIN codes, nominal values, interest rates, maturity dates
  • Bond Guarantees — Management of guarantee structures, guarantee documents, and guarantee states for bonds
  • Document Management — Upload, storage, and retrieval of bond documents and guarantee documents (via S3)
  • Marketing Assets — Storage and management of bond marketing materials
  • User & Passkey Management — User registration with passkey support (WebAuthn); identity recovery
  • Scoring — Record and track company scoring events (credit ratings, risk assessments, etc.)
  • Blockchain Operations — Coordinate asynchronous blockchain writes via JobRunr; track operation status
  • Async Job Execution — Bond issuance, company creation, manager changes, freeze operations via JobRunr

Owned Data

Core Entities:

  • users — User accounts with email, passkeys, wallet addresses
  • companies — Master company records (name, identifiers, country, wallet address)
  • issuer_details — Profile for companies issuing bonds
  • investor_details — Profile for companies investing in bonds
  • bonds — Bond records (ISIN, nominal value, interest rate, maturity, state: DRAFT/WAITING_FOR_ISSUANCE/ISSUED)
  • bond_industry_codes — Industry classification codes for bonds
  • bond_documents — Uploaded bond prospectuses and related documents
  • bond_marketing_assets — Marketing materials for bonds
  • bond_guarantees — Guarantee arrangements for bonds
  • bond_guarantee_documents — Documents related to bond guarantees
  • scorings — Historical scoring records for companies
  • operations — Records of asynchronous blockchain operations with status tracking
  • passkeys — WebAuthn passkeys for user identity Constraints:
  • One issuer profile per company (unique)
  • One investor profile per company (unique)
  • ISIN codes are unique
  • Bonds tracked in states: DRAFT → WAITING_FOR_ISSUANCE → ISSUED
  • Users have optional email (nullable post-migration)

Inbound Interfaces

REST API

Authentication: JWT Bearer token; varies by endpoint (ANONYMOUS for public, ADMIN for admin)

Companies Management (/v1/companies, /v1/admin/companies)

EndpointMethodOperationPurpose
/v1/companiesGETgetCompaniesList companies with filters (name, acting user, distributor, business ID, VAT, LEI, AML state, wallet, country)
/v1/companies/{company_id}GETgetCompanyFetch company details
/v1/companies/issuerPOSTcreateIssuerCompanyCreate company with issuer profile (async, returns 202)
/v1/companies/investorPOSTcreateInvestorCompanyCreate company with investor profile (async, returns 202)
/v1/companies/{company_id}/issuer-profilePOSTaddIssuerProfileAdd issuer profile to existing company
/v1/companies/{company_id}/investor-profilePOSTaddInvestorProfileAdd investor profile to existing company
/v1/companies/{company_id}PATCHupdateCompanyUpdate company attributes
/v1/companies/{company_id}/managerPATCHchangeCompanyManagerChange acting manager (async operation)

Bonds Management (/v1/bonds, /v1/admin/bonds)

EndpointMethodOperationPurpose
/v1/bondsGETgetBondsList bonds with filters (name, company, registration, headcount, guarantor)
/v1/bonds/{bond_id}GETgetBondFetch bond draft details
/v1/bonds/isin/{bond_isin}GETgetBondByIsinFetch bond by ISIN code
/v1/bondsPOSTcreateBondDraftCreate new bond draft
/v1/bonds/{bond_id}PATCHpatchBondDraftUpdate bond draft fields
/v1/bonds/{bond_id}DELETEdeleteBondDraftDelete draft bond
/v1/bonds/{bond_id}/issuePOSTissueBondIssue bond (async, triggers blockchain ops)

Bond Documents (/v1/bonds/{bond_id}/documents)

EndpointMethodOperationPurpose
/v1/bonds/{bond_id}/documents/uploadPOSTinitiateBondDocumentUploadBegin file upload (returns upload_id)
/v1/bonds/{bond_id}/documents/upload/{upload_id}/completePOSTcompleteBondDocumentUploadFinalize upload to S3
/v1/bonds/{bond_id}/documentsGETgetBondDocumentsList uploaded documents
/v1/bonds/{bond_id}/documents/{document_id}DELETEdeleteBondDocumentDelete document

Bond Marketing Assets (/v1/bonds/{bond_id}/marketing-assets)

EndpointMethodOperationPurpose
/v1/bonds/{bond_id}/marketing-assets/uploadPOSTinitiateBondMarketingAssetUploadBegin marketing asset upload
/v1/bonds/{bond_id}/marketing-assets/upload/{upload_id}/completePOSTcompleteBondMarketingAssetUploadFinalize marketing asset to S3
/v1/bonds/{bond_id}/marketing-assetsGETgetBondMarketingAssetsList marketing assets
/v1/bonds/{bond_id}/marketing-assets/{asset_id}DELETEdeleteBondMarketingAssetDelete marketing asset

Bond Guarantees (/v1/bonds/{bond_id}/guarantees)

EndpointMethodOperationPurpose
/v1/bonds/{bond_id}/guaranteesGETgetBondGuaranteesList guarantees for bond
/v1/bonds/{bond_id}/guaranteesPOSTcreateBondGuaranteeCreate guarantee for bond
/v1/bonds/{bond_id}/guarantees/{guarantee_id}PATCHupdateBondGuaranteeUpdate guarantee status/details

Users (/v1/users)

EndpointMethodOperationPurpose
/v1/usersPOSTcreateUserCreate new user
/v1/users/{user_id}/walletPOSTsetUserWalletSet blockchain wallet address for user
/v1/users/{user_id}/passkeyPOSTregisterPasskeyRegister WebAuthn passkey
/v1/users/{user_id}/recoverPOSTrecoverUserRecover user identity via passkey

Scoring (/v1/scoring)

EndpointMethodOperationPurpose
/v1/scoringPOSTrecordScoringRecord company scoring event (credit rating, risk, etc.)

Operations (/v1/operations)

EndpointMethodOperationPurpose
/v1/operations/{operation_id}GETgetOperationQuery status of async operation (blockchain job)

Outbound Interfaces

Internal Service Calls

  • Company Service (Broker Platform) — Generated OpenAPI client for company operations (internal integration)

External Integrations

  • AWS S3 — Document and marketing asset storage
    • Bucket: Configurable via AWS_S3_BUCKET
    • Operations: Upload/download bond docs, marketing assets, guarantee docs
  • Blockchain — Asynchronous blockchain writes via JobRunr
    • Company entity type ID: Configurable (default: 1)
    • Wallet type/role: Configurable for company wallets
    • Operations: Create issuer/investor on-chain, manage wallets

Database Only

  • PostgreSQL direct access via Hibernate/JPA

Kafka Integration

Status: Disabled (kafka.enabled: false)

  • No Kafka producers
  • No Kafka consumers
  • No CDC/Debezium enabled
  • Async model uses JobRunr instead

External Integrations

  • AWS S3 — Bond documents, marketing assets, guarantee documents stored with presigned URLs
  • Blockchain (On-Chain Registry) — Companies created/updated on blockchain via JobRunr jobs
    • Entity type IDs for issuers/investors
    • Wallet management (EOA or smart contract wallets)
  • Company Service (Broker Platform) — OpenAPI client for company-related operations
  • JobRunr — Distributed job scheduler for async operations

Asynchronous Job Model

Registry Service uses JobRunr for background task execution:

JobTriggerPurposeRetry Logic
IssueBondJobBond issuance requestRegister bond on blockchain, finalize stateAutomatic with custom filters
CreateCompanyJobsCompany creation (issuer/investor)Create company wallet on-chainRetry on blockchain errors
ChangeManagerJobsManager change requestUpdate manager on-chainRetry on blockchain errors
FreezeJobsFreeze operationLock/freeze company account on-chainCustom handling
PublishBondJobBond publicationPublish bond details on-chainRetry logic
AddScoringJobScoring recordRecord score on-chainRetry logic
IssueBondSchedulerPeriodic (default 5min interval)Poll and process pending issuanceConfigurable interval

Configuration:

registry:
issue-bond-scheduler:
interval: ${ISSUE_BOND_SCHEDULER_INTERVAL:PT5M}

Key Business Rules

  1. Companies must have at least one role (ISSUER or INVESTOR)
  2. Bonds progress through states: DRAFT → WAITING_FOR_ISSUANCE → ISSUED
  3. Bond Drafts can only be deleted; published bonds cannot be modified
  4. ISIN Codes are unique and immutable once assigned
  5. Bond Guarantees are tied to specific bonds and track guarantee state/documents
  6. User Passkeys enable passwordless recovery; email is optional
  7. Scoring events are immutable audit records
  8. Operations track all async blockchain jobs with success/failure state
  9. AML Verification States filter companies by compliance status (UNKNOWN, VERIFIED, REJECTED, EXPIRED)
  10. File Uploads use 2-stage process: initiate (get upload_id) → complete (finalize to S3)

Deployment

Runtime Stack:

  • Java 25 (OpenJDK JRE in Alpine container)
  • Micronaut on Netty
  • PostgreSQL database with Flyway migrations (28 migration versions)
  • JobRunr for distributed job scheduling
  • Kotlin coroutines for async/await patterns Configuration:
  • Port: 8080
  • Health check: /health
  • Environment variables:
    • DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD
    • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_S3_BUCKET, AWS_S3_HOST
    • CHAIN_COMPANY_ENTITY_TYPE_ID, CHAIN_COMPANY_WALLET_TYPE, CHAIN_COMPANY_WALLET_ROLE
    • ISSUE_BOND_SCHEDULER_INTERVAL
    • JWT_GENERATOR_SIGNATURE_SECRET Container:
  • Non-root user (runtime) for security
  • Init process (tini) for signal handling
  • JVM container support enabled

Observability

  • Structured Logging — Semantic logging with events and parameters
  • Health Endpoint/health for K8s liveness/readiness
  • Job Status Tracking — Operations table tracks job success/failure/retry count
  • Metrics — Unknown (Micrometer integration status not verified)

Technical Notes

  • Async-First Model — Company creation and bond issuance return 202 Accepted; clients must poll /v1/operations/{operation_id} for completion
  • Job Scheduler PatternIssueBondScheduler polls pending issuances every 5 minutes; configurable interval
  • Two-Stage File Upload — Security pattern: request upload slot, get presigned URL, complete upload to confirm
  • Custom Job Retry FiltersJobRetryExhaustedFilter, TxNotMinedYetException for blockchain-specific handling
  • Coroutine Support — Uses Kotlin coroutines for async I/O patterns
  • CBOR Serialization — Jackson CBOR support for compact binary serialization
  • Company Visibility — Companies can be filtered by visibility states (public/private)
  • Profile Status & Frozen State — Companies/users can be frozen with frozenUntil timestamp

Relationships with Other Services

  • Partner Service (core) — Unknown; likely separate governance domains (Partner = payment/fees, Registry = governance/bonds)
  • Core Payment Service (core) — Unknown; Registry may coordinate payments or receive payment notifications
  • Company Service (Broker Platform) — Active integration via OpenAPI client for company operations
  • Blockchain — Direct blockchain writes for company/bond entities
  • Indexer (GraphQL) — May expose registry data via GraphQL (Unknown—not verified)

Documentation Sources:

  • Source: core/registry-service/src/
  • Migrations: core/registry-service/src/main/resources/db/migration/ (28 versions)
  • OpenAPI Public: api-specifications/.../registry-service/public/
  • OpenAPI Internal: api-specifications/.../registry-service/internal/
  • Config: core/registry-service/src/main/resources/application.yaml
  • Container: core/registry-service/Dockerfile