11// Package main is the entry point for the Meridian unified binary.
22//
3- // It wires all 11 Meridian services into a single Go process with a shared gRPC
3+ // It wires all Meridian services into a single Go process with a shared gRPC
44// server and gateway HTTP server. Services are initialized in tier dependency order:
55//
6- // - Tier 0 (no deps): party, reference-data, market-information, tenant, internal-account
6+ // - Tier 0 (no deps): party, reference-data, market-information, tenant, internal-account, identity
77// - Tier 1 (Tier 0 deps): financial-accounting, position-keeping, forecasting
88// - Tier 2 (Tier 1 deps): current-account
99// - Tier 3 (Tier 2 deps): payment-order, reconciliation
@@ -36,6 +36,7 @@ import (
3636 currentaccountv1 "github.com/meridianhub/meridian/api/proto/meridian/current_account/v1"
3737 financialaccountingv1 "github.com/meridianhub/meridian/api/proto/meridian/financial_accounting/v1"
3838 forecastingv1 "github.com/meridianhub/meridian/api/proto/meridian/forecasting/v1"
39+ identityv1 "github.com/meridianhub/meridian/api/proto/meridian/identity/v1"
3940 internalaccountv1 "github.com/meridianhub/meridian/api/proto/meridian/internal_account/v1"
4041 marketinformationv1 "github.com/meridianhub/meridian/api/proto/meridian/market_information/v1"
4142 partyv1 "github.com/meridianhub/meridian/api/proto/meridian/party/v1"
@@ -59,6 +60,9 @@ import (
5960 forecastingpersistence "github.com/meridianhub/meridian/services/forecasting/adapters/persistence"
6061 forecastinghandler "github.com/meridianhub/meridian/services/forecasting/handler"
6162 forecastingstarlark "github.com/meridianhub/meridian/services/forecasting/starlark"
63+ identitypersistence "github.com/meridianhub/meridian/services/identity/adapters/persistence"
64+ identitybootstrap "github.com/meridianhub/meridian/services/identity/bootstrap"
65+ identityservice "github.com/meridianhub/meridian/services/identity/service"
6266 internalaccountpersistence "github.com/meridianhub/meridian/services/internal-account/adapters/persistence"
6367 internalaccountservice "github.com/meridianhub/meridian/services/internal-account/service"
6468 marketinformationpersistence "github.com/meridianhub/meridian/services/market-information/adapters/persistence"
@@ -263,7 +267,7 @@ func run(logger *slog.Logger, grpcPort, httpPort int) error {
263267
264268 // ─── Register All Services ──────────────────────────────────────────
265269
266- if err := registerServices (grpcServer , conns , idempotencySvc , faEventPublisher , pkEventPublisher , outboxPublisher , outboxRepo , loopback , tracer , logger ); err != nil {
270+ if err := registerServices (ctx , grpcServer , conns , idempotencySvc , faEventPublisher , pkEventPublisher , outboxPublisher , outboxRepo , loopback , tracer , logger ); err != nil {
267271 return err
268272 }
269273
@@ -333,9 +337,10 @@ func run(logger *slog.Logger, grpcPort, httpPort int) error {
333337 return nil
334338}
335339
336- // registerServices wires all 11 gRPC services into the shared server in tier dependency order,
340+ // registerServices wires all gRPC services into the shared server in tier dependency order,
337341// then enables health checking and reflection.
338342func registerServices (
343+ ctx context.Context ,
339344 grpcServer * grpc.Server ,
340345 conns * serviceConns ,
341346 idempotencySvc idempotency.Service ,
@@ -368,13 +373,21 @@ func registerServices(
368373 }},
369374 {"control-plane" , func () error { return wireControlPlane (grpcServer , conns .pgxPool ("control-plane" ), logger ) }},
370375 {"audit" , func () error { return wireAudit (grpcServer , conns .gormDB ("tenant" ), logger ) }}, // audit uses platform DB
376+ {"identity" , func () error { return wireIdentity (grpcServer , conns .gormDB ("identity" ), logger ) }},
371377 } {
372378 if err := wire .fn (); err != nil {
373379 return fmt .Errorf ("%s: %w" , wire .name , err )
374380 }
375381 }
376382 logger .Info ("Tier 0 services registered" )
377383
384+ // Run identity bootstrap: provisions the platform admin identity on first boot.
385+ // This is a no-op if the admin already exists or if env vars are not set.
386+ identityRepo := identitypersistence .NewRepository (conns .gormDB ("identity" ))
387+ if err := identitybootstrap .Run (ctx , identityRepo ); err != nil {
388+ logger .Warn ("identity bootstrap failed, service startup continues" , "error" , err )
389+ }
390+
378391 // Tier 1: Depend on Tier 0 via loopback
379392 for _ , wire := range []struct {
380393 name string
@@ -795,6 +808,19 @@ func wireAudit(server *grpc.Server, db *gorm.DB, logger *slog.Logger) error {
795808 return nil
796809}
797810
811+ // ─── Identity Wiring ─────────────────────────────────────────────────────────
812+
813+ func wireIdentity (server * grpc.Server , db * gorm.DB , logger * slog.Logger ) error {
814+ repo := identitypersistence .NewRepository (db )
815+ svc , err := identityservice .NewService (repo , logger )
816+ if err != nil {
817+ return err
818+ }
819+ identityv1 .RegisterIdentityServiceServer (server , svc )
820+ logger .Info ("registered identity service" )
821+ return nil
822+ }
823+
798824// ─── Control Plane Wiring ────────────────────────────────────────────────────
799825
800826func wireControlPlane (server * grpc.Server , pool * pgxpool.Pool , logger * slog.Logger ) error {
@@ -887,6 +913,7 @@ var serviceNames = []string{
887913 "meridian.reference_data.v1.AccountTypeRegistryService" ,
888914 "meridian.mapping.v1.MappingService" ,
889915 "meridian.audit.v1.AuditService" ,
916+ "meridian.identity.v1.IdentityService" ,
890917}
891918
892919// wireGateway creates the gateway HTTP server with the Vanguard transcoder
@@ -1078,7 +1105,7 @@ func newServiceConns(ctx context.Context, baseDSN string, logger *slog.Logger) (
10781105 gormServices := []string {
10791106 "party" , "tenant" , "internal-account" ,
10801107 "financial-accounting" , "current-account" ,
1081- "payment-order" , "reconciliation" ,
1108+ "payment-order" , "reconciliation" , "identity" ,
10821109 }
10831110
10841111 // Services requiring pgxpool connections.
0 commit comments