core

module
v0.0.0-...-ad95c11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: Apache-2.0

README

OpenNSW Core

A Go SDK for building single window systems — integrated service portals that orchestrate complex, multi-step government or enterprise workflows across multiple agencies and backend services.

What is a Single Window System?

A single window system provides citizens or businesses with one portal to complete end-to-end service applications (e.g. trade permits, licensing, consignment approvals) without navigating separate agency websites. Behind the scenes it:

  • Runs long-lived workflows that span days or weeks
  • Coordinates interactive tasks where humans submit forms, upload documents, or wait for agency review
  • Integrates payment gateways for fees and levies
  • Calls external agency services on the user's behalf
  • Renders dynamic UI driven by workflow state

This SDK provides all the infrastructure pieces to build such a system, while keeping your domain logic in your own application.

Packages

Package Purpose
artifact Versioned configuration registry — load workflow definitions, form schemas, and templates by ID (includes artifact/adapter, bridge adapters for domain types)
authn JWT validation, identity context injection, and HTTP middleware
authz Scope-based authorization middleware and predicates, decoupled from authn
cors CORS HTTP middleware
database GORM/PostgreSQL connection factory with pooling and health checks
httputil Shared HTTP response helpers for JSON payloads and correlation-ID-tagged API error bodies
notification Multi-channel notification router (SMS, email) with pluggable providers
pagination Standard pagination envelope and query parameter parsing
payment Pluggable payment gateway orchestration with webhook processing and idempotency
remote Registry-based outbound HTTP client with pluggable auth (API key, Bearer, OAuth2)
secret Secret-bearing config values (SecretRef) resolved from env, file, or literal sources
shared Small, dependency-free helpers (deep copy, nested map access, config validation) used across other modules
storage File storage abstraction (local filesystem and AWS S3) with presigned URLs
taskflow Micro-interactive task orchestration — the core engine for human-in-the-loop steps
temporal Temporal client factory
trace HTTP request trace propagation and context-based trace ID correlation
uiprojector Zone-based, metadata-driven UI rendering from workflow state and business data
workflow JSON DSL-driven Temporal workflow graph interpreter

Requirements

  • Go 1.26+
  • PostgreSQL (via GORM)
  • Temporal server (for workflow and task orchestration)

Installation

go get github.com/OpenNSW/core

Architecture Overview

flowchart TD
    Portal["User Portal / Frontend"]

    subgraph server["Your HTTP Server · authn / authz / cors"]
        DS["Domain Services"]
        SR["payment webhooks · storage routes"]
    end

    subgraph macrowf["workflow — macro DAG (Temporal)"]
        WF["JSON graph · START · TASK · GATEWAY · SPLIT · END"]
    end

    subgraph microwf["taskflow.TaskManager (Temporal)"]
        TM["micro workflows · human-in-the-loop steps"]
    end

    subgraph pluginset["Subtask Plugins"]
        P["USER_INPUT · PAYMENT · EXTERNAL_REVIEW · API_CALL · custom"]
    end

    SS["payment · remote · notification · storage"]
    AR[("artifact registry<br>workflow defs · task templates<br>form schemas · render templates")]

    Portal -->|HTTP| server
    DS -->|StartWorkflow| macrowf
    server -->|"GetTaskRenderInfo / CompleteTaskStep"| microwf
    macrowf -->|TASK node reached| microwf
    microwf --> pluginset
    pluginset -->|use| SS
    macrowf -. loads .-> AR
    microwf -. loads .-> AR

The two-tier workflow design is central to single window systems:

  1. Macro workflow (the workflow package) — a long-lived Temporal workflow that represents the full service application (e.g. an export permit). It moves through TASK nodes, GATEWAY nodes, and SPLIT nodes according to a JSON graph definition.
  2. Micro workflow (the taskflow package) — each TASK node spawns a short-lived Temporal workflow that presents one interactive step to the user (a form, a payment, an external review). When the user completes the step the micro workflow signals the macro workflow to continue.

Full Wiring Example

The following shows how to assemble the components into a working application (condensed from the reference implementation pattern):

func Build(cfg *Config) (*App, error) {
    // 1. Database
    db, err := database.New(cfg.Database)

    // 2. Artifact registry — one loader is the single source of truth
    artifactLoader, _ := local.New(local.Config{Root: "configs"})
    registry := artifact.NewRegistry(artifactLoader)
    manifest, _ := artifact.LoadManifest(ctx, artifactLoader) // reads configs/manifest.json
    artifact.RegisterFromConfig(registry, manifest)

    // 3. Payment
    paymentRepo := NewPaymentRepo(db)
    paymentRegistry, _ := payment.NewRegistry("configs/payment_methods.json", map[string]payment.Factory{
        "govpay": govpay.NewGovPayGateway,
    })
    paymentService := payment.NewPaymentService(paymentRepo, paymentRegistry)

    // 4. Temporal client
    temporalClient, _ := temporal.NewClient(cfg.Temporal)

    // 5. Task subsystem
    taskStore := gormstore.New(db)
    pluginRegistry := plugins.NewRegistry()
    pluginRegistry.Register("USER_INPUT",      plugins.NewUserInputPlugin())
    pluginRegistry.Register("PAYMENT",         NewPaymentPlugin(paymentService))
    pluginRegistry.Register("EXTERNAL_REVIEW", NewExternalReviewPlugin(remoteManager))
    pluginRegistry.Register("MY_PLUGIN",       &MyPlugin{})

    assembler, _ := uiprojector.NewAssembler(templateProvider, uiprojector.DefaultProjectors())
    taskRenderer := zoneview.NewTaskRenderer(assembler)

    var tm *orchestrator.TaskManager
    microRunner := workflow.NewTemporalManager(
        temporalClient, "MICRO_WORKFLOW_QUEUE",
        func(p workflow.TaskPayload) (map[string]any, error) { return tm.StartSubTask(ctx, p) },
        func(wfID string, vars map[string]any) error { return tm.HandleTaskCompletion(ctx, wfID, vars) },
    )
    onTaskCompleted := func(parentWorkflowID, parentRunID, parentNodeID string, vars map[string]any) error {
        return consignmentService.HandleTaskCompletion(ctx, parentWorkflowID, parentRunID, parentNodeID, vars)
    }
    tm = orchestrator.NewTaskManager(taskStore, registry, pluginRegistry, microRunner, onTaskCompleted, taskRenderer)
    microRunner.StartWorker()

    // 6. Macro workflow runner
    macroRunner := workflow.NewTemporalManager(
        temporalClient, "INTERPRETER_TASK_QUEUE",
        onMacroTaskActivation, onMacroCompletion,
    )
    macroRunner.StartWorker()

    // 7. Auth
    authnManager, _ := authn.NewManager(userProfileSvc, cfg.Authn)
    authzr, _ := authz.New(func(ctx context.Context) (authz.Principal, bool) {
        ac := authn.GetAuthContext(ctx)
        return ac, ac != nil
    })

    // 8. HTTP
    mux := http.NewServeMux()
    withAuth := authnManager.RequireAuthMiddleware()
    mux.Handle("GET /api/v1/tasks/{id}",  withAuth(authzr.RequireScope("tasks:read")(getTaskHandler(tm))))
    mux.Handle("POST /api/v1/tasks/{id}", withAuth(authzr.RequireScope("tasks:write")(submitTaskHandler(tm))))
    mux.Handle("POST /api/v1/payments/{gatewayId}/webhook", webhookHandler(paymentService))

    return &App{Handler: cors.CORS(cfg.CORS)(mux)}, nil
}

Contributing

Contributions are welcome. See CONTRIBUTING.md for local setup, hooks, the Apache-2.0 license-header policy, and commit conventions.

After cloning, install tools and enable git hooks in one step:

make setup

License

See LICENSE.

Directories

Path Synopsis
loaders
Package loaders selects and constructs the core/artifact Loader used to fetch artifacts (workflow definitions, templates, manifests) at startup.
Package loaders selects and constructs the core/artifact Loader used to fetch artifacts (workflow definitions, templates, manifests) at startup.
loaders/github
Package github provides an artifact Loader that fetches bytes from a GitHub repository over the REST Contents API, using only net/http (no GitHub SDK dependency).
Package github provides an artifact Loader that fetches bytes from a GitHub repository over the REST Contents API, using only net/http (no GitHub SDK dependency).
loaders/s3
Package s3 provides an artifact Loader that reads objects from an S3 bucket (or an S3-compatible store).
Package s3 provides an artifact Loader that reads objects from an S3 bucket (or an S3-compatible store).
testutil
Package testutil provides shared test helpers for packages that work with the artifact registry.
Package testutil provides shared test helpers for packages that work with the artifact registry.
authn module
authz module
database module
httputil module
pagination module
payment module
remote module
secret module
shared module
storage module
taskflow
trace module
uiprojector module
Package engine implements a Temporal-based graph interpreter workflow engine.
Package engine implements a Temporal-based graph interpreter workflow engine.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL