Skip to main content
Parklet is a Neuron assembly package hosted by Waher.IoTGateway. The backend is composed in TAG.Service.Parklet, exposed over HTTP through TAG.Service.Parklet.Http, and centered on domain services in TAG.Service.Parklet.Core.

Runtime shape

At startup, ParkletModule creates a ControllerEndpointRouter mounted at /parklet-api with SnakeCaseParameterNameCodec. The module then:
  1. Registers account and anonymous authentication schemes on the router.
  2. Creates repositories, reference-data providers, domain services, hydrators, payment collaborators, entitlement services, and authorization services.
  3. Registers those dependencies in router.ServiceProvider.
  4. Creates ParkletHttpService, which adds /open-api, request logging middleware, and scans the HTTP assembly for controllers.
  5. Registers the router with Gateway.HttpServer.
  6. Starts background work such as event dispatching, reservation lifecycle tracking, debt payment scheduling, and Stripe subscription processing.
Stop() reverses the runtime pieces by unregistering the router and disposing or stopping the long-running workers.

Project layers

Request flow

An HTTP request enters through Gateway.HttpServer and is routed to /parklet-api/.... The HTTP router then:
  1. Matches the request method and route.
  2. Runs route middleware and authorization middleware in pipeline order.
  3. Creates a controller instance for the request through router.ServiceProvider.
  4. Binds route, query, and JSON body values using the router’s snake-case naming codec.
  5. Calls the controller action.
  6. Lets the controller call Core services and repositories through injected dependencies.
  7. Hydrates domain models into HTTP response DTOs and returns JSON.
The controllers are intentionally thin. Most business rules live in Core services such as parking, reservations, leases, groups, queues, organizations, users, payments, and principals. Hydrators keep HTTP response shapes separate from domain models. Parklet uses parent controllers for nested resources. For example, ParkingAreaController is declared under ParkingAreasController, and ParkingSquaresController is declared under ParkingAreaController, producing routes such as /parklet-api/parking-areas/[areaId]/squares/[squareId]. The same pattern appears under /me, /groups/[groupId], and /principals/[principalId].

Authorization model

Parklet uses router authentication schemes to identify what kinds of callers the API accepts, then uses attribute-based authorization for endpoint permissions. ParkletAuthorization resolves request facts into an ABAC subject and context. ParkletAuthorizationMiddleware bridges the HTTP router authorization pipeline to the Parklet authorization service. The shared ParkletController base class gives controllers helpers for asserting the current principal, user, authorization state, and service results. This keeps endpoint code focused on the use case while authorization policy, role lookup, and request fact resolution stay centralized.

Events and background work

Core services publish domain events through IParkletEventPublisher. The default publisher writes events to a persisted DatabaseQueue, and PersistedQueueEventDispatcher dequeues events, discovers matching IParkletEventHandler<T> implementations through the runtime inventory, and invokes them with retry handling. The module also starts specialized background workers:
  • reservation lifecycle tracking, which advances reservation state based on runtime settings
  • debt payment scheduling, which processes outstanding ledger debt through the payment gateway
  • Stripe subscription event dispatching for lease subscription changes
These workers are started after the dependency graph is registered and stopped during module shutdown.

OpenAPI endpoint

ParkletHttpService exposes /parklet-api/open-api as a live OpenAPI document endpoint. It calls OpenApiGenerator.Generate(router, new OpenApiInfo { Title = "Parklet API", Version = "3.0.0" }), adds the current Neuron server URL with OpenApiGenerator.CurrentServers(), and returns the generated document as JSON. The generated document reflects the current router tree, controller routes, bound request/response types, authentication metadata, authorization metadata, and OpenAPI annotations such as [Summary] and [Tag].

Where to add behavior

  • Add new business rules in TAG.Service.Parklet.Core.
  • Add storage behavior behind Core repository contracts in TAG.Service.Parklet.Persistence.
  • Add external HTTP surface area in TAG.Service.Parklet.Http controllers, requests, responses, and hydrators.
  • Register new long-lived dependencies in ParkletModule.Start() before controller discovery.
  • Publish cross-cutting side effects as domain events when the work should happen outside the request’s main transaction.