Diagram
100%

Drag to pan · Scroll to zoom · + / − to zoom · 0 to fit · Esc to close

Skip to content

13. Operations Capstone ​

The capstone joins Directory, Access, Workflow, and Ops into one effective domain program while keeping the Ops Flutter application independently deployable.

The Operations model connects shared people, access rules, and work definitions.

1. Define the module graph ​

dart
const directoryRef = ModuleRef('directory');
const accessRef = ModuleRef('access');
const workflowRef = ModuleRef('workflow');
const opsRef = ModuleRef('ops');

const companyRef = EntityRef(module: directoryRef, name: 'company');
const siteRef = EntityRef(module: directoryRef, name: 'site');
const userRef = EntityRef(module: directoryRef, name: 'user');
const roleRef = EntityRef(module: accessRef, name: 'role');
const roleAssignmentRef = EntityRef(
  module: accessRef,
  name: 'role_assignment',
);
const taskRef = EntityRef(module: workflowRef, name: 'task');
const areaRef = EntityRef(module: opsRef, name: 'area');
const areaGovernanceRef = FacetRef(entity: areaRef, name: 'governance');

final directoryModule = Module(
  name: 'directory',
  title: 'Directory',
  version: '1.0.0',
  entities: [companyEntity, siteEntity, userEntity],
  exports: const [
    EntityExport(entity: companyRef),
    EntityExport(entity: siteRef),
    EntityExport(entity: userRef),
  ],
);

final accessModule = Module(
  name: 'access',
  title: 'Access',
  version: '1.0.0',
  entities: [roleEntity, permissionEntity, roleAssignmentEntity],
  dependencies: const [directoryRef],
  exports: const [
    EntityExport(entity: roleRef),
    EntityExport(entity: roleAssignmentRef),
  ],
);

final workflowModule = Module(
  name: 'workflow',
  title: 'Workflow',
  version: '1.0.0',
  entities: [taskEntity],
  exports: const [
    ActionExport(
      ActionRef(
        facet: FacetRef(entity: taskRef, name: 'lifecycle'),
        name: 'create',
      ),
    ),
  ],
);

2. Declare the Ops entity ​

dart
final areaEntity = Entity(
  name: 'area',
  title: 'Area',
  pluralTitle: 'Areas',
  description: 'Controlled physical spaces within an operating site.',
  db: const EntityDb(
    tableName: 'areas',
    expectedRows: DbRowScale.medium,
    readPattern: DbReadPattern.runtimeList,
    queryPatterns: [
      QueryPattern.filter,
      QueryPattern.search,
      QueryPattern.sort,
    ],
  ),
  tenantField: AreaFields.tenantId,
  history: History.revisions(),
  uniqueKeys: const [
    UniqueKey([AreaFields.tenantId, AreaFields.code]),
  ),
  ui: const EntityUI(
    icon: UIIcon('location'),
    routePrefix: '/areas',
    list: ListUI(
      layouts: [
        ListLayoutUI.table(
          columns: [
            TableColumnUI(field: AreaFields.code, required: true),
            TableColumnUI(field: AreaFields.name),
            TableColumnUI(field: AreaFields.areaType),
            TableColumnUI(
              field: AreaFields.status,
              appearance: UIColumnAppearance.status,
            ),
          ],
        ),
        ListLayoutUI.grid(
          content: CardContentUI(
            titleField: AreaFields.name,
            subtitleField: AreaFields.code,
            statusField: AreaFields.status,
          ),
        ),
      ],
      query: QueryUI(maxSortLevels: 3, maxGroupLevels: 2),
    ),
    editors: [
      EditorUI(
        name: 'area-editor',
        title: 'Area',
        presentation: EditorPresentation.adaptive,
        form: FormUI.derived(),
      ),
    ],
    details: [
      DetailUI(
        name: 'summary',
        title: 'Summary',
        kind: DetailUIKind.summary,
      ),
      DetailUI(
        name: 'history',
        title: 'History',
        kind: DetailUIKind.history,
      ),
      DetailUI(
        name: 'audit',
        title: 'Audit',
        kind: DetailUIKind.audit,
      ),
    ],
    actionPlacements: [
      ActionPlacementUI(
        placement: ActionPlacementRef.recordHeader,
        actions: [
          ActionUIRef(
            ActionRef(facet: areaGovernanceRef, name: 'activate'),
          ),
          ActionUIRef(
            ActionRef(facet: areaGovernanceRef, name: 'retire'),
          ),
        ],
      ),
    ],
  ),
  facets: [
    IdentityFacet(
      fields: const [
        AreaFields.code,
        AreaFields.name,
        AreaFields.description,
      ],
    ),
    Facet(
      name: 'tenancy',
      fields: const [AreaFields.tenantId, AreaFields.siteId],
    ),
    areaGovernanceFacet,
    areaHierarchyFacet,
  ],
);

The field tokens carry enum labels, reference hints, input capability, query posture, and the name-to-code autofill developed in earlier chapters.

3. Govern activation ​

dart
enum AreaStatus { draft, active, retired }

final class ActivateArea extends Action {
  const ActivateArea()
    : super(
        name: 'activate',
        title: 'Activate',
        consistency: ConsistencyMode.strict,
        rules: [
          Rule(
            id: 'ops.area.activate.grant',
            kind: RuleKind.access,
            test: HostFact<bool>('actor.holds', [
              'action',
              'ops.area.governance.activate',
            ]),
          ),
          Rule(
            id: 'ops.area.activate.qualified',
            kind: RuleKind.access,
            test: HostFact<bool>('actor.qualified', [
              ['training.gmp_current'],
              'site',
            ]),
          ),
          Rule(
            id: 'ops.area.activate.checklist',
            kind: RuleKind.evidence,
            test: HostFact<bool>('evidence.present', [
              'area_release_checklist',
            ]),
          ),
        ],
        capture: ActionCapture(
          evidence: [
            Evidence(name: 'actor', kind: EvidenceKind.actor),
            Evidence(name: 'signature', kind: EvidenceKind.signature),
            Evidence(name: 'reason', kind: EvidenceKind.reason),
            releaseChecklist,
          ],
          snapshot: ContextSnapshot(
            targets: [
              SnapshotTarget(
                name: 'policy.area_release',
                sourceRef: 'policy.ops.area_release',
              ),
              SnapshotTarget(
                name: 'master.area_category',
                strategy: SnapshotStrategy.value,
                sourceRef: 'ops.area.category',
              ),
            ],
          ),
        ),
        emits: [
          ActionEvent(
            name: 'ops.area.activated',
            kind: ActionEventKind.stateChanged,
          ),
        ],
      );
}

final class RetireArea extends Action {
  const RetireArea() : super(name: 'retire');
}

abstract final class AreaActions {
  static const activate = ActivateArea();
  static const retire = RetireArea();
}

final areaGovernanceFacet = Facet(
  name: 'governance',
  lifecycle: Lifecycle<AreaStatus>.typed(
    stateField: AreaFields.status,
    initialState: AreaStatus.draft,
    transitions: const [
      Transition.typed(
        from: AreaStatus.draft,
        to: AreaStatus.active,
        action: AreaActions.activate,
      ),
      Transition.typed(
        from: AreaStatus.active,
        to: AreaStatus.retired,
        action: AreaActions.retire,
      ),
    ],
  ),
  actions: const [AreaActions.activate, AreaActions.retire],
);

4. Assemble the Ops module ​

dart
final opsModule = Module(
  name: 'ops',
  title: 'Operations',
  version: '1.0.0',
  entities: [
    areaCategoryEntity,
    areaEntity,
    equipmentCategoryEntity,
    equipmentEntity,
    activityEntity,
    activityArtifactEntity,
    checklistTemplateEntity,
  ],
  dependencies: const [directoryRef, accessRef, workflowRef],
  taskTemplates: [areaActivationReviewTask],
  db: const ModuleDb(
    auditMode: DbAuditMode.full,
    rlsMode: DbRlsMode.enforced,
    outboxMode: DbOutboxMode.schema,
    retentionRef: 'gxp_10_years',
  ),
);

final pharmaBlueprint = Blueprint(
  name: 'vyrun_pharma',
  version: '1.0.0',
  modules: [
    directoryModule,
    accessModule,
    workflowModule,
    opsModule,
  ],
);

5. Type-check and compile ​

dart
final findings = BlueprintValidator.validate(pharmaBlueprint);
if (findings.isNotEmpty) {
  for (final finding in findings) {
    print('${finding.code} ${finding.path}: ${finding.message}');
  }
  throw StateError('Blueprint is invalid.');
}

final effective = pharmaBlueprint.assemble();
final database = DbCompiler.compile(pharmaBlueprint);

print(effective.entity('ops.area')?.originGraph);
print(database.toReport());

Review generated SQL, migrations, RLS/grants, reference integrity, indexes, audit/history, runtime records, and outbox before installation.

6. Assemble app surfaces ​

dart
const opsAppDescriptor = AppDescriptor(
  name: 'ops',
  title: 'Operations',
);

final opsBlueprint = BlueprintAssembler.assemble(
  name: 'ops',
  title: 'Operations',
  version: '1.0.0',
  blueprint: pharmaBlueprint,
  descriptors: const [opsAppDescriptor],
  entityUI: const AppEntityUIScope.selected(
    moduleRefs: ['ops'],
  ),
);

The assembled Blueprint still sees Directory and Access entities for references and policy resolution, but exposes only Ops entity UI and routes.

7. Prove one execution end to end ​

For a validation scenario:

  1. Seed company, site, actor, grant, qualification, area category, and area.
  2. Request ops.area.governance.activate.
  3. Inspect plan and preflight.
  4. Attach checklist evidence and signature context.
  5. Execute through the runtime adapter.
  6. Verify the state write, action record, rule trace, evidence manifest, domain event, audit projection, and outbox effect in one commit boundary.
  7. Inspect the durable action sequence, event stream sequence, and effect idempotency records.
  8. Repeat with an unqualified actor and prove that denial is retained.

Graduation checklist ​

You now have the mental model to read the

as a list of disconnected classes.

Next: Governed revisions and database inspection.