Content: a uniqueness rule per state, so a teacher cannot time in twice
- Dominant language
- C#
- Stars
- 6
- Forks
- 7
- Avg merge
- 4h 21m
- Merged PRs (30d)
- 307
Description
Arnel, 14 September 2026, the teacher time clock: Time in creates a `timeEntry`, Time out is a `ClockOut` transition. Nothing stops a teacher from clicking Time in twice and holding two open entries, and a workflow cannot prevent it because it runs after the save commits.
That is the same shape as the counter floor (#808): a rule that must hold inside the write. Today it needs a lifecycle hook in a module.
## Change
A declarative uniqueness rule on a content type, checked inside the write transaction:
```json
{ "uniqueness": [ { "name": "OneOpenEntryPerTeacher", "fields": ["$createdBy"], "whenState": "Open" } ] }
```
- `fields`: data fields or `$createdBy`, compared exactly.
- `whenState`: optional; the rule only counts entries in that lifecycle state, so a closed entry frees the slot.
- Enforced on create, update and on a transition into the state, under a lock so two concurrent saves cannot both pass.
- Refused with a 409 naming the rule and the entry already holding it (its id only, when the caller may read it).
- Validated when the type is saved: the fields exist, the state exists.
## Done when
- A second Time in while one entry is Open is a 409; after ClockOut a new Time in succeeds.
- Two concurrent creates produce exactly one entry, proven by a test that runs them in parallel.
- A type without the rule behaves as before.
## Where it lives
Core: content validation inside the write transaction. A rule that must hold in the write cannot be a module's job by default.
Contributor guide
Research direction
Start at the core content validation inside the write transaction and trace the existing lifecycle hook/module used by the Time in and ClockOut flow. Add coverage for repeated, closed-entry, type-validation, no-rule, and parallel-create cases; done means the listed 409 and concurrency behaviors hold without changing types that have no rule.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100