@appiq/flutter-workflow 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +163 -0
- package/README.md +3 -1
- package/agents/claude/cubit-agent.md +91 -4
- package/agents/claude/data-agent.md +129 -15
- package/agents/claude/domain-agent.md +104 -4
- package/agents/claude/initial-flow-agent.md +55 -0
- package/agents/claude/orchestrator.md +17 -3
- package/agents/claude/po-agent.md +17 -3
- package/agents/claude/security-agent.md +109 -4
- package/agents/claude/test-agent.md +17 -3
- package/agents/claude/ui-agent.md +107 -5
- package/agents/cubit-agent.md +1 -1
- package/agents/data-agent.md +21 -14
- package/agents/domain-agent.md +1 -1
- package/agents/initial-flow-agent.md +342 -0
- package/agents/po-agent.md +1 -1
- package/agents/security-agent.md +1 -1
- package/agents/test-agent.md +1 -1
- package/agents/ui-agent.md +1 -1
- package/bin/cli.js +54 -1
- package/package.json +6 -2
- package/templates/additional_cubit_req.md +357 -0
- package/templates/additional_data_req.md +480 -0
- package/templates/additional_domain_req.md +431 -0
- package/templates/additional_ui_req.md +205 -0
@@ -0,0 +1,431 @@
|
|
1
|
+
# Additional Domain Requirements - Business Logic Extensions
|
2
|
+
|
3
|
+
This template defines additional domain layer requirements, complex business rules, and domain service integrations.
|
4
|
+
|
5
|
+
## Advanced Business Rules
|
6
|
+
|
7
|
+
### Complex Validation Logic
|
8
|
+
```dart
|
9
|
+
class {Entity} extends Equatable {
|
10
|
+
final String id;
|
11
|
+
final String name;
|
12
|
+
final {EntityStatus} status;
|
13
|
+
final DateTime createdAt;
|
14
|
+
final DateTime? updatedAt;
|
15
|
+
|
16
|
+
const {Entity}({
|
17
|
+
required this.id,
|
18
|
+
required this.name,
|
19
|
+
required this.status,
|
20
|
+
required this.createdAt,
|
21
|
+
this.updatedAt,
|
22
|
+
});
|
23
|
+
|
24
|
+
// Advanced business rule validation
|
25
|
+
ValidationResult validateBusinessRules() {
|
26
|
+
final errors = <String>[];
|
27
|
+
|
28
|
+
// Custom business validation logic
|
29
|
+
if (name.trim().length < 3) {
|
30
|
+
errors.add('Name must be at least 3 characters long');
|
31
|
+
}
|
32
|
+
|
33
|
+
if (status == {EntityStatus}.archived && updatedAt == null) {
|
34
|
+
errors.add('Archived entities must have an updated timestamp');
|
35
|
+
}
|
36
|
+
|
37
|
+
// Time-based business rules
|
38
|
+
if (createdAt.isAfter(DateTime.now())) {
|
39
|
+
errors.add('Creation date cannot be in the future');
|
40
|
+
}
|
41
|
+
|
42
|
+
return ValidationResult(
|
43
|
+
isValid: errors.isEmpty,
|
44
|
+
errors: errors,
|
45
|
+
);
|
46
|
+
}
|
47
|
+
|
48
|
+
// Business logic for state transitions
|
49
|
+
{Entity} markAsCompleted() {
|
50
|
+
if (status == {EntityStatus}.completed) {
|
51
|
+
throw DomainException('Entity is already completed');
|
52
|
+
}
|
53
|
+
|
54
|
+
if (status == {EntityStatus}.archived) {
|
55
|
+
throw DomainException('Cannot complete archived entity');
|
56
|
+
}
|
57
|
+
|
58
|
+
return copyWith(
|
59
|
+
status: {EntityStatus}.completed,
|
60
|
+
updatedAt: DateTime.now(),
|
61
|
+
);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
```
|
65
|
+
|
66
|
+
### Cross-Entity Business Rules
|
67
|
+
```dart
|
68
|
+
class {Feature}DomainService {
|
69
|
+
// Complex business logic involving multiple entities
|
70
|
+
Future<Either<Failure, {ResultEntity}>> processComplexOperation({
|
71
|
+
required {Entity1} entity1,
|
72
|
+
required {Entity2} entity2,
|
73
|
+
required List<{Entity3}> entities3,
|
74
|
+
}) async {
|
75
|
+
// Validate cross-entity business rules
|
76
|
+
final validation = _validateCrossEntityRules(entity1, entity2, entities3);
|
77
|
+
if (!validation.isValid) {
|
78
|
+
return Left(ValidationFailure(validation.errors.join(', ')));
|
79
|
+
}
|
80
|
+
|
81
|
+
// Execute complex business logic
|
82
|
+
try {
|
83
|
+
final result = _executeBusinessLogic(entity1, entity2, entities3);
|
84
|
+
return Right(result);
|
85
|
+
} catch (e) {
|
86
|
+
return Left(DomainFailure('Business operation failed: ${e.toString()}'));
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
ValidationResult _validateCrossEntityRules(
|
91
|
+
{Entity1} entity1,
|
92
|
+
{Entity2} entity2,
|
93
|
+
List<{Entity3}> entities3,
|
94
|
+
) {
|
95
|
+
final errors = <String>[];
|
96
|
+
|
97
|
+
// Example: Entity1 and Entity2 compatibility check
|
98
|
+
if (entity1.type != entity2.compatibleType) {
|
99
|
+
errors.add('Entity1 type is not compatible with Entity2');
|
100
|
+
}
|
101
|
+
|
102
|
+
// Example: Quantity validation across entities
|
103
|
+
final totalQuantity = entities3.fold(0, (sum, e) => sum + e.quantity);
|
104
|
+
if (totalQuantity > entity1.maxCapacity) {
|
105
|
+
errors.add('Total quantity exceeds maximum capacity');
|
106
|
+
}
|
107
|
+
|
108
|
+
// Example: Status consistency check
|
109
|
+
if (entity1.isActive && entities3.any((e) => !e.isValid)) {
|
110
|
+
errors.add('Active Entity1 cannot contain invalid Entity3 items');
|
111
|
+
}
|
112
|
+
|
113
|
+
return ValidationResult(
|
114
|
+
isValid: errors.isEmpty,
|
115
|
+
errors: errors,
|
116
|
+
);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
```
|
120
|
+
|
121
|
+
## Advanced Use Cases
|
122
|
+
|
123
|
+
### Workflow Management Use Case
|
124
|
+
```dart
|
125
|
+
class Manage{Feature}WorkflowUseCase {
|
126
|
+
final {Feature}Repository repository;
|
127
|
+
final {Feature}DomainService domainService;
|
128
|
+
final NotificationService notificationService;
|
129
|
+
|
130
|
+
const Manage{Feature}WorkflowUseCase({
|
131
|
+
required this.repository,
|
132
|
+
required this.domainService,
|
133
|
+
required this.notificationService,
|
134
|
+
});
|
135
|
+
|
136
|
+
Future<Either<Failure, WorkflowResult>> execute({
|
137
|
+
required String workflowId,
|
138
|
+
required WorkflowAction action,
|
139
|
+
required Map<String, dynamic> context,
|
140
|
+
}) async {
|
141
|
+
try {
|
142
|
+
// Load current workflow state
|
143
|
+
final workflowResult = await repository.getWorkflow(workflowId);
|
144
|
+
if (workflowResult.isLeft()) {
|
145
|
+
return workflowResult.fold((l) => Left(l), (r) => throw Exception());
|
146
|
+
}
|
147
|
+
|
148
|
+
final workflow = workflowResult.getOrElse(() => throw Exception());
|
149
|
+
|
150
|
+
// Validate action is allowed in current state
|
151
|
+
final validationResult = domainService.validateWorkflowTransition(
|
152
|
+
workflow: workflow,
|
153
|
+
action: action,
|
154
|
+
context: context,
|
155
|
+
);
|
156
|
+
|
157
|
+
if (!validationResult.isValid) {
|
158
|
+
return Left(ValidationFailure(validationResult.errors.join(', ')));
|
159
|
+
}
|
160
|
+
|
161
|
+
// Execute workflow transition
|
162
|
+
final updatedWorkflow = domainService.executeWorkflowTransition(
|
163
|
+
workflow: workflow,
|
164
|
+
action: action,
|
165
|
+
context: context,
|
166
|
+
);
|
167
|
+
|
168
|
+
// Persist updated workflow
|
169
|
+
final saveResult = await repository.saveWorkflow(updatedWorkflow);
|
170
|
+
if (saveResult.isLeft()) {
|
171
|
+
return saveResult.fold((l) => Left(l), (r) => throw Exception());
|
172
|
+
}
|
173
|
+
|
174
|
+
// Send notifications if required
|
175
|
+
if (updatedWorkflow.requiresNotification) {
|
176
|
+
await notificationService.sendWorkflowNotification(updatedWorkflow);
|
177
|
+
}
|
178
|
+
|
179
|
+
return Right(WorkflowResult(
|
180
|
+
workflow: updatedWorkflow,
|
181
|
+
previousState: workflow.state,
|
182
|
+
newState: updatedWorkflow.state,
|
183
|
+
executedAt: DateTime.now(),
|
184
|
+
));
|
185
|
+
|
186
|
+
} catch (e) {
|
187
|
+
return Left(DomainFailure('Workflow execution failed: ${e.toString()}'));
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
```
|
192
|
+
|
193
|
+
### Batch Processing Use Case
|
194
|
+
```dart
|
195
|
+
class BatchProcess{Feature}UseCase {
|
196
|
+
final {Feature}Repository repository;
|
197
|
+
final {Feature}DomainService domainService;
|
198
|
+
|
199
|
+
Future<Either<Failure, BatchResult>> execute({
|
200
|
+
required List<String> entityIds,
|
201
|
+
required BatchOperation operation,
|
202
|
+
required Map<String, dynamic> parameters,
|
203
|
+
}) async {
|
204
|
+
final results = <String, Either<Failure, {Entity}>>[];
|
205
|
+
final errors = <String>[];
|
206
|
+
|
207
|
+
// Process entities in batches to manage memory
|
208
|
+
const batchSize = 50;
|
209
|
+
for (int i = 0; i < entityIds.length; i += batchSize) {
|
210
|
+
final batch = entityIds.skip(i).take(batchSize).toList();
|
211
|
+
|
212
|
+
// Load batch entities
|
213
|
+
final entitiesResult = await repository.getEntitiesByIds(batch);
|
214
|
+
if (entitiesResult.isLeft()) {
|
215
|
+
errors.add('Failed to load batch ${i ~/ batchSize + 1}');
|
216
|
+
continue;
|
217
|
+
}
|
218
|
+
|
219
|
+
final entities = entitiesResult.getOrElse(() => []);
|
220
|
+
|
221
|
+
// Process each entity in the batch
|
222
|
+
for (final entity in entities) {
|
223
|
+
try {
|
224
|
+
final processedEntity = await _processEntity(entity, operation, parameters);
|
225
|
+
results[entity.id] = Right(processedEntity);
|
226
|
+
} catch (e) {
|
227
|
+
results[entity.id] = Left(DomainFailure(e.toString()));
|
228
|
+
errors.add('Failed to process entity ${entity.id}: $e');
|
229
|
+
}
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
return Right(BatchResult(
|
234
|
+
totalProcessed: results.length,
|
235
|
+
successCount: results.values.where((r) => r.isRight()).length,
|
236
|
+
errorCount: results.values.where((r) => r.isLeft()).length,
|
237
|
+
results: results,
|
238
|
+
errors: errors,
|
239
|
+
));
|
240
|
+
}
|
241
|
+
}
|
242
|
+
```
|
243
|
+
|
244
|
+
## Domain Events System
|
245
|
+
|
246
|
+
### Domain Event Definition
|
247
|
+
```dart
|
248
|
+
abstract class DomainEvent extends Equatable {
|
249
|
+
final String eventId;
|
250
|
+
final DateTime occurredAt;
|
251
|
+
final String aggregateId;
|
252
|
+
final int aggregateVersion;
|
253
|
+
|
254
|
+
const DomainEvent({
|
255
|
+
required this.eventId,
|
256
|
+
required this.occurredAt,
|
257
|
+
required this.aggregateId,
|
258
|
+
required this.aggregateVersion,
|
259
|
+
});
|
260
|
+
}
|
261
|
+
|
262
|
+
class {Entity}CreatedEvent extends DomainEvent {
|
263
|
+
final {Entity} entity;
|
264
|
+
|
265
|
+
const {Entity}CreatedEvent({
|
266
|
+
required this.entity,
|
267
|
+
required String eventId,
|
268
|
+
required DateTime occurredAt,
|
269
|
+
required String aggregateId,
|
270
|
+
required int aggregateVersion,
|
271
|
+
}) : super(
|
272
|
+
eventId: eventId,
|
273
|
+
occurredAt: occurredAt,
|
274
|
+
aggregateId: aggregateId,
|
275
|
+
aggregateVersion: aggregateVersion,
|
276
|
+
);
|
277
|
+
|
278
|
+
@override
|
279
|
+
List<Object> get props => [entity, eventId, occurredAt, aggregateId, aggregateVersion];
|
280
|
+
}
|
281
|
+
```
|
282
|
+
|
283
|
+
### Aggregate Root with Events
|
284
|
+
```dart
|
285
|
+
abstract class AggregateRoot<T> extends Equatable {
|
286
|
+
final String id;
|
287
|
+
final int version;
|
288
|
+
final List<DomainEvent> _domainEvents = [];
|
289
|
+
|
290
|
+
AggregateRoot({
|
291
|
+
required this.id,
|
292
|
+
required this.version,
|
293
|
+
});
|
294
|
+
|
295
|
+
List<DomainEvent> get domainEvents => List.unmodifiable(_domainEvents);
|
296
|
+
|
297
|
+
void addDomainEvent(DomainEvent event) {
|
298
|
+
_domainEvents.add(event);
|
299
|
+
}
|
300
|
+
|
301
|
+
void clearDomainEvents() {
|
302
|
+
_domainEvents.clear();
|
303
|
+
}
|
304
|
+
|
305
|
+
void markEventsAsCommitted() {
|
306
|
+
_domainEvents.clear();
|
307
|
+
}
|
308
|
+
}
|
309
|
+
|
310
|
+
class {Entity}Aggregate extends AggregateRoot<{Entity}> {
|
311
|
+
final {Entity} entity;
|
312
|
+
|
313
|
+
{Entity}Aggregate({
|
314
|
+
required this.entity,
|
315
|
+
required String id,
|
316
|
+
required int version,
|
317
|
+
}) : super(id: id, version: version);
|
318
|
+
|
319
|
+
{Entity}Aggregate update{Entity}({
|
320
|
+
required String name,
|
321
|
+
required {EntityStatus} status,
|
322
|
+
}) {
|
323
|
+
final updatedEntity = entity.copyWith(
|
324
|
+
name: name,
|
325
|
+
status: status,
|
326
|
+
updatedAt: DateTime.now(),
|
327
|
+
);
|
328
|
+
|
329
|
+
// Add domain event
|
330
|
+
addDomainEvent({Entity}UpdatedEvent(
|
331
|
+
entity: updatedEntity,
|
332
|
+
previousEntity: entity,
|
333
|
+
eventId: const Uuid().v4(),
|
334
|
+
occurredAt: DateTime.now(),
|
335
|
+
aggregateId: id,
|
336
|
+
aggregateVersion: version + 1,
|
337
|
+
));
|
338
|
+
|
339
|
+
return {Entity}Aggregate(
|
340
|
+
entity: updatedEntity,
|
341
|
+
id: id,
|
342
|
+
version: version + 1,
|
343
|
+
);
|
344
|
+
}
|
345
|
+
|
346
|
+
@override
|
347
|
+
List<Object> get props => [entity, id, version];
|
348
|
+
}
|
349
|
+
```
|
350
|
+
|
351
|
+
## Advanced Repository Patterns
|
352
|
+
|
353
|
+
### Specification Pattern for Complex Queries
|
354
|
+
```dart
|
355
|
+
abstract class Specification<T> {
|
356
|
+
bool isSatisfiedBy(T candidate);
|
357
|
+
Specification<T> and(Specification<T> other);
|
358
|
+
Specification<T> or(Specification<T> other);
|
359
|
+
Specification<T> not();
|
360
|
+
}
|
361
|
+
|
362
|
+
class {Entity}ActiveSpecification extends Specification<{Entity}> {
|
363
|
+
@override
|
364
|
+
bool isSatisfiedBy({Entity} candidate) {
|
365
|
+
return candidate.status == {EntityStatus}.active;
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
369
|
+
class {Entity}CreatedAfterSpecification extends Specification<{Entity}> {
|
370
|
+
final DateTime date;
|
371
|
+
|
372
|
+
{Entity}CreatedAfterSpecification(this.date);
|
373
|
+
|
374
|
+
@override
|
375
|
+
bool isSatisfiedBy({Entity} candidate) {
|
376
|
+
return candidate.createdAt.isAfter(date);
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
// Extended repository interface
|
381
|
+
abstract class {Feature}Repository {
|
382
|
+
Future<Either<Failure, List<{Entity}>>> findBySpecification(
|
383
|
+
Specification<{Entity}> specification,
|
384
|
+
);
|
385
|
+
|
386
|
+
Future<Either<Failure, PaginatedResult<{Entity}>>> findPaginatedBySpecification(
|
387
|
+
Specification<{Entity}> specification,
|
388
|
+
PaginationParams pagination,
|
389
|
+
);
|
390
|
+
}
|
391
|
+
```
|
392
|
+
|
393
|
+
## Integration Requirements Checklist
|
394
|
+
|
395
|
+
### Business Logic Complexity
|
396
|
+
- [ ] Complex validation rules implemented
|
397
|
+
- [ ] Cross-entity business rules defined
|
398
|
+
- [ ] State transition logic validated
|
399
|
+
- [ ] Business invariants enforced
|
400
|
+
- [ ] Domain services for complex operations
|
401
|
+
|
402
|
+
### Use Case Extensions
|
403
|
+
- [ ] Workflow management use cases
|
404
|
+
- [ ] Batch processing capabilities
|
405
|
+
- [ ] Transaction management
|
406
|
+
- [ ] Event-driven architecture
|
407
|
+
- [ ] Saga pattern implementation (if needed)
|
408
|
+
|
409
|
+
### Domain Events
|
410
|
+
- [ ] Domain event definitions
|
411
|
+
- [ ] Aggregate root with event support
|
412
|
+
- [ ] Event publishing mechanism
|
413
|
+
- [ ] Event handlers for side effects
|
414
|
+
- [ ] Event store integration (if needed)
|
415
|
+
|
416
|
+
### Advanced Patterns
|
417
|
+
- [ ] Specification pattern for queries
|
418
|
+
- [ ] Domain service implementations
|
419
|
+
- [ ] Value object validations
|
420
|
+
- [ ] Repository extensions
|
421
|
+
- [ ] Unit of work pattern (if needed)
|
422
|
+
|
423
|
+
### Performance Considerations
|
424
|
+
- [ ] Batch processing for large datasets
|
425
|
+
- [ ] Lazy loading strategies
|
426
|
+
- [ ] Caching mechanisms
|
427
|
+
- [ ] Query optimization patterns
|
428
|
+
- [ ] Memory management for large aggregates
|
429
|
+
|
430
|
+
## Notes
|
431
|
+
Add any feature-specific domain requirements, complex business rules, or architectural patterns needed for your application.
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# Additional UI Requirements - Role-Based Access Control
|
2
|
+
|
3
|
+
This template defines role-specific UI implementations and access controls for your feature.
|
4
|
+
|
5
|
+
## Role Definitions
|
6
|
+
|
7
|
+
### Admin Role
|
8
|
+
**Access Level**: Full system access
|
9
|
+
**UI Elements**:
|
10
|
+
- [ ] Admin dashboard with system statistics
|
11
|
+
- [ ] User management interface (create, edit, delete users)
|
12
|
+
- [ ] System configuration panels
|
13
|
+
- [ ] Advanced analytics and reporting
|
14
|
+
- [ ] Role assignment interface
|
15
|
+
- [ ] Security logs and audit trails
|
16
|
+
|
17
|
+
**Restricted Elements**:
|
18
|
+
- None - full access
|
19
|
+
|
20
|
+
### Manager Role
|
21
|
+
**Access Level**: Department/team management access
|
22
|
+
**UI Elements**:
|
23
|
+
- [ ] Team dashboard with team metrics
|
24
|
+
- [ ] Team member management (view, edit team members)
|
25
|
+
- [ ] Department-specific reporting
|
26
|
+
- [ ] Approval workflows interface
|
27
|
+
- [ ] Team scheduling and task assignment
|
28
|
+
|
29
|
+
**Restricted Elements**:
|
30
|
+
- [ ] System-wide configuration (admin only)
|
31
|
+
- [ ] User role changes (admin only)
|
32
|
+
- [ ] Global system analytics (admin only)
|
33
|
+
|
34
|
+
### User Role
|
35
|
+
**Access Level**: Standard user access
|
36
|
+
**UI Elements**:
|
37
|
+
- [ ] Personal dashboard with user-specific data
|
38
|
+
- [ ] Profile management (edit own profile)
|
39
|
+
- [ ] Task list and personal workflows
|
40
|
+
- [ ] Basic reporting (own data only)
|
41
|
+
- [ ] Standard feature access
|
42
|
+
|
43
|
+
**Restricted Elements**:
|
44
|
+
- [ ] User management (manager/admin only)
|
45
|
+
- [ ] System configuration (admin only)
|
46
|
+
- [ ] Other users' data (unless shared)
|
47
|
+
- [ ] Administrative functions
|
48
|
+
|
49
|
+
### Guest Role
|
50
|
+
**Access Level**: Limited read-only access
|
51
|
+
**UI Elements**:
|
52
|
+
- [ ] Public information display
|
53
|
+
- [ ] Basic feature demonstration
|
54
|
+
- [ ] Registration/login prompts
|
55
|
+
- [ ] Public content consumption
|
56
|
+
|
57
|
+
**Restricted Elements**:
|
58
|
+
- [ ] Any personal data access
|
59
|
+
- [ ] Modification capabilities
|
60
|
+
- [ ] Internal system information
|
61
|
+
|
62
|
+
## Screen-Specific Access Control
|
63
|
+
|
64
|
+
### Login/Authentication Screens
|
65
|
+
```dart
|
66
|
+
// Role-based redirect after authentication
|
67
|
+
switch (userRole) {
|
68
|
+
case UserRole.admin:
|
69
|
+
// Navigate to admin dashboard
|
70
|
+
break;
|
71
|
+
case UserRole.manager:
|
72
|
+
// Navigate to manager dashboard
|
73
|
+
break;
|
74
|
+
case UserRole.user:
|
75
|
+
// Navigate to user dashboard
|
76
|
+
break;
|
77
|
+
case UserRole.guest:
|
78
|
+
// Navigate to public content
|
79
|
+
break;
|
80
|
+
}
|
81
|
+
```
|
82
|
+
|
83
|
+
### Dashboard Implementation
|
84
|
+
- **Admin Dashboard**: System overview, all metrics, user management
|
85
|
+
- **Manager Dashboard**: Team metrics, team management, approvals
|
86
|
+
- **User Dashboard**: Personal metrics, tasks, profile
|
87
|
+
- **Guest Dashboard**: Public information, registration prompts
|
88
|
+
|
89
|
+
### Navigation Structure
|
90
|
+
```yaml
|
91
|
+
Admin Navigation:
|
92
|
+
- Dashboard
|
93
|
+
- User Management
|
94
|
+
- System Settings
|
95
|
+
- Reports & Analytics
|
96
|
+
- Security & Logs
|
97
|
+
|
98
|
+
Manager Navigation:
|
99
|
+
- Team Dashboard
|
100
|
+
- Team Management
|
101
|
+
- Team Reports
|
102
|
+
- Approvals
|
103
|
+
- Schedule
|
104
|
+
|
105
|
+
User Navigation:
|
106
|
+
- Personal Dashboard
|
107
|
+
- My Tasks
|
108
|
+
- My Profile
|
109
|
+
- My Reports
|
110
|
+
|
111
|
+
Guest Navigation:
|
112
|
+
- Public Content
|
113
|
+
- Features Overview
|
114
|
+
- Login/Register
|
115
|
+
```
|
116
|
+
|
117
|
+
## UI Component Visibility Rules
|
118
|
+
|
119
|
+
### Conditional Widget Display
|
120
|
+
```dart
|
121
|
+
// Example role-based widget visibility
|
122
|
+
if (userRole == UserRole.admin || userRole == UserRole.manager) {
|
123
|
+
// Show management tools
|
124
|
+
return ManagementToolsWidget();
|
125
|
+
}
|
126
|
+
|
127
|
+
if (userRole != UserRole.guest) {
|
128
|
+
// Show authenticated user content
|
129
|
+
return AuthenticatedContentWidget();
|
130
|
+
}
|
131
|
+
|
132
|
+
// Show guest content
|
133
|
+
return GuestContentWidget();
|
134
|
+
```
|
135
|
+
|
136
|
+
### Button/Action Availability
|
137
|
+
- **Create**: Admin, Manager (for their scope)
|
138
|
+
- **Edit**: Admin, Manager (for their scope), User (own data)
|
139
|
+
- **Delete**: Admin, Manager (for their scope), User (own data, limited)
|
140
|
+
- **View**: Based on data ownership and role permissions
|
141
|
+
|
142
|
+
## Data Access Patterns
|
143
|
+
|
144
|
+
### API Endpoint Access by Role
|
145
|
+
```yaml
|
146
|
+
Admin Endpoints:
|
147
|
+
- /api/admin/* (all admin functions)
|
148
|
+
- /api/users/* (all user data)
|
149
|
+
- /api/system/* (system configuration)
|
150
|
+
|
151
|
+
Manager Endpoints:
|
152
|
+
- /api/teams/{teamId}/* (team data)
|
153
|
+
- /api/users/team/{teamId} (team members)
|
154
|
+
- /api/reports/team/{teamId} (team reports)
|
155
|
+
|
156
|
+
User Endpoints:
|
157
|
+
- /api/users/{userId} (own profile)
|
158
|
+
- /api/tasks/user/{userId} (own tasks)
|
159
|
+
- /api/reports/user/{userId} (own reports)
|
160
|
+
|
161
|
+
Guest Endpoints:
|
162
|
+
- /api/public/* (public information)
|
163
|
+
- /api/auth/* (authentication)
|
164
|
+
```
|
165
|
+
|
166
|
+
## Error Handling for Unauthorized Access
|
167
|
+
|
168
|
+
### Permission Denied Screens
|
169
|
+
- **Graceful Degradation**: Show alternative content instead of errors
|
170
|
+
- **Clear Messaging**: Explain why access is restricted
|
171
|
+
- **Upgrade Prompts**: Suggest role upgrades where appropriate
|
172
|
+
- **Alternative Actions**: Provide allowed alternatives
|
173
|
+
|
174
|
+
### Security Considerations
|
175
|
+
- [ ] Never expose role checking logic in client-side code
|
176
|
+
- [ ] Always validate permissions on backend
|
177
|
+
- [ ] Log unauthorized access attempts
|
178
|
+
- [ ] Implement session timeout for sensitive roles
|
179
|
+
- [ ] Use secure token-based authentication
|
180
|
+
|
181
|
+
## Implementation Checklist
|
182
|
+
|
183
|
+
### UI Implementation
|
184
|
+
- [ ] Role-based navigation menus implemented
|
185
|
+
- [ ] Conditional widget rendering based on roles
|
186
|
+
- [ ] Role-specific dashboard layouts created
|
187
|
+
- [ ] Permission-based button/action visibility
|
188
|
+
- [ ] Graceful handling of unauthorized access
|
189
|
+
|
190
|
+
### Security Implementation
|
191
|
+
- [ ] Backend permission validation for all endpoints
|
192
|
+
- [ ] Secure role assignment and validation
|
193
|
+
- [ ] Session management with appropriate timeouts
|
194
|
+
- [ ] Audit logging for role-based actions
|
195
|
+
- [ ] Regular security review of role permissions
|
196
|
+
|
197
|
+
### Testing
|
198
|
+
- [ ] Unit tests for role-based UI logic
|
199
|
+
- [ ] Integration tests for role-based workflows
|
200
|
+
- [ ] Security testing for unauthorized access attempts
|
201
|
+
- [ ] User experience testing for each role
|
202
|
+
- [ ] Performance testing with role-based data loading
|
203
|
+
|
204
|
+
## Notes
|
205
|
+
Add any additional role-specific requirements, custom permissions, or special access patterns needed for your application.
|