Files
member-console/internal/workflows
cgalo5758 f8a3478f2a Rebuild the entitlement set Rules surface as a staged batch
The Rules section is one record table grouped by kind, Limit then
Boolean, on fixed columns, edited in place: Edit opens a row's controls
in their columns, Add rule opens a dense row above the table, and every
change is staged into a tray that lists the deltas with Undo and applies
them as one rule-change act. The reduction policy is a column of the
rule beside its limit. History shows counts only. Group rows are a quiet
heading rather than a divider, the maintainer's pick from four rounds of
outside-model ideation.

Dense rows align to the top and render each error under its control in
every form family (design D16), replacing the below-row error block; the
forms library gains the batch form (rows plus one tray) and the RowField
dense and label-hidden options. Migration 00019 records the governing
reduction policy on effect rows.

Archive staged-rule-changes with its spec updates (entitlement-set-
management, entitlement-set-history, entitlements, form-library,
form-conventions, ui-quality-gate). Screens accepted 2026-09-19.
2026-09-19 19:46:09 -05:00
..
2026-09-06 02:29:42 -05:00
2025-12-19 15:47:32 -06:00

Temporal Workflows

This directory contains the Temporal workflow definitions, activity implementations, and worker configuration for the member-console application.

Structure: Domain-Based

We use a Domain-Based (or Feature-Based) structure. Instead of grouping all workflows in one folder and all activities in another, we group them by business domain.

internal/workflows/
├── client.go           # Temporal client factory
├── worker.go           # Central worker setup & registration
├── queues/
│   └── queues.go       # Task Queue constants
├── common/             # Shared utilities & generic activities
│   └── options.go      # Standard ActivityOptions (retries, timeouts)
├── example/            # "Example" Domain
│   ├── workflow.go     # Workflow definition
│   └── activities.go   # Domain-specific activities
├── fedwiki/            # "FedWiki" Domain - Site provisioning
│   ├── README.md       # Domain documentation
│   ├── FARMMANAGER.md  # FarmManager API documentation
│   ├── workflow.go     # Create/Delete site workflows
│   ├── activities.go   # Site management activities
│   └── farmmanager_client.go  # HTTP client for FarmManager API
└── onboarding/         # (Future) "Onboarding" Domain
    ├── workflow.go
    └── activities.go

Adding a New Domain

  1. Create a directory: internal/workflows/<domain_name>/
  2. Define the Workflow: Create workflow.go in that directory.
  3. Define Activities: Create activities.go in that directory.
    • Define a struct (e.g., Activities) to hold dependencies (DB, Logger).
    • Implement a NewActivities constructor.
  4. Register: Go to internal/workflows/worker.go and add your new domain to the NewWorker function:
// internal/workflows/worker.go

// ... inside NewWorker ...
w.RegisterWorkflow(yourdomain.Workflow)
w.RegisterActivity(yourdomain.NewActivities(cfg.DB, cfg.Logger))

Usage

Starting the Worker

The worker is embedded in the main application but can be extracted later.

import "git.coopcloud.tech/wiki-cafe/member-console/internal/workflows"

// ... in your main setup ...
workerCfg := workflows.DefaultWorkerConfig(database, logger)
worker, err := workflows.NewWorker(temporalClient, workerCfg)
if err := worker.Start(); err != nil {
    // handle error
}
defer worker.Stop()

Starting a Workflow

import (
    "git.coopcloud.tech/wiki-cafe/member-console/internal/workflows"
    "git.coopcloud.tech/wiki-cafe/member-console/internal/workflows/queues"
    "git.coopcloud.tech/wiki-cafe/member-console/internal/workflows/example"
)

// ... inside an HTTP handler ...
workflowOpts := client.StartWorkflowOptions{
    ID:        "example-" + uuid.New().String(),
    TaskQueue: queues.Main,
}

we, err := temporalClient.ExecuteWorkflow(
    ctx,
    workflowOpts,
    example.Workflow, // Pass the function reference
    example.Input{Message: "hello"},
)