BaryoDev / BaryoDev/barakoCMS

Workflows: forEach, createEntry, transition, a without filter and a report step, so a nightly sweep is configuration

Open
#835 0 comments 0 reactions 0 assignees View on GitHub
core module
Dominant language
C#
Stars
6
Forks
7
Avg merge
4h 42m
Merged PRs (30d)
307

Description

Arnel, 14 September 2026: every day at midnight a sweep finds teachers with a missing time out and teachers with no activity, records who is absent, and generates the day's report. The schedule trigger is #255. Passing values between steps is #575. This issue is the steps such a workflow still cannot express.

How a barako expert would build it, once these exist:

```text
trigger schedule 00:00 tenant time (#255), day = {{schedule.previousAt | date "yyyy-MM-dd"}}
1 query openEntries: timeEntry in state Open created on {{day}}
2 forEach openEntries
transition MissingTimeOut (a named transition, so it is audited and permissioned)
3 query absent: teacher entries with NO timeEntry created on {{day}} (the "without" filter below)
4 forEach absent
createEntry absence { Teacher: {{item.id}}, Date: {{day}}, Reason: "No activity" }
5 report attendance for {{day}}: counts and the rows from steps 1 and 3, as CSV, stored in Files
6 email template "daily-attendance" (#829) to the principal, attaching the report (#806)
```

## Change

- **`forEach` step.** Runs its inner steps once per row of a previous step's output, with `{{item.Field}}`. Capped per run (configurable, default 1000), with each item's outcome recorded so one failure does not hide the rest and a retry skips items already done.
- **`createEntry` action.** Creates an entry of a named type from placeholders, validated like any write, as the workflow's service identity. Today only `CreateTask` and `UpdateField` write.
- **`transition` action.** Runs a named transition on the entry in scope, so an automatic close is the same audited move a person would make.
- **A "without" filter on saved queries.** Rows of type A with no row of type B referencing them within a filter, for example teachers without a time entry on a day. Evaluated in the database, never by loading both lists.
- **`report` action.** Turns a step's rows into a CSV (and a PDF once #585 exists) stored in Files, with Public-field masking, and outputs the file id for the email step.
- **Safe to run twice.** Absences use the uniqueness rule (#830) on Teacher plus Date, so a catch-up run or a retry never records a second absence for the same day.

## Where a service is the better answer

When absence depends on rules the client owns, such as approved leave, holidays, part-time schedules or substitutes, step 3 becomes a `publish` to a service (#831) that computes the absent list and writes the absences back. The workflow stays the same shape.

## Done when

- A test with a fake clock runs the sweep for a day with one open entry, one complete entry and one teacher with no activity: one MissingTimeOut transition, one absence, a CSV in Files with both rows, one email.
- Running the same due time again changes nothing.

## Where it lives

Core: `forEach`, `createEntry` and `transition` actions and the "without" filter in the saved query runner. Module: the `report` step belongs to the Reports module (#837), registered through the public `IWorkflowAction` extension point.

Contributor guide

Open the contributing guide

Research direction

Start with the saved query runner for the "without" filter, the core workflow actions, and the Reports module's public IWorkflowAction extension point. Use the described fake-clock sweep test as the completion check: one transition, one absence, a CSV in Files, one email, and no changes when the same due time runs again.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend, databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.