Event Types
The Tech Strategy Tool processes events across 5 entity categories plus system events. All events are submitted via POST /api/events and processed by the event processor.
Entity creation, deletion, name/description updates, and reordering are handled by generic polymorphic events (create_entity, delete_entity, update_name, update_description, reorder_entity) that work across all entity types via the required targetType field.
Quick Reference
Section titled “Quick Reference”| Event | Category | Description |
|---|---|---|
create_entity | Generic | Create any entity (team, group, principle, objective, initiative) |
delete_entity | Generic | Delete any entity with cascading side effects |
update_name | Generic | Rename any named entity |
update_description | Generic | Update the description of any described entity |
reorder_entity | Generic | Change the position of any orderable entity |
update_team_color | Team | Change a team’s color |
assign_objective_to_group | Objective | Assign an objective to a group |
remove_objective_from_group | Objective | Remove an objective from its group |
assign_principle_to_objective | Objective | Link a principle to an objective |
remove_principle_from_objective | Objective | Remove a principle link from an objective |
update_initiative_progress | Initiative | Set an initiative’s completion percentage |
set_initiative_jira_key | Initiative | Set or update the Jira issue key |
remove_initiative_jira_key | Initiative | Clear the Jira issue key |
restore_history | System | Restore the strategy to a previous point in time |
import_team | System | Audit marker for a bulk team import |
Event Structure
Section titled “Event Structure”Every event submission includes:
| Field | Type | Description |
|---|---|---|
eventType | string | One of the recognized event types listed above |
targetId | string (GUID) | The entity being acted upon (see conventions below) |
targetType | string | Required for generic events: "Team", "Group", "Principle", "Objective", or "Initiative" |
data | object | Key-value pairs specific to the event type |
lastSeenSequence | long (optional) | For conflict detection on supported field edits |
TargetId conventions
Section titled “TargetId conventions”| Event | TargetId Meaning |
|---|---|
create_entity | Parent entity ID (team ID for groups/principles/objectives; objective ID for initiatives); null for teams |
| All other events | The entity being modified or deleted |
restore_history | (not set) |
import_team | (not set — generated internally) |
For create_entity, the new entity’s ID is always in data.id.
Field Limits
Section titled “Field Limits”All text fields are validated server-side against maximum lengths. Exceeding a limit causes the event to be rejected.
| Field | Max Length |
|---|---|
| Team name | 100 |
| Team color | 7 (# + 6 hex digits) |
| Group name | 100 |
| Group description | 200 |
| Principle name | 300 |
| Principle description | 2000 |
| Objective name | 300 |
| Initiative name | 200 |
| Jira issue key | 50 |
Generic Events
Section titled “Generic Events”These five events work across all entity types. The targetType field is required and determines which entity kind the event applies to and which field limits are enforced.
create_entity
Section titled “create_entity”Creates a new entity of any type. Requires the admin role when targetType is "Team".
| Field | Type | Description |
|---|---|---|
targetType | string | Required. "Team", "Group", "Principle", "Objective", or "Initiative" |
targetId | GUID | Parent entity ID (null for teams) |
| Data Field | Required | Description |
|---|---|---|
id | Yes | GUID for the new entity |
name | Yes | Display name (max length depends on entity type) |
description | No | Description text (Groups, Principles, Objectives only) |
color | No | Hex color code for teams only (e.g., #3498db) |
groupId | No | Group assignment for objectives only |
create_entity decomposes into multiple stored events: the create_entity itself plus a derived update_name event (and optionally update_description, update_team_color, and/or assign_objective_to_group). Each is stored separately in the event log.
{ "eventType": "create_entity", "targetType": "Group", "targetId": "<teamId>", "data": { "id": "a1b2c3d4-...", "name": "Infrastructure", "description": "Platform and tooling objectives" }}delete_entity
Section titled “delete_entity”Deletes any entity. Requires the admin role when targetType is "Team".
| Field | Type | Description |
|---|---|---|
targetType | string | Required. Entity type to delete |
targetId | GUID | The entity to delete |
No data fields required.
Cascade effects:
- Team: deletes all groups, principles, objectives, and initiatives
- Group: objectives in the group are unassigned (not deleted); emits
remove_objective_from_group+delete_entityas derived events - Principle: removed from all objectives that reference it; emits
remove_principle_from_objectivefor each affected objective +delete_entityas derived events. Cascadecard-changednotifications are emitted for affected objectives. - Objective: deletes all initiatives
- Initiative: removed from parent objective
update_name
Section titled “update_name”Renames any entity that implements INamedEntity (Team, Group, Principle, Objective, Initiative). Requires the admin role when targetType is "Team". Supports conflict detection.
| Field | Type | Description |
|---|---|---|
targetType | string | Required. Entity type being renamed |
targetId | GUID | The entity to rename |
| Data Field | Required | Description |
|---|---|---|
name | Yes | New name. Max length: Team/Group → 100, Objective/Principle → 300, Initiative → 200 |
update_description
Section titled “update_description”Updates the description of any entity that implements IDescribedEntity (Group, Principle, Objective). Supports conflict detection.
| Field | Type | Description |
|---|---|---|
targetType | string | Required. Entity type being updated |
targetId | GUID | The entity to update |
| Data Field | Required | Description |
|---|---|---|
description | Yes | New description (may be empty to clear). Max length: Group → 200, Principle → 2000 |
reorder_entity
Section titled “reorder_entity”Changes the position of any orderable entity (Group, Principle, Objective, Initiative). Teams cannot be reordered.
| Field | Type | Description |
|---|---|---|
targetType | string | Optional. Entity type — inferred from entity if omitted |
targetId | GUID | The entity to reorder |
| Data Field | Required | Description |
|---|---|---|
index | Yes | New zero-based target position (clamped to valid range; must be a valid integer) |
No-op if the entity is already at the requested position (after clamping).
Team Events
Section titled “Team Events”Team events require the admin role. Non-admin users receive a 403 response.
Team creation and deletion are handled by create_entity / delete_entity with targetType: "Team".
update_team_color
Section titled “update_team_color”Updates a team’s color. Validated via regex ^#[0-9A-Fa-f]{6}$. Supports conflict detection.
| Data Field | Required | Description |
|---|---|---|
color | Yes | New hex color code (e.g., #3498db) |
targetId is the team to update.
Group Events
Section titled “Group Events”Group creation, deletion, renaming, and reordering are handled by generic events with targetType: "Group".
Principle Events
Section titled “Principle Events”Principle creation, deletion, renaming, description updates, and reordering are handled by generic events with targetType: "Principle".
Objective Events
Section titled “Objective Events”Objective creation and deletion are handled by create_entity / delete_entity with targetType: "Objective".
assign_objective_to_group
Section titled “assign_objective_to_group”Assigns an objective to a group. The group must exist in the same team. The objective is relocated to the end of the target group’s slice.
| Data Field | Required | Description |
|---|---|---|
groupId | Yes | GUID of the target group |
targetId is the objective.
remove_objective_from_group
Section titled “remove_objective_from_group”Removes an objective from its current group, moving it to the ungrouped section.
No data fields required. targetId is the objective.
assign_principle_to_objective
Section titled “assign_principle_to_objective”Links a principle to an objective.
| Data Field | Required | Description |
|---|---|---|
principleId | Yes | GUID of the principle to link |
targetId is the objective.
remove_principle_from_objective
Section titled “remove_principle_from_objective”Removes a principle reference from an objective. The principle itself is not deleted.
| Data Field | Required | Description |
|---|---|---|
principleId | Yes | GUID of the principle to unlink |
targetId is the objective.
Objective reordering is handled by reorder_entity with targetType: "Objective" (index is group-slice-relative).
Initiative Events
Section titled “Initiative Events”Initiative creation and deletion are handled by create_entity / delete_entity with targetType: "Initiative".
update_initiative_progress
Section titled “update_initiative_progress”Updates an initiative’s progress percentage. Supports conflict detection. The objective’s total progress bar recalculates automatically.
| Data Field | Required | Description |
|---|---|---|
progress | Yes | Completion percentage (0-100 inclusive, integer) |
targetId is the initiative.
set_initiative_jira_key
Section titled “set_initiative_jira_key”Sets or updates the Jira issue key for an initiative. No conflict detection.
| Data Field | Required | Description |
|---|---|---|
jiraKey | Yes | Jira issue key (e.g., PROJ-123, max 50) |
targetId is the initiative.
remove_initiative_jira_key
Section titled “remove_initiative_jira_key”Clears the Jira issue key from an initiative. No-op if the key is already null.
No data fields required. targetId is the initiative.
Initiative reordering is handled by reorder_entity with targetType: "Initiative".
System Events
Section titled “System Events”restore_history
Section titled “restore_history”Restores the system state to a previous point in time. Requires the admin role.
| Data Field | Required | Description |
|---|---|---|
restoreToSequence | Yes | Sequence number to restore to |
targetId is null. This event is always recorded as applied in the log (it serves as a marker). The actual state restoration is handled by the API layer after the event is logged.
import_team
Section titled “import_team”An audit marker automatically inserted by POST /api/teams/import. This event is never submitted directly by clients — the import endpoint generates it internally.
| Data Field | Description |
|---|---|
sourceTeamId | Original team ID from the export |
sourceTeamName | Original team name from the export |
exportedAt | Timestamp when the export was created |
eventCount | Number of events in the import batch |
targetId is null. targetType is null.
Conflict Detection
Section titled “Conflict Detection”Three field-edit event types support conflict detection via lastSeenSequence. The processor uses the HasConflict helper to compare the request’s lastSeenSequence against the field’s current NameSequence, DescriptionSequence, or FieldSequences["progress"] on the entity. If the field was modified since the client’s last read, the event is rejected.
| Event Type | Field Checked |
|---|---|
update_name | NameSequence on the target entity |
update_description | DescriptionSequence on the target entity |
update_initiative_progress | progress key in FieldSequences |
update_team_color | color key in FieldSequences |
All other event types ignore lastSeenSequence even if provided.
On conflict rejection, the response includes:
| Field | Value |
|---|---|
status | "rejected" |
rejectionReason | Description of the conflict |
conflictingServerValue | The current server value the client is out of sync with |
On successful application of a field-edit event, the response includes:
| Field | Value |
|---|---|
status | "applied" |
previousValue | The field’s value before the change (for history) |
See Conflict Resolution for the full design rationale and client-side handling.
No-Op Detection
Section titled “No-Op Detection”All update events compare the new value against the current value (exact match). If they are identical, the processor returns a no-op result — no event is persisted and no SSE notification is broadcast. The API returns "no_change" as the status.
Envelope Validation
Section titled “Envelope Validation”Before reaching the event processor, the API layer validates the request envelope:
eventTypemust be non-empty and one of the recognized types (fromEventTypes.All)targetIdis required for all event types exceptcreate_entity,restore_history, andimport_team(listed inEventTypes.NoTargetIdRequired)targetTypeis required forcreate_entity,delete_entity,update_name, andupdate_description; it is optional forreorder_entity(inferred from the entity if omitted)
Invalid envelopes receive a 400 Bad Request response. This is distinct from domain rejections (200 OK with status: "rejected"), which indicate valid requests rejected by business rules.