Skip to content

Commit 1f6026d

Browse files
authored
Merge pull request #560 from DevKor-github/feature/issue-525-domain-entity-decoupling
test: guard domain entity decoupling
2 parents 965ecab + 2ea6c8b commit 1f6026d

2 files changed

Lines changed: 57 additions & 1 deletion

File tree

CONTEXT.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ release, and feature discussions use the same terms.
55

66
## Language
77

8+
**OnTime User**:
9+
A person's OnTime account profile that owns schedules, places, preparation defaults, and notification preferences.
10+
_Avoid_: User identity, analytics subject, device
11+
12+
**Schedule**:
13+
A planned commitment with an intended time, destination place, travel time, and optional preparation plan.
14+
_Avoid_: Alarm, notification, calendar row
15+
16+
**Place**:
17+
The destination or location label attached to a Schedule.
18+
_Avoid_: Route, address record, notification location
19+
20+
**Preparation**:
21+
An ordered plan of steps the user intends to complete before leaving for a Schedule.
22+
_Avoid_: Reminder, notification, alarm
23+
24+
**Preparation Step**:
25+
One named action in a Preparation with an expected duration.
26+
_Avoid_: UI row, checklist widget, notification step
27+
828
**Product Usage Event**:
929
A named record that a user performed a product-relevant action, excluding raw personal content.
1030
_Avoid_: User activity, tracking event, raw interaction log
@@ -123,6 +143,12 @@ _Avoid_: Notification, native alarm
123143

124144
## Relationships
125145

146+
- An **OnTime User** may own zero or more **Schedules**.
147+
- A **Schedule** has one **Place**.
148+
- A **Schedule** may use one **Preparation**.
149+
- A **Preparation** contains zero or more **Preparation Steps** in user-defined order.
150+
- A **Preparation Step** belongs to exactly one **Preparation**.
151+
- A **Schedule Notification** uses **Schedule** and **Preparation** timing, but is not itself a **Schedule** or **Preparation**.
126152
- A **Product Usage Event** may describe a schedule, preparation, notification, alarm, onboarding, or account action without storing the user's raw schedule names, notes, place names, credentials, tokens, or free text.
127153
- First-release **Product Usage Events** are **Workflow Milestone Events**, not every tap or raw navigation step.
128154
- First-release **Workflow Milestone Events** cover analytics preference, onboarding, authentication, schedule, notification permission, alarm, and schedule-finish outcomes.
@@ -173,8 +199,14 @@ _Avoid_: Notification, native alarm
173199
> **Dev:** "Should the analytics event include the schedule note so we can understand why users are late?"
174200
> **Domain expert:** "No. A **Product Usage Event** can say a schedule was finished late, but it must not include the user's raw note."
175201
202+
> **Dev:** "Can a **Schedule Notification** replace the **Schedule** if the user taps it?"
203+
> **Domain expert:** "No. The **Schedule Notification** only prompts preparation for the **Schedule**; the **Schedule** remains the planned commitment."
204+
176205
## Flagged ambiguities
177206

207+
- "User" was overloaded as both the human actor and stored profile; resolved: use **OnTime User** for the account/profile concept and plain user only for the person performing an action.
208+
- "Schedule" was used near notification and alarm flows; resolved: a **Schedule** is the planned commitment, while notifications and alarms are delivery experiences for preparation timing.
209+
- "Preparation state" was ambiguous between step progress and display styling; resolved: **Preparation Step** progress belongs to preparation language, while visual labels should not redefine the domain.
178210
- "User activities" was used broadly; resolved: the canonical term is **Product Usage Event**, and raw personal content is out of scope.
179211
- "Analytics" was used to include all possible purposes; resolved: marketing and personalization are deferred, not first-release purposes.
180212
- "User identity" for analytics was ambiguous; resolved: analytics uses a **Pseudonymous Analytics Subject**, not directly identifying user data.

test/domain/entities/domain_entity_boundary_test.dart

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ void main() {
66
test('domain entities do not import lower architectural layers', () {
77
final domainEntityDirectory = Directory('lib/domain/entities');
88
final forbiddenImportPattern = RegExp(
9-
r'''import\s+['"](?:(?:package:on_time_front/)|/)?(?:core|data|presentation)/''',
9+
r'''import\s+['"](?:(?:package:on_time_front/)|(?:\.\./)+|/)?(?:core|data|presentation)/''',
1010
);
1111

1212
final violations = domainEntityDirectory
@@ -26,4 +26,28 @@ void main() {
2626

2727
expect(violations, isEmpty);
2828
});
29+
30+
test('domain entities do not expose persistence mapper methods', () {
31+
final domainEntityDirectory = Directory('lib/domain/entities');
32+
final legacyMapperMethodPattern = RegExp(
33+
r'''\b(?:fromModel|toModel|from[A-Za-z0-9_]*Model|to[A-Za-z0-9_]*Model|fromScheduleWithPlaceModel|toScheduleModel|toScheduleWithPlaceModel|toPreparationUserModel)\b''',
34+
);
35+
36+
final violations = domainEntityDirectory
37+
.listSync()
38+
.whereType<File>()
39+
.where((file) => file.path.endsWith('.dart'))
40+
.where((file) => !file.path.endsWith('.freezed.dart'))
41+
.expand((file) {
42+
final lines = file.readAsLinesSync();
43+
return [
44+
for (var index = 0; index < lines.length; index++)
45+
if (legacyMapperMethodPattern.hasMatch(lines[index]))
46+
'${file.path}:${index + 1}: ${lines[index].trim()}',
47+
];
48+
})
49+
.toList();
50+
51+
expect(violations, isEmpty);
52+
});
2953
}

0 commit comments

Comments
 (0)