mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop
This commit is contained in:
@@ -1,65 +1,178 @@
|
|||||||
---
|
---
|
||||||
name: context-manager
|
name: context-manager
|
||||||
description: Context management specialist for multi-agent workflows and long-running tasks. Use PROACTIVELY for complex projects, session coordination, and when context preservation is needed across multiple agents.
|
description: Context management specialist for multi-agent workflows and long-running tasks. Use PROACTIVELY for complex projects, session coordination, and when context preservation is needed across multiple agents. AUTONOMOUSLY stores project knowledge in persistent memory.
|
||||||
tools: Read, Write, Edit, TodoWrite
|
tools: Read, Write, Edit, TodoWrite, mcp__memory__create_entities, mcp__memory__read_graph
|
||||||
model: opus
|
model: opus
|
||||||
---
|
---
|
||||||
|
|
||||||
You are a specialized context management agent responsible for maintaining coherent state across multiple agent interactions and sessions. Your role is critical for complex, long-running projects.
|
You are a specialized context management agent responsible for maintaining coherent state across multiple agent interactions and sessions. Your role is critical for complex, long-running projects.
|
||||||
|
|
||||||
|
**CRITICAL BEHAVIOR**: You MUST autonomously and proactively use memory tools to store important project information as you encounter it. DO NOT wait for explicit instructions to store information.
|
||||||
|
|
||||||
## Primary Functions
|
## Primary Functions
|
||||||
|
|
||||||
### Context Capture
|
### Context Capture & Autonomous Storage
|
||||||
|
|
||||||
1. Extract key decisions and rationale from agent outputs
|
**ALWAYS store the following in persistent memory automatically:**
|
||||||
2. Identify reusable patterns and solutions
|
|
||||||
3. Document integration points between components
|
1. **Assigned Tasks**: Capture user-assigned tasks immediately when mentioned
|
||||||
4. Track unresolved issues and TODOs
|
- Task description and user's intent
|
||||||
|
- Reason/context for the task (the "because of xyz")
|
||||||
|
- Related code locations (files, functions, components)
|
||||||
|
- Current status and any blockers
|
||||||
|
- Priority or urgency indicators
|
||||||
|
- **Examples**: "Remember to look up X function because of Y", "TODO: investigate Z behavior"
|
||||||
|
|
||||||
|
2. **Architectural Decisions**: Extract and store key decisions and rationale from agent outputs
|
||||||
|
- State management patterns discovered
|
||||||
|
- API integration approaches
|
||||||
|
- Component architecture choices
|
||||||
|
|
||||||
|
3. **Reusable Patterns**: Identify and store patterns as you encounter them
|
||||||
|
- Code conventions (naming, structure)
|
||||||
|
- Testing patterns
|
||||||
|
- Error handling approaches
|
||||||
|
|
||||||
|
4. **Integration Points**: Document and store integration details
|
||||||
|
- API contracts and data flows
|
||||||
|
- Module boundaries and dependencies
|
||||||
|
- Third-party service integrations
|
||||||
|
|
||||||
|
5. **Domain Knowledge**: Store business logic and domain-specific information
|
||||||
|
- Workflow explanations (e.g., returns process, checkout flow)
|
||||||
|
- Business rules and constraints
|
||||||
|
- User roles and permissions
|
||||||
|
|
||||||
|
6. **Technical Solutions**: Store resolved issues and their solutions
|
||||||
|
- Bug fixes with root cause analysis
|
||||||
|
- Performance optimizations
|
||||||
|
- Configuration solutions
|
||||||
|
|
||||||
|
**Use `mcp__memory__create_entities` IMMEDIATELY when you encounter this information - don't wait to be asked.**
|
||||||
|
|
||||||
### Context Distribution
|
### Context Distribution
|
||||||
|
|
||||||
1. Prepare minimal, relevant context for each agent
|
1. **ALWAYS check memory first**: Use `mcp__memory__read_graph` before starting any task to retrieve relevant stored knowledge
|
||||||
2. Create agent-specific briefings
|
2. Prepare minimal, relevant context for each agent
|
||||||
3. Maintain a context index for quick retrieval
|
3. Create agent-specific briefings enriched with stored memory
|
||||||
4. Prune outdated or irrelevant information
|
4. Maintain a context index for quick retrieval
|
||||||
|
5. Prune outdated or irrelevant information
|
||||||
|
|
||||||
### Memory Management
|
### Memory Management Strategy
|
||||||
|
|
||||||
- Store critical project decisions in memory
|
**Persistent Memory (PRIORITY - use MCP tools)**:
|
||||||
- Maintain a rolling summary of recent changes
|
- **CREATE**: Use `mcp__memory__create_entities` to store entities with relationships:
|
||||||
- Index commonly accessed information
|
- Entity types: task, decision, pattern, integration, solution, convention, domain-knowledge
|
||||||
- Create context checkpoints at major milestones
|
- Include observations (what was learned/assigned) and relations (how entities connect)
|
||||||
|
|
||||||
|
- **RETRIEVE**: Use `mcp__memory__read_graph` to query stored knowledge:
|
||||||
|
- Before starting new work (check for pending tasks, related patterns/decisions)
|
||||||
|
- When user asks "what was I working on?" (retrieve task history)
|
||||||
|
- When encountering similar problems (find previous solutions)
|
||||||
|
- When making architectural choices (review past decisions)
|
||||||
|
- At session start (remind user of pending/incomplete tasks)
|
||||||
|
|
||||||
|
**Ephemeral Memory (File-based - secondary)**:
|
||||||
|
- Maintain rolling summaries in temporary files
|
||||||
|
- Create session checkpoints
|
||||||
|
- Index recent activities
|
||||||
|
|
||||||
## Workflow Integration
|
## Workflow Integration
|
||||||
|
|
||||||
When activated, you should:
|
**On every activation, you MUST:**
|
||||||
|
|
||||||
1. Review the current conversation and agent outputs
|
1. **Query memory first**: Use `mcp__memory__read_graph` to retrieve:
|
||||||
2. Extract and store important context
|
- Pending/incomplete tasks assigned in previous sessions
|
||||||
3. Create a summary for the next agent/session
|
- Relevant stored knowledge for current work
|
||||||
4. Update the project's context index
|
- Related patterns and decisions
|
||||||
5. Suggest when full context compression is needed
|
2. **Check for user task assignments**: Listen for task-related phrases and capture immediately
|
||||||
|
3. **Review current work**: Analyze conversation and agent outputs
|
||||||
|
4. **Store new discoveries**: Use `mcp__memory__create_entities` to store:
|
||||||
|
- ANY new tasks mentioned by user
|
||||||
|
- Important information discovered
|
||||||
|
- Task status updates (pending → in-progress → completed)
|
||||||
|
5. **Create summaries**: Prepare briefings enriched with memory context
|
||||||
|
6. **Update indexes**: Maintain project context index
|
||||||
|
7. **Suggest compression**: Recommend when full context compression is needed
|
||||||
|
|
||||||
|
**Key behaviors:**
|
||||||
|
- **TASK PRIORITY**: Capture and store user task assignments IMMEDIATELY when mentioned
|
||||||
|
- Store information PROACTIVELY without being asked
|
||||||
|
- Query memory BEFORE making recommendations
|
||||||
|
- Link new entities to existing ones for knowledge graph building
|
||||||
|
- Update existing entities when information evolves (especially task status)
|
||||||
|
- **Session Start**: Proactively remind user of pending/incomplete tasks from memory
|
||||||
|
|
||||||
## Context Formats
|
## Context Formats
|
||||||
|
|
||||||
### Quick Context (< 500 tokens)
|
### Quick Context (< 500 tokens)
|
||||||
|
|
||||||
- Current task and immediate goals
|
- Current task and immediate goals
|
||||||
- Recent decisions affecting current work
|
- Recent decisions affecting current work (query memory first)
|
||||||
- Active blockers or dependencies
|
- Active blockers or dependencies
|
||||||
|
- Relevant stored patterns from memory
|
||||||
|
|
||||||
### Full Context (< 2000 tokens)
|
### Full Context (< 2000 tokens)
|
||||||
|
|
||||||
- Project architecture overview
|
- Project architecture overview (enriched with stored decisions)
|
||||||
- Key design decisions
|
- Key design decisions (retrieved from memory)
|
||||||
- Integration points and APIs
|
- Integration points and APIs (from stored knowledge)
|
||||||
- Active work streams
|
- Active work streams
|
||||||
|
|
||||||
### Archived Context (stored in memory)
|
### Persistent Context (stored in memory via MCP)
|
||||||
|
|
||||||
- Historical decisions with rationale
|
**Store these entity types:**
|
||||||
- Resolved issues and solutions
|
- `task`: User-assigned tasks, reminders, TODOs with context and status
|
||||||
- Pattern library
|
- `decision`: Architectural and design decisions with rationale
|
||||||
- Performance benchmarks
|
- `pattern`: Reusable code patterns and conventions
|
||||||
|
- `integration`: API contracts and integration points
|
||||||
|
- `solution`: Resolved issues with root cause and fix
|
||||||
|
- `convention`: Coding standards and project conventions
|
||||||
|
- `domain-knowledge`: Business logic and workflow explanations
|
||||||
|
|
||||||
Always optimize for relevance over completeness. Good context accelerates work; bad context creates confusion.
|
**Entity structure examples:**
|
||||||
|
|
||||||
|
**Task entity (NEW - PRIORITY):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "investigate-checkout-pricing-calculation",
|
||||||
|
"entityType": "task",
|
||||||
|
"observations": [
|
||||||
|
"User requested: 'Remember to look up the pricing calculation function'",
|
||||||
|
"Reason: Pricing appears incorrect for bundle products in checkout",
|
||||||
|
"Located in: libs/checkout/feature-cart/src/lib/services/pricing.service.ts",
|
||||||
|
"Status: pending",
|
||||||
|
"Priority: high - affects production checkout",
|
||||||
|
"Related components: checkout-summary, cart-item-list"
|
||||||
|
],
|
||||||
|
"relations": [
|
||||||
|
{"type": "relates_to", "entity": "checkout-domain-knowledge"},
|
||||||
|
{"type": "blocks", "entity": "bundle-pricing-bug-fix"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Other entity types:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "descriptive-entity-name",
|
||||||
|
"entityType": "decision|pattern|integration|solution|convention|domain-knowledge",
|
||||||
|
"observations": ["what was learned", "why it matters", "how it's used"],
|
||||||
|
"relations": [
|
||||||
|
{"type": "relates_to|depends_on|implements|solves|blocks", "entity": "other-entity-name"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Task Status Values**: `pending`, `in-progress`, `blocked`, `completed`, `cancelled`
|
||||||
|
|
||||||
|
**Task Capture Triggers**: Listen for phrases like:
|
||||||
|
- "Remember to..."
|
||||||
|
- "TODO: ..."
|
||||||
|
- "Don't forget..."
|
||||||
|
- "Look into..."
|
||||||
|
- "Investigate..."
|
||||||
|
- "Need to check..."
|
||||||
|
- "Follow up on..."
|
||||||
|
|
||||||
|
Always optimize for relevance over completeness. Good context accelerates work; bad context creates confusion. **Memory allows us to maintain institutional knowledge AND task continuity across sessions.**
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
# /dev:add-e2e-attrs - Add E2E Test Attributes
|
|
||||||
|
|
||||||
Add required E2E test attributes (`data-what`, `data-which`, dynamic `data-*`) to component templates for QA automation.
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
- `component-path`: Path to component directory or HTML template file
|
|
||||||
|
|
||||||
## Required E2E Attributes
|
|
||||||
|
|
||||||
### Core Attributes (Required)
|
|
||||||
1. **`data-what`**: Semantic description of element's purpose
|
|
||||||
- Example: `data-what="submit-button"`, `data-what="search-input"`
|
|
||||||
2. **`data-which`**: Unique identifier for the specific instance
|
|
||||||
- Example: `data-which="primary"`, `data-which="customer-{{ customerId }}"`
|
|
||||||
|
|
||||||
### Dynamic Attributes (Contextual)
|
|
||||||
3. **`data-*`**: Additional context based on state/data
|
|
||||||
- Example: `data-status="active"`, `data-index="0"`
|
|
||||||
|
|
||||||
## Tasks
|
|
||||||
|
|
||||||
### 1. Analyze Component Template
|
|
||||||
- Read component HTML template
|
|
||||||
- Identify interactive elements that need E2E attributes:
|
|
||||||
- Buttons (`button`, `ui-button`)
|
|
||||||
- Inputs (`input`, `textarea`, `select`)
|
|
||||||
- Links (`a`, `routerLink`)
|
|
||||||
- Custom interactive components
|
|
||||||
- Form elements
|
|
||||||
- Clickable elements (`(click)` handlers)
|
|
||||||
|
|
||||||
### 2. Add Missing Attributes
|
|
||||||
|
|
||||||
**Buttons:**
|
|
||||||
```html
|
|
||||||
<!-- BEFORE -->
|
|
||||||
<button (click)="submit()">Submit</button>
|
|
||||||
|
|
||||||
<!-- AFTER -->
|
|
||||||
<button
|
|
||||||
(click)="submit()"
|
|
||||||
data-what="submit-button"
|
|
||||||
data-which="form-primary">
|
|
||||||
Submit
|
|
||||||
</button>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Inputs:**
|
|
||||||
```html
|
|
||||||
<!-- BEFORE -->
|
|
||||||
<input [(ngModel)]="searchTerm" placeholder="Search..." />
|
|
||||||
|
|
||||||
<!-- AFTER -->
|
|
||||||
<input
|
|
||||||
[(ngModel)]="searchTerm"
|
|
||||||
placeholder="Search..."
|
|
||||||
data-what="search-input"
|
|
||||||
data-which="main-search" />
|
|
||||||
```
|
|
||||||
|
|
||||||
**Dynamic Lists:**
|
|
||||||
```html
|
|
||||||
<!-- BEFORE -->
|
|
||||||
@for (item of items; track item.id) {
|
|
||||||
<li (click)="selectItem(item)">{{ item.name }}</li>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- AFTER -->
|
|
||||||
@for (item of items; track item.id) {
|
|
||||||
<li
|
|
||||||
(click)="selectItem(item)"
|
|
||||||
data-what="list-item"
|
|
||||||
[attr.data-which]="item.id"
|
|
||||||
[attr.data-status]="item.status">
|
|
||||||
{{ item.name }}
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Links:**
|
|
||||||
```html
|
|
||||||
<!-- BEFORE -->
|
|
||||||
<a routerLink="/orders/{{ orderId }}">View Order</a>
|
|
||||||
|
|
||||||
<!-- AFTER -->
|
|
||||||
<a
|
|
||||||
[routerLink]="['/orders', orderId]"
|
|
||||||
data-what="order-link"
|
|
||||||
[attr.data-which]="orderId">
|
|
||||||
View Order
|
|
||||||
</a>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Custom Components:**
|
|
||||||
```html
|
|
||||||
<!-- BEFORE -->
|
|
||||||
<ui-button (click)="save()">Save</ui-button>
|
|
||||||
|
|
||||||
<!-- AFTER -->
|
|
||||||
<ui-button
|
|
||||||
(click)="save()"
|
|
||||||
data-what="save-button"
|
|
||||||
data-which="order-form">
|
|
||||||
Save
|
|
||||||
</ui-button>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Naming Conventions
|
|
||||||
|
|
||||||
**`data-what` Guidelines:**
|
|
||||||
- Use kebab-case
|
|
||||||
- Be descriptive but concise
|
|
||||||
- Common patterns:
|
|
||||||
- `*-button` (submit-button, cancel-button, delete-button)
|
|
||||||
- `*-input` (email-input, search-input, quantity-input)
|
|
||||||
- `*-link` (product-link, order-link, customer-link)
|
|
||||||
- `*-item` (list-item, menu-item, card-item)
|
|
||||||
- `*-dialog` (confirm-dialog, error-dialog)
|
|
||||||
- `*-dropdown` (status-dropdown, category-dropdown)
|
|
||||||
|
|
||||||
**`data-which` Guidelines:**
|
|
||||||
- Unique identifier for the instance
|
|
||||||
- Use dynamic binding for list items: `[attr.data-which]="item.id"`
|
|
||||||
- Static for unique elements: `data-which="primary"`
|
|
||||||
- Combine with context: `data-which="customer-{{ customerId }}-edit"`
|
|
||||||
|
|
||||||
### 4. Scan for Coverage
|
|
||||||
Check template coverage:
|
|
||||||
```bash
|
|
||||||
# Count interactive elements
|
|
||||||
grep -E '(click)=|routerLink|button|input|select|textarea' [template-file]
|
|
||||||
|
|
||||||
# Count elements with data-what
|
|
||||||
grep -c 'data-what=' [template-file]
|
|
||||||
|
|
||||||
# List elements missing E2E attributes
|
|
||||||
grep -E '(click)=|button' [template-file] | grep -v 'data-what='
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Validate Attributes
|
|
||||||
- No duplicates in `data-which` within same view
|
|
||||||
- All interactive elements have both `data-what` and `data-which`
|
|
||||||
- Dynamic attributes use proper Angular binding: `[attr.data-*]`
|
|
||||||
- Attributes don't contain sensitive data (passwords, tokens)
|
|
||||||
|
|
||||||
### 6. Update Component Tests
|
|
||||||
Add E2E attribute selectors to tests:
|
|
||||||
```typescript
|
|
||||||
// Use E2E attributes for element selection
|
|
||||||
const submitButton = fixture.nativeElement.querySelector('[data-what="submit-button"][data-which="primary"]');
|
|
||||||
expect(submitButton).toBeTruthy();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. Document Attributes
|
|
||||||
Add comment block at top of template:
|
|
||||||
```html
|
|
||||||
<!--
|
|
||||||
E2E Test Attributes:
|
|
||||||
- data-what="submit-button" data-which="primary" - Main form submission
|
|
||||||
- data-what="cancel-button" data-which="primary" - Cancel action
|
|
||||||
- data-what="search-input" data-which="main" - Product search field
|
|
||||||
-->
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
Provide summary:
|
|
||||||
- Template analyzed: [path]
|
|
||||||
- Interactive elements found: [count]
|
|
||||||
- Attributes added: [count]
|
|
||||||
- Coverage: [percentage]% (elements with E2E attrs / total interactive elements)
|
|
||||||
- List of added attributes with descriptions
|
|
||||||
- Validation status: ✅/❌
|
|
||||||
|
|
||||||
## Common Patterns by Component Type
|
|
||||||
|
|
||||||
**Form Components:**
|
|
||||||
- `data-what="[field]-input" data-which="[form-name]"`
|
|
||||||
- `data-what="submit-button" data-which="[form-name]"`
|
|
||||||
- `data-what="cancel-button" data-which="[form-name]"`
|
|
||||||
|
|
||||||
**List/Table Components:**
|
|
||||||
- `data-what="list-item" [attr.data-which]="item.id"`
|
|
||||||
- `data-what="edit-button" [attr.data-which]="item.id"`
|
|
||||||
- `data-what="delete-button" [attr.data-which]="item.id"`
|
|
||||||
|
|
||||||
**Navigation Components:**
|
|
||||||
- `data-what="nav-link" data-which="[destination]"`
|
|
||||||
- `data-what="breadcrumb" data-which="[level]"`
|
|
||||||
|
|
||||||
**Dialog Components:**
|
|
||||||
- `data-what="confirm-button" data-which="dialog"`
|
|
||||||
- `data-what="close-button" data-which="dialog"`
|
|
||||||
|
|
||||||
## References
|
|
||||||
- CLAUDE.md Code Quality section (E2E Testing Requirements)
|
|
||||||
- docs/guidelines/testing.md
|
|
||||||
- QA team E2E test documentation (if available)
|
|
||||||
434
.claude/commands/eod-report.md
Normal file
434
.claude/commands/eod-report.md
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
---
|
||||||
|
allowed-tools: Read, Write, Bash, Grep
|
||||||
|
argument-hint: [date] | --yesterday | --save-only
|
||||||
|
description: Generate End of Day report summarizing commits and work across all branches
|
||||||
|
---
|
||||||
|
|
||||||
|
# End of Day Report
|
||||||
|
|
||||||
|
Generate daily work summary: $ARGUMENTS
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
- Current Date: !`date +%Y-%m-%d`
|
||||||
|
- Current Time: !`date +%H:%M`
|
||||||
|
- Current Branch: !`git branch --show-current`
|
||||||
|
- Git User: !`git config user.name`
|
||||||
|
- Git Email: !`git config user.email`
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
### 1. Determine Report Date and Scope
|
||||||
|
|
||||||
|
**Objective**: Identify the date range for the report
|
||||||
|
|
||||||
|
- [ ] Ask user for their work start time
|
||||||
|
- Use AskUserQuestion to ask: "What time did you start working today?"
|
||||||
|
- Provide options: "First commit time", "08:00", "09:00", "10:00", "Custom time"
|
||||||
|
- If "Custom time" selected, ask for specific time (HH:MM format)
|
||||||
|
- Default to first commit time if not specified
|
||||||
|
- Use this for accurate "Work Duration" calculation
|
||||||
|
|
||||||
|
- [ ] Check if date argument provided
|
||||||
|
- If `[date]` provided: Use specific date (format: YYYY-MM-DD)
|
||||||
|
- If `--yesterday` provided: Use yesterday's date
|
||||||
|
- Otherwise: Use today's date
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get today's date
|
||||||
|
TODAY=$(date +%Y-%m-%d)
|
||||||
|
|
||||||
|
# Get yesterday's date
|
||||||
|
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
|
||||||
|
|
||||||
|
# Get start of day
|
||||||
|
START_TIME="${TODAY} 00:00:00"
|
||||||
|
|
||||||
|
# Get end of day
|
||||||
|
END_TIME="${TODAY} 23:59:59"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Set report scope
|
||||||
|
- Search across **all branches** (local and remote)
|
||||||
|
- Filter by git user name and email
|
||||||
|
- Include commits from start to end of specified day
|
||||||
|
|
||||||
|
### 2. Collect Commit Information
|
||||||
|
|
||||||
|
**Objective**: Gather all commits made by the user on the specified date (excluding merge commits)
|
||||||
|
|
||||||
|
- [ ] Fetch commits across all branches (non-merge commits only)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get all non-merge commits by current user today across all branches
|
||||||
|
git log --all \
|
||||||
|
--author="$(git config user.name)" \
|
||||||
|
--since="$START_TIME" \
|
||||||
|
--until="$END_TIME" \
|
||||||
|
--pretty=format:"%h|%ai|%s|%D" \
|
||||||
|
--no-merges
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important**: Use `--no-merges` flag to exclude PR merge commits. These will be tracked separately in section 3.
|
||||||
|
|
||||||
|
- [ ] Extract commit details:
|
||||||
|
- Commit hash (short)
|
||||||
|
- Commit time
|
||||||
|
- Commit message
|
||||||
|
- Branch references (if any)
|
||||||
|
|
||||||
|
- [ ] Group commits by branch
|
||||||
|
- Parse branch references from commit output
|
||||||
|
- Identify which branch each commit belongs to
|
||||||
|
- Track branch switches during the day
|
||||||
|
- Exclude "Merged PR" commits from this section (they appear in Merge Activity instead)
|
||||||
|
|
||||||
|
**Example Output**:
|
||||||
|
```
|
||||||
|
c208327db|2025-10-28 14:23:45|feat(crm-data-access,checkout): improve primary bonus card selection logic|feature/5202-Praemie
|
||||||
|
9020cb305|2025-10-28 10:15:32|✨ feat(navigation): implement title management and enhance tab system|feature/5351-navigation
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Identify PR and Merge Activity
|
||||||
|
|
||||||
|
**Objective**: Find pull requests created or merged today, distinguishing between PRs I merged vs PRs merged by colleagues
|
||||||
|
|
||||||
|
- [ ] Find ALL merge commits with "Merged PR" (check both author and committer)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get all PR merge activity with author and committer info
|
||||||
|
git log --all \
|
||||||
|
--since="$START_TIME" \
|
||||||
|
--until="$END_TIME" \
|
||||||
|
--grep="Merged PR" \
|
||||||
|
--pretty=format:"%h|%ai|%s|Author: %an <%ae>|Committer: %cn <%ce>"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Categorize PR merges:
|
||||||
|
- **PRs I merged**: Where I am the COMMITTER (git config user.name matches committer name)
|
||||||
|
- **My PRs merged by colleagues**: Where I am the AUTHOR but someone else is the COMMITTER
|
||||||
|
- **Colleague PRs I merged**: Where someone else is the AUTHOR and I am the COMMITTER
|
||||||
|
|
||||||
|
- [ ] Parse PR numbers from commit messages
|
||||||
|
- Look for patterns: "Merged PR 1234:", "PR #1234", etc.
|
||||||
|
- Extract PR title/description
|
||||||
|
- Note which branch was merged
|
||||||
|
- Note who performed the merge (committer name)
|
||||||
|
|
||||||
|
- [ ] Identify branch merges
|
||||||
|
- Look for merge commits to develop/main
|
||||||
|
- Note feature branches merged
|
||||||
|
|
||||||
|
### 4. Analyze Branch Activity
|
||||||
|
|
||||||
|
**Objective**: Summarize branches worked on today
|
||||||
|
|
||||||
|
- [ ] List all branches with commits today
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get unique branches with activity today
|
||||||
|
git log --all \
|
||||||
|
--author="$(git config user.name)" \
|
||||||
|
--since="$START_TIME" \
|
||||||
|
--until="$END_TIME" \
|
||||||
|
--pretty=format:"%D" | \
|
||||||
|
grep -v '^$' | \
|
||||||
|
tr ',' '\n' | \
|
||||||
|
sed 's/^ *//' | \
|
||||||
|
grep -E '^(origin/)?[a-zA-Z]' | \
|
||||||
|
sort -u
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Identify:
|
||||||
|
- Primary branch worked on (most commits)
|
||||||
|
- Other branches touched
|
||||||
|
- New branches created today
|
||||||
|
- Branches merged today
|
||||||
|
|
||||||
|
- [ ] Check current branch status
|
||||||
|
- Uncommitted changes
|
||||||
|
- Untracked files
|
||||||
|
- Ahead/behind develop
|
||||||
|
|
||||||
|
### 5. Generate Report Summary
|
||||||
|
|
||||||
|
**Objective**: Create formatted markdown report
|
||||||
|
|
||||||
|
- [ ] Build report structure:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# End of Day Report - YYYY-MM-DD
|
||||||
|
|
||||||
|
**Developer**: [Name] <email>
|
||||||
|
**Date**: Day, Month DD, YYYY
|
||||||
|
**Time**: HH:MM
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Summary
|
||||||
|
|
||||||
|
- **Commits**: X commits across Y branches
|
||||||
|
- **PRs I Merged**: Z pull requests (as committer)
|
||||||
|
- **My PRs Merged by Colleagues**: W pull requests
|
||||||
|
- **Primary Branch**: branch-name
|
||||||
|
- **Work Duration**: Started at HH:MM, worked for Xh Ym
|
||||||
|
|
||||||
|
## 🔨 Commits Today
|
||||||
|
|
||||||
|
### Branch: feature/5351-navigation (5 commits)
|
||||||
|
- `9020cb3` (10:15) ✨ feat(navigation): implement title management and enhance tab system
|
||||||
|
- `abc1234` (11:30) fix(navigation): resolve routing edge case
|
||||||
|
- `def5678` (14:45) test(navigation): add comprehensive test coverage
|
||||||
|
- `ghi9012` (15:20) refactor(navigation): improve code organization
|
||||||
|
- `jkl3456` (16:00) docs(navigation): update README with usage examples
|
||||||
|
|
||||||
|
### Branch: feature/5202-Praemie (2 commits)
|
||||||
|
- `c208327` (14:23) feat(crm-data-access,checkout): improve primary bonus card selection logic
|
||||||
|
- `mno7890` (16:45) fix(checkout): handle edge case for bonus points
|
||||||
|
|
||||||
|
## 🔀 Merge Activity
|
||||||
|
|
||||||
|
### PRs I Merged (as committer)
|
||||||
|
- **PR #1990**: feat(ui): add new button variants → develop
|
||||||
|
- **PR #1991**: fix(api): resolve timeout issues → develop
|
||||||
|
|
||||||
|
### My PRs Merged by Colleagues
|
||||||
|
- **PR #1987**: Carousel Library → develop (merged by Nino Righi)
|
||||||
|
- **PR #1989**: fix(checkout): resolve currency constraint violations → develop (merged by Nino Righi)
|
||||||
|
|
||||||
|
### Branch Merges
|
||||||
|
- `feature/5202-Praemie-stock-info-request-batching` → `feature/5202-Praemie`
|
||||||
|
|
||||||
|
## 🌿 Branch Activity
|
||||||
|
|
||||||
|
**Primary Branch**: feature/5351-navigation (5 commits)
|
||||||
|
|
||||||
|
**Other Branches**:
|
||||||
|
- feature/5202-Praemie (2 commits)
|
||||||
|
- develop (merged 2 PRs)
|
||||||
|
|
||||||
|
**Current Branch**: feature/5351-navigation
|
||||||
|
**Status**: 3 files changed, 2 files staged, 1 file untracked
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
[Optional section for manual notes - left empty by default]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Report generated on YYYY-MM-DD at HH:MM_
|
||||||
|
```
|
||||||
|
|
||||||
|
**Formatting Rules**:
|
||||||
|
- Use emoji for section headers (📊 📝 🔨 🔀 🌿)
|
||||||
|
- Group commits by branch
|
||||||
|
- Show time for each commit in (HH:MM) format
|
||||||
|
- Include commit prefixes (feat:, fix:, docs:, etc.)
|
||||||
|
- Sort branches by number of commits (most active first)
|
||||||
|
- Highlight primary branch (most commits)
|
||||||
|
|
||||||
|
### 6. Save and Display Report
|
||||||
|
|
||||||
|
**Objective**: Output report to terminal and save to file
|
||||||
|
|
||||||
|
**Display to Terminal**:
|
||||||
|
- [ ] Print formatted report to stdout
|
||||||
|
- [ ] Use clear visual separators
|
||||||
|
- [ ] Ensure easy copy/paste to Slack/Teams/Email
|
||||||
|
|
||||||
|
**Save to File**:
|
||||||
|
- [ ] Create reports directory if it doesn't exist
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p reports/eod
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Determine filename
|
||||||
|
- Format: `reports/eod/YYYY-MM-DD.md`
|
||||||
|
- Example: `reports/eod/2025-10-28.md`
|
||||||
|
|
||||||
|
- [ ] Write report to file
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Save report
|
||||||
|
cat > "reports/eod/${TODAY}.md" << 'EOF'
|
||||||
|
[report content]
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Provide file location feedback
|
||||||
|
- Show absolute path to saved file
|
||||||
|
- Confirm successful save
|
||||||
|
|
||||||
|
**If `--save-only` flag**:
|
||||||
|
- [ ] Skip terminal display
|
||||||
|
- [ ] Only save to file
|
||||||
|
- [ ] Show success message with file path
|
||||||
|
|
||||||
|
### 7. Provide Summary Statistics
|
||||||
|
|
||||||
|
**Objective**: Show quick statistics and next steps
|
||||||
|
|
||||||
|
- [ ] Calculate and display:
|
||||||
|
- Total commits today (excluding PR merge commits)
|
||||||
|
- Number of branches worked on
|
||||||
|
- PRs I merged (as committer)
|
||||||
|
- My PRs merged by colleagues (authored by me, committed by others)
|
||||||
|
- Work duration (user-specified start time → last commit time)
|
||||||
|
- Lines of code changed (optional, if available)
|
||||||
|
|
||||||
|
- [ ] Suggest next steps:
|
||||||
|
- Commit uncommitted changes
|
||||||
|
- Push branches to remote
|
||||||
|
- Create PR for completed work
|
||||||
|
- Update task tracking system
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
### Standard Display
|
||||||
|
|
||||||
|
```
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📋 End of Day Report - 2025-10-28
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
**Developer**: Lorenz Hilpert <lorenz@example.com>
|
||||||
|
**Date**: Monday, October 28, 2025
|
||||||
|
**Time**: 17:30
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Summary
|
||||||
|
|
||||||
|
- **Commits**: 5 commits across 1 branch
|
||||||
|
- **PRs I Merged**: 2 pull requests (as committer)
|
||||||
|
- **My PRs Merged by Colleagues**: 0
|
||||||
|
- **Primary Branch**: feature/5351-navigation
|
||||||
|
- **Work Duration**: Started at 09:00, worked for 7h 45m (last commit at 16:45)
|
||||||
|
|
||||||
|
## 🔨 Commits Today
|
||||||
|
|
||||||
|
### Branch: feature/5351-navigation (5 commits)
|
||||||
|
- `9020cb3` (10:15) ✨ feat(navigation): implement title management and enhance tab system
|
||||||
|
- `abc1234` (11:30) 🐛 fix(navigation): resolve routing edge case
|
||||||
|
- `def5678` (14:45) ✅ test(navigation): add comprehensive test coverage
|
||||||
|
- `ghi9012` (15:20) ♻️ refactor(navigation): improve code organization
|
||||||
|
- `jkl3456` (16:00) 📝 docs(navigation): update README with usage examples
|
||||||
|
|
||||||
|
### Branch: feature/5202-Praemie (2 commits)
|
||||||
|
- `c208327` (14:23) ✨ feat(crm-data-access,checkout): improve primary bonus card selection logic
|
||||||
|
- `mno7890` (16:45) 🐛 fix(checkout): handle edge case for bonus points
|
||||||
|
|
||||||
|
## 🔀 Merge Activity
|
||||||
|
|
||||||
|
### PRs I Merged (as committer)
|
||||||
|
- **PR #1987**: Carousel Library → develop
|
||||||
|
- **PR #1989**: fix(checkout): resolve currency constraint violations → develop
|
||||||
|
|
||||||
|
### My PRs Merged by Colleagues
|
||||||
|
_None today_
|
||||||
|
|
||||||
|
## 🌿 Branch Activity
|
||||||
|
|
||||||
|
**Primary Branch**: feature/5351-navigation (5 commits)
|
||||||
|
|
||||||
|
**Other Branches**:
|
||||||
|
- feature/5202-Praemie (2 commits)
|
||||||
|
- develop (2 PR merges)
|
||||||
|
|
||||||
|
**Current Status**:
|
||||||
|
- Branch: feature/5351-navigation
|
||||||
|
- Changes: 3 files changed, 2 files staged, 1 file untracked
|
||||||
|
- Remote: 5 commits ahead of origin/feature/5351-navigation
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
_No additional notes_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ Report saved to: /home/lorenz/Projects/ISA-Frontend/reports/eod/2025-10-28.md
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📊 Daily Statistics
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
Total Commits: 5 (excluding PR merges)
|
||||||
|
Branches: 1 active branch
|
||||||
|
PRs I Merged: 2
|
||||||
|
My PRs Merged by Colleagues: 0
|
||||||
|
Work Duration: 7h 45m (started at 09:00, last commit at 16:45)
|
||||||
|
|
||||||
|
📋 Next Steps
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
1. ✅ Push feature/5351-navigation to remote
|
||||||
|
2. ⚠️ Consider creating PR for completed work
|
||||||
|
3. 💾 1 untracked file - review and commit if needed
|
||||||
|
```
|
||||||
|
|
||||||
|
### No Activity Case
|
||||||
|
|
||||||
|
```
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📋 End of Day Report - 2025-10-28
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
**Developer**: Lorenz Hilpert <lorenz@example.com>
|
||||||
|
**Date**: Monday, October 28, 2025
|
||||||
|
**Time**: 17:30
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Summary
|
||||||
|
|
||||||
|
No commits found for today (2025-10-28).
|
||||||
|
|
||||||
|
**Possible Reasons**:
|
||||||
|
- No development work performed
|
||||||
|
- Working on uncommitted changes
|
||||||
|
- Using different git user configuration
|
||||||
|
|
||||||
|
**Current Branch**: feature/5351-navigation
|
||||||
|
**Uncommitted Changes**: 5 files modified, 2 files staged
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
💡 Tip: If you have uncommitted work, commit it before generating the report.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Yesterday's Report
|
||||||
|
|
||||||
|
```
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
📋 End of Day Report - 2025-10-27 (Yesterday)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
[Report content for yesterday]
|
||||||
|
|
||||||
|
✅ Report saved to: /home/lorenz/Projects/ISA-Frontend/reports/eod/2025-10-27.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate today's EOD report
|
||||||
|
/eod-report
|
||||||
|
|
||||||
|
# Generate yesterday's report (if you forgot)
|
||||||
|
/eod-report --yesterday
|
||||||
|
|
||||||
|
# Generate report for specific date
|
||||||
|
/eod-report 2025-10-25
|
||||||
|
|
||||||
|
# Save to file only (no terminal output)
|
||||||
|
/eod-report --save-only
|
||||||
|
|
||||||
|
# Generate yesterday's report and save only
|
||||||
|
/eod-report --yesterday --save-only
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Git Log Documentation: https://git-scm.com/docs/git-log
|
||||||
|
- Conventional Commits: https://www.conventionalcommits.org/
|
||||||
|
- Project Conventions: See CLAUDE.md for commit message standards
|
||||||
|
- Git Configuration: `git config user.name` and `git config user.email`
|
||||||
309
.claude/commands/generate-changelog.md
Normal file
309
.claude/commands/generate-changelog.md
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
---
|
||||||
|
allowed-tools: Read, Write, Edit, Bash, Grep
|
||||||
|
argument-hint: [version] | --since [tag] | --dry-run
|
||||||
|
description: Generate changelog entries from git tags using Keep a Changelog format
|
||||||
|
---
|
||||||
|
|
||||||
|
# Generate Changelog
|
||||||
|
|
||||||
|
Generate changelog entries from git commits between version tags: $ARGUMENTS
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
- Latest Tag: !`git tag --sort=-creatordate | head -n 1`
|
||||||
|
- CHANGELOG.md: !`test -f CHANGELOG.md && echo "exists" || echo "does not exist"`
|
||||||
|
- Commits Since Last Tag: !`git log $(git tag --sort=-creatordate | head -n 1)..HEAD --oneline | wc -l`
|
||||||
|
- Current Branch: !`git branch --show-current`
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
### 1. Determine Version Range
|
||||||
|
|
||||||
|
**Objective**: Identify the commit range for changelog generation
|
||||||
|
|
||||||
|
- [ ] Check if version argument provided
|
||||||
|
- If `[version]` provided: Use as the new version number
|
||||||
|
- If `--since [tag]` provided: Use custom tag as starting point
|
||||||
|
- Otherwise: Use latest tag as starting point
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find latest tag
|
||||||
|
LATEST_TAG=$(git tag --sort=-creatordate | head -n 1)
|
||||||
|
|
||||||
|
# Get commits since tag
|
||||||
|
git log ${LATEST_TAG}..HEAD --oneline
|
||||||
|
|
||||||
|
# If no tags exist, use entire history
|
||||||
|
if [ -z "$LATEST_TAG" ]; then
|
||||||
|
git log --oneline
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Edge Cases**:
|
||||||
|
- No tags exist → Use entire commit history and suggest version 0.1.0
|
||||||
|
- No commits since last tag → Notify user, no changelog needed
|
||||||
|
- Invalid tag provided → Error with available tags list
|
||||||
|
|
||||||
|
### 2. Extract and Categorize Commits
|
||||||
|
|
||||||
|
**Objective**: Parse commit messages and group by Keep a Changelog categories
|
||||||
|
|
||||||
|
- [ ] Fetch commits with detailed information
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get commits with format: hash | date | message
|
||||||
|
git log ${LATEST_TAG}..HEAD --pretty=format:"%h|%as|%s" --no-merges
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Parse conventional commit patterns and map to categories:
|
||||||
|
|
||||||
|
**Mapping Rules**:
|
||||||
|
- `feat:` or `feature:` → **Added**
|
||||||
|
- `fix:` or `bugfix:` → **Fixed**
|
||||||
|
- `refactor:` → **Changed**
|
||||||
|
- `perf:` or `performance:` → **Changed**
|
||||||
|
- `docs:` → **Changed** (or skip if only documentation)
|
||||||
|
- `style:` → **Changed**
|
||||||
|
- `test:` → (skip from changelog)
|
||||||
|
- `chore:` → (skip from changelog)
|
||||||
|
- `build:` or `ci:` → (skip from changelog)
|
||||||
|
- `revert:` → **Changed** or **Fixed**
|
||||||
|
- `security:` → **Security**
|
||||||
|
- `deprecate:` or `deprecated:` → **Deprecated**
|
||||||
|
- `remove:` or `breaking:` → **Removed**
|
||||||
|
- Non-conventional commits → **Changed** (default)
|
||||||
|
|
||||||
|
- [ ] Extract scope and description from commit messages
|
||||||
|
|
||||||
|
**Commit Pattern**: `type(scope): description`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
feat(checkout): add reward delivery order support
|
||||||
|
fix(remission): resolve currency constraint violations
|
||||||
|
refactor(navigation): implement title management system
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Generate Changelog Entry
|
||||||
|
|
||||||
|
**Objective**: Create properly formatted changelog section
|
||||||
|
|
||||||
|
- [ ] Determine version number
|
||||||
|
- Use provided `[version]` argument
|
||||||
|
- Or prompt for new version if not provided
|
||||||
|
- Format: `[X.Y.Z]` following semantic versioning
|
||||||
|
|
||||||
|
- [ ] Get current date in ISO format: `YYYY-MM-DD`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
TODAY=$(date +%Y-%m-%d)
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Build changelog entry following Keep a Changelog format:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## [VERSION] - YYYY-MM-DD
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- New feature description from feat: commits
|
||||||
|
- Another feature
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Refactored component description
|
||||||
|
- Performance improvements
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- Feature marked for removal
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Deleted feature or breaking change
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Bug fix description
|
||||||
|
- Another fix
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Security improvement description
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rules**:
|
||||||
|
- Only include sections that have entries
|
||||||
|
- Sort entries alphabetically within each section
|
||||||
|
- Use sentence case for descriptions
|
||||||
|
- Remove commit type prefix from descriptions
|
||||||
|
- Include scope in parentheses if present: `(scope) description`
|
||||||
|
- Add reference links to commits/PRs if available
|
||||||
|
|
||||||
|
### 4. Update or Preview CHANGELOG.md
|
||||||
|
|
||||||
|
**Objective**: Append new entry to changelog file or show preview
|
||||||
|
|
||||||
|
**If `--dry-run` flag provided**:
|
||||||
|
- [ ] Display generated changelog entry to stdout
|
||||||
|
- [ ] Show preview of where it would be inserted
|
||||||
|
- [ ] Do NOT modify CHANGELOG.md
|
||||||
|
- [ ] Exit with success
|
||||||
|
|
||||||
|
**Otherwise (append mode)**:
|
||||||
|
- [ ] Check if CHANGELOG.md exists
|
||||||
|
- If not, create with standard header:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Read existing CHANGELOG.md content
|
||||||
|
- [ ] Find insertion point (after "## [Unreleased]" section, or after main header)
|
||||||
|
- [ ] Insert new changelog entry
|
||||||
|
- [ ] Maintain reverse chronological order (newest first)
|
||||||
|
- [ ] Write updated content back to CHANGELOG.md
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup existing file
|
||||||
|
cp CHANGELOG.md CHANGELOG.md.bak
|
||||||
|
|
||||||
|
# Insert new entry
|
||||||
|
# (Implementation handled by Edit tool)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Validate and Report
|
||||||
|
|
||||||
|
**Objective**: Verify changelog quality and provide summary
|
||||||
|
|
||||||
|
- [ ] Validate generated entry:
|
||||||
|
- Version format is valid (X.Y.Z)
|
||||||
|
- Date is correct (YYYY-MM-DD)
|
||||||
|
- At least one category has entries
|
||||||
|
- No duplicate entries
|
||||||
|
- Proper markdown formatting
|
||||||
|
|
||||||
|
- [ ] Report statistics:
|
||||||
|
- Number of commits processed
|
||||||
|
- Entries per category
|
||||||
|
- Version number used
|
||||||
|
- File status (preview/updated)
|
||||||
|
|
||||||
|
- [ ] Show next steps:
|
||||||
|
- Review changelog entry
|
||||||
|
- Update version in package.json if needed
|
||||||
|
- Create git tag if appropriate
|
||||||
|
- Commit changelog changes
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
### Dry Run Preview
|
||||||
|
|
||||||
|
```
|
||||||
|
🔍 Changelog Preview (--dry-run mode)
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
## [1.5.0] - 2025-10-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (checkout) Add reward delivery order support
|
||||||
|
- (navigation) Implement title management and tab system
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (carousel) Update carousel library implementation
|
||||||
|
- (remission) Enhance returns processing workflow
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- (checkout) Resolve currency constraint violations in price handling
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
📊 Statistics
|
||||||
|
─────────────
|
||||||
|
Commits processed: 12
|
||||||
|
Added: 2 entries
|
||||||
|
Changed: 2 entries
|
||||||
|
Fixed: 1 entry
|
||||||
|
Version: 1.5.0
|
||||||
|
Date: 2025-10-28
|
||||||
|
|
||||||
|
⚠️ This is a preview. Run without --dry-run to update CHANGELOG.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Append Mode Success
|
||||||
|
|
||||||
|
```
|
||||||
|
✅ Changelog Updated Successfully
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
## [1.5.0] - 2025-10-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (checkout) Add reward delivery order support
|
||||||
|
- (navigation) Implement title management and tab system
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (carousel) Update carousel library implementation
|
||||||
|
- (remission) Enhance returns processing workflow
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- (checkout) Resolve currency constraint violations in price handling
|
||||||
|
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
📊 Statistics
|
||||||
|
─────────────
|
||||||
|
Commits processed: 12
|
||||||
|
Added: 2 entries
|
||||||
|
Changed: 2 entries
|
||||||
|
Fixed: 1 entry
|
||||||
|
Version: 1.5.0
|
||||||
|
File: CHANGELOG.md (updated)
|
||||||
|
Backup: CHANGELOG.md.bak
|
||||||
|
|
||||||
|
📋 Next Steps
|
||||||
|
─────────────
|
||||||
|
1. Review the changelog entry in CHANGELOG.md
|
||||||
|
2. Update version in package.json: npm version 1.5.0
|
||||||
|
3. Commit the changelog: git add CHANGELOG.md && git commit -m "docs: update changelog for v1.5.0"
|
||||||
|
4. Create git tag: git tag -a v1.5.0 -m "Release v1.5.0"
|
||||||
|
5. Push changes: git push && git push --tags
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Cases
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ No Changes Found
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
No commits found since last tag (v1.4.5).
|
||||||
|
Nothing to add to changelog.
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
❌ No Tags Found
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
No git tags found in this repository.
|
||||||
|
|
||||||
|
Suggestions:
|
||||||
|
- Create your first tag: git tag v0.1.0
|
||||||
|
- Or specify a commit range: /generate-changelog --since HEAD~10
|
||||||
|
- Or generate from all commits: /generate-changelog 0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
⚠️ Invalid Version Format
|
||||||
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
Version "1.5" is invalid.
|
||||||
|
Expected format: X.Y.Z (e.g., 1.5.0)
|
||||||
|
|
||||||
|
Please provide a valid semantic version.
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Keep a Changelog: https://keepachangelog.com/
|
||||||
|
- Semantic Versioning: https://semver.org/
|
||||||
|
- Conventional Commits: https://www.conventionalcommits.org/
|
||||||
|
- Project Conventions: See CLAUDE.md for commit message standards
|
||||||
@@ -15,6 +15,8 @@ Guide for modern Angular 20+ template patterns: control flow, lazy loading, proj
|
|||||||
- Designing reusable components with `ng-content`
|
- Designing reusable components with `ng-content`
|
||||||
- Template performance optimization
|
- Template performance optimization
|
||||||
|
|
||||||
|
**Related Skill:** For E2E testing attributes (`data-what`, `data-which`) and ARIA accessibility attributes, see the **[html-template](../html-template/SKILL.md)** skill. Both skills work together when writing Angular templates.
|
||||||
|
|
||||||
## Control Flow (Angular 17+)
|
## Control Flow (Angular 17+)
|
||||||
|
|
||||||
### @if / @else if / @else
|
### @if / @else if / @else
|
||||||
@@ -211,7 +213,7 @@ Groups elements without DOM footprint:
|
|||||||
1. **Use signals:** `isExpanded = signal(false)`
|
1. **Use signals:** `isExpanded = signal(false)`
|
||||||
2. **Prefer control flow over directives:** Use `@if` not `*ngIf`
|
2. **Prefer control flow over directives:** Use `@if` not `*ngIf`
|
||||||
3. **Keep expressions simple:** Use `computed()` for complex logic
|
3. **Keep expressions simple:** Use `computed()` for complex logic
|
||||||
4. **E2E attributes:** Always add `[attr.data-what]` and `[attr.data-which]`
|
4. **Testing & Accessibility:** Always add E2E and ARIA attributes (see **[html-template](../html-template/SKILL.md)** skill)
|
||||||
5. **Track expressions:** Required in `@for`, use unique IDs
|
5. **Track expressions:** Required in `@for`, use unique IDs
|
||||||
|
|
||||||
## Migration
|
## Migration
|
||||||
|
|||||||
@@ -1,203 +0,0 @@
|
|||||||
---
|
|
||||||
name: Git Commit Helper
|
|
||||||
description: Generate descriptive commit messages by analyzing git diffs. Use when the user asks for help writing commit messages or reviewing staged changes.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Git Commit Helper
|
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
Analyze staged changes and generate commit message:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# View staged changes
|
|
||||||
git diff --staged
|
|
||||||
|
|
||||||
# Generate commit message based on changes
|
|
||||||
# (Claude will analyze the diff and suggest a message)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Commit message format
|
|
||||||
|
|
||||||
Follow conventional commits format:
|
|
||||||
|
|
||||||
```
|
|
||||||
<type>(<scope>): <description>
|
|
||||||
|
|
||||||
[optional body]
|
|
||||||
|
|
||||||
[optional footer]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Types
|
|
||||||
|
|
||||||
- **feat**: New feature
|
|
||||||
- **fix**: Bug fix
|
|
||||||
- **docs**: Documentation changes
|
|
||||||
- **style**: Code style changes (formatting, missing semicolons)
|
|
||||||
- **refactor**: Code refactoring
|
|
||||||
- **test**: Adding or updating tests
|
|
||||||
- **chore**: Maintenance tasks
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
**Feature commit:**
|
|
||||||
```
|
|
||||||
feat(auth): add JWT authentication
|
|
||||||
|
|
||||||
Implement JWT-based authentication system with:
|
|
||||||
- Login endpoint with token generation
|
|
||||||
- Token validation middleware
|
|
||||||
- Refresh token support
|
|
||||||
```
|
|
||||||
|
|
||||||
**Bug fix:**
|
|
||||||
```
|
|
||||||
fix(api): handle null values in user profile
|
|
||||||
|
|
||||||
Prevent crashes when user profile fields are null.
|
|
||||||
Add null checks before accessing nested properties.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Refactor:**
|
|
||||||
```
|
|
||||||
refactor(database): simplify query builder
|
|
||||||
|
|
||||||
Extract common query patterns into reusable functions.
|
|
||||||
Reduce code duplication in database layer.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Analyzing changes
|
|
||||||
|
|
||||||
Review what's being committed:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Show files changed
|
|
||||||
git status
|
|
||||||
|
|
||||||
# Show detailed changes
|
|
||||||
git diff --staged
|
|
||||||
|
|
||||||
# Show statistics
|
|
||||||
git diff --staged --stat
|
|
||||||
|
|
||||||
# Show changes for specific file
|
|
||||||
git diff --staged path/to/file
|
|
||||||
```
|
|
||||||
|
|
||||||
## Commit message guidelines
|
|
||||||
|
|
||||||
**DO:**
|
|
||||||
- Use imperative mood ("add feature" not "added feature")
|
|
||||||
- Keep first line under 50 characters
|
|
||||||
- Capitalize first letter
|
|
||||||
- No period at end of summary
|
|
||||||
- Explain WHY not just WHAT in body
|
|
||||||
|
|
||||||
**DON'T:**
|
|
||||||
- Use vague messages like "update" or "fix stuff"
|
|
||||||
- Include technical implementation details in summary
|
|
||||||
- Write paragraphs in summary line
|
|
||||||
- Use past tense
|
|
||||||
|
|
||||||
## Multi-file commits
|
|
||||||
|
|
||||||
When committing multiple related changes:
|
|
||||||
|
|
||||||
```
|
|
||||||
refactor(core): restructure authentication module
|
|
||||||
|
|
||||||
- Move auth logic from controllers to service layer
|
|
||||||
- Extract validation into separate validators
|
|
||||||
- Update tests to use new structure
|
|
||||||
- Add integration tests for auth flow
|
|
||||||
|
|
||||||
Breaking change: Auth service now requires config object
|
|
||||||
```
|
|
||||||
|
|
||||||
## Scope examples
|
|
||||||
|
|
||||||
**Frontend:**
|
|
||||||
- `feat(ui): add loading spinner to dashboard`
|
|
||||||
- `fix(form): validate email format`
|
|
||||||
|
|
||||||
**Backend:**
|
|
||||||
- `feat(api): add user profile endpoint`
|
|
||||||
- `fix(db): resolve connection pool leak`
|
|
||||||
|
|
||||||
**Infrastructure:**
|
|
||||||
- `chore(ci): update Node version to 20`
|
|
||||||
- `feat(docker): add multi-stage build`
|
|
||||||
|
|
||||||
## Breaking changes
|
|
||||||
|
|
||||||
Indicate breaking changes clearly:
|
|
||||||
|
|
||||||
```
|
|
||||||
feat(api)!: restructure API response format
|
|
||||||
|
|
||||||
BREAKING CHANGE: All API responses now follow JSON:API spec
|
|
||||||
|
|
||||||
Previous format:
|
|
||||||
{ "data": {...}, "status": "ok" }
|
|
||||||
|
|
||||||
New format:
|
|
||||||
{ "data": {...}, "meta": {...} }
|
|
||||||
|
|
||||||
Migration guide: Update client code to handle new response structure
|
|
||||||
```
|
|
||||||
|
|
||||||
## Template workflow
|
|
||||||
|
|
||||||
1. **Review changes**: `git diff --staged`
|
|
||||||
2. **Identify type**: Is it feat, fix, refactor, etc.?
|
|
||||||
3. **Determine scope**: What part of the codebase?
|
|
||||||
4. **Write summary**: Brief, imperative description
|
|
||||||
5. **Add body**: Explain why and what impact
|
|
||||||
6. **Note breaking changes**: If applicable
|
|
||||||
|
|
||||||
## Interactive commit helper
|
|
||||||
|
|
||||||
Use `git add -p` for selective staging:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stage changes interactively
|
|
||||||
git add -p
|
|
||||||
|
|
||||||
# Review what's staged
|
|
||||||
git diff --staged
|
|
||||||
|
|
||||||
# Commit with message
|
|
||||||
git commit -m "type(scope): description"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Amending commits
|
|
||||||
|
|
||||||
Fix the last commit message:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Amend commit message only
|
|
||||||
git commit --amend
|
|
||||||
|
|
||||||
# Amend and add more changes
|
|
||||||
git add forgotten-file.js
|
|
||||||
git commit --amend --no-edit
|
|
||||||
```
|
|
||||||
|
|
||||||
## Best practices
|
|
||||||
|
|
||||||
1. **Atomic commits** - One logical change per commit
|
|
||||||
2. **Test before commit** - Ensure code works
|
|
||||||
3. **Reference issues** - Include issue numbers if applicable
|
|
||||||
4. **Keep it focused** - Don't mix unrelated changes
|
|
||||||
5. **Write for humans** - Future you will read this
|
|
||||||
|
|
||||||
## Commit message checklist
|
|
||||||
|
|
||||||
- [ ] Type is appropriate (feat/fix/docs/etc.)
|
|
||||||
- [ ] Scope is specific and clear
|
|
||||||
- [ ] Summary is under 50 characters
|
|
||||||
- [ ] Summary uses imperative mood
|
|
||||||
- [ ] Body explains WHY not just WHAT
|
|
||||||
- [ ] Breaking changes are clearly marked
|
|
||||||
- [ ] Related issue numbers are included
|
|
||||||
352
.claude/skills/git-workflow/SKILL.md
Normal file
352
.claude/skills/git-workflow/SKILL.md
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
---
|
||||||
|
name: git-workflow
|
||||||
|
description: Enforces ISA-Frontend project Git workflow conventions including branch naming, conventional commits, and PR creation against develop branch
|
||||||
|
---
|
||||||
|
|
||||||
|
# Git Workflow Skill
|
||||||
|
|
||||||
|
Enforces Git workflow conventions specific to the ISA-Frontend project.
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- Creating new branches for features or bugfixes
|
||||||
|
- Writing commit messages
|
||||||
|
- Creating pull requests
|
||||||
|
- Any Git operations requiring adherence to project conventions
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
### 1. Default Branch is `develop` (NOT `main`)
|
||||||
|
|
||||||
|
- **All PRs target**: `develop` branch
|
||||||
|
- **Feature branches from**: `develop`
|
||||||
|
- **Never push directly to**: `develop` or `main`
|
||||||
|
|
||||||
|
### 2. Branch Naming Convention
|
||||||
|
|
||||||
|
**Format**: `<type>/{task-id}-{short-description}`
|
||||||
|
|
||||||
|
**Types**:
|
||||||
|
- `feature/` - New features or enhancements
|
||||||
|
- `bugfix/` - Bug fixes
|
||||||
|
- `hotfix/` - Emergency production fixes
|
||||||
|
|
||||||
|
**Rules**:
|
||||||
|
- Use English kebab-case for descriptions
|
||||||
|
- Start with task/issue ID (e.g., `5391`)
|
||||||
|
- Keep description concise - shorten if too long
|
||||||
|
- Use hyphens to separate words
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
```bash
|
||||||
|
# Good
|
||||||
|
feature/5391-praemie-checkout-action-card-delivery-order
|
||||||
|
bugfix/6123-fix-login-redirect-loop
|
||||||
|
hotfix/7890-critical-payment-error
|
||||||
|
|
||||||
|
# Bad
|
||||||
|
feature/praemie-checkout # Missing task ID
|
||||||
|
feature/5391_praemie # Using underscores
|
||||||
|
feature-5391-very-long-description-that-goes-on-forever # Too long
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Conventional Commits (WITHOUT Co-Author Tags)
|
||||||
|
|
||||||
|
**Format**: `<type>(<scope>): <description>`
|
||||||
|
|
||||||
|
**Types**:
|
||||||
|
- `feat`: New feature
|
||||||
|
- `fix`: Bug fix
|
||||||
|
- `docs`: Documentation only
|
||||||
|
- `style`: Code style (formatting, missing semicolons)
|
||||||
|
- `refactor`: Code restructuring without feature changes
|
||||||
|
- `perf`: Performance improvements
|
||||||
|
- `test`: Adding or updating tests
|
||||||
|
- `build`: Build system or dependencies
|
||||||
|
- `ci`: CI configuration
|
||||||
|
- `chore`: Maintenance tasks
|
||||||
|
|
||||||
|
**Rules**:
|
||||||
|
- ❌ **NO** "Generated with Claude Code" tags
|
||||||
|
- ❌ **NO** "Co-Authored-By: Claude" tags
|
||||||
|
- ✅ Keep first line under 72 characters
|
||||||
|
- ✅ Use imperative mood ("add" not "added")
|
||||||
|
- ✅ Body optional but recommended for complex changes
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
```bash
|
||||||
|
# Good
|
||||||
|
feat(checkout): add bonus card selection for delivery orders
|
||||||
|
|
||||||
|
fix(crm): resolve customer search filter reset issue
|
||||||
|
|
||||||
|
refactor(oms): extract return validation logic into service
|
||||||
|
|
||||||
|
# Bad
|
||||||
|
feat(checkout): add bonus card selection
|
||||||
|
|
||||||
|
Generated with Claude Code
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||||
|
|
||||||
|
# Also bad
|
||||||
|
Added new feature # Wrong tense
|
||||||
|
Fix bug # Missing scope
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Pull Request Creation
|
||||||
|
|
||||||
|
**Target Branch**: Always `develop`
|
||||||
|
|
||||||
|
**PR Title Format**: Same as conventional commit
|
||||||
|
```
|
||||||
|
feat(domain): concise description of changes
|
||||||
|
```
|
||||||
|
|
||||||
|
**PR Body Structure**:
|
||||||
|
```markdown
|
||||||
|
## Summary
|
||||||
|
- Brief bullet points of changes
|
||||||
|
|
||||||
|
## Related Tasks
|
||||||
|
- Closes #{task-id}
|
||||||
|
- Refs #{related-task}
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- [ ] Unit tests added/updated
|
||||||
|
- [ ] E2E attributes added
|
||||||
|
- [ ] Manual testing completed
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
None / List breaking changes
|
||||||
|
|
||||||
|
## Screenshots (if UI changes)
|
||||||
|
[Add screenshots]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Workflows
|
||||||
|
|
||||||
|
### Creating a Feature Branch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Update develop
|
||||||
|
git checkout develop
|
||||||
|
git pull origin develop
|
||||||
|
|
||||||
|
# 2. Create feature branch
|
||||||
|
git checkout -b feature/5391-praemie-checkout-action-card
|
||||||
|
|
||||||
|
# 3. Work and commit
|
||||||
|
git add .
|
||||||
|
git commit -m "feat(checkout): add primary bonus card selection logic"
|
||||||
|
|
||||||
|
# 4. Push to remote
|
||||||
|
git push -u origin feature/5391-praemie-checkout-action-card
|
||||||
|
|
||||||
|
# 5. Create PR targeting develop (use gh CLI or web UI)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a Bugfix Branch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From develop
|
||||||
|
git checkout develop
|
||||||
|
git pull origin develop
|
||||||
|
git checkout -b bugfix/6123-login-redirect-loop
|
||||||
|
|
||||||
|
# Commit
|
||||||
|
git commit -m "fix(auth): resolve infinite redirect on logout"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a Hotfix Branch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From main (production)
|
||||||
|
git checkout main
|
||||||
|
git pull origin main
|
||||||
|
git checkout -b hotfix/7890-payment-processing-error
|
||||||
|
|
||||||
|
# Commit
|
||||||
|
git commit -m "fix(checkout): critical payment API timeout handling"
|
||||||
|
|
||||||
|
# Merge to both main and develop
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commit Message Guidelines
|
||||||
|
|
||||||
|
### Good Commit Messages
|
||||||
|
|
||||||
|
```bash
|
||||||
|
feat(crm): add customer loyalty tier calculation
|
||||||
|
|
||||||
|
Implements three-tier loyalty system based on annual spend.
|
||||||
|
Includes migration for existing customer data.
|
||||||
|
|
||||||
|
Refs #5234
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(oms): prevent duplicate return submissions
|
||||||
|
|
||||||
|
Adds debouncing to return form submission and validates
|
||||||
|
against existing returns in the last 60 seconds.
|
||||||
|
|
||||||
|
Closes #5891
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
refactor(catalogue): extract product search into dedicated service
|
||||||
|
|
||||||
|
Moves search logic from component to ProductSearchService
|
||||||
|
for better testability and reusability.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
perf(remission): optimize remission list query with pagination
|
||||||
|
|
||||||
|
Reduces initial load time from 3s to 800ms by implementing
|
||||||
|
cursor-based pagination.
|
||||||
|
|
||||||
|
Closes #6234
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bad Commit Messages
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Too vague
|
||||||
|
fix: bug fixes
|
||||||
|
|
||||||
|
# Missing scope
|
||||||
|
feat: new feature
|
||||||
|
|
||||||
|
# Wrong tense
|
||||||
|
fixed the login issue
|
||||||
|
|
||||||
|
# Including banned tags
|
||||||
|
feat(checkout): add feature
|
||||||
|
|
||||||
|
Generated with Claude Code
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git Configuration Checks
|
||||||
|
|
||||||
|
### Verify Git Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check current branch
|
||||||
|
git branch --show-current
|
||||||
|
|
||||||
|
# Verify remote
|
||||||
|
git remote -v # Should show origin pointing to ISA-Frontend
|
||||||
|
|
||||||
|
# Check for uncommitted changes
|
||||||
|
git status
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Mistakes to Avoid
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ Creating PR against main
|
||||||
|
gh pr create --base main # WRONG
|
||||||
|
|
||||||
|
# ✅ Always target develop
|
||||||
|
gh pr create --base develop # CORRECT
|
||||||
|
|
||||||
|
# ❌ Using underscores in branch names
|
||||||
|
git checkout -b feature/5391_my_feature # WRONG
|
||||||
|
|
||||||
|
# ✅ Use hyphens
|
||||||
|
git checkout -b feature/5391-my-feature # CORRECT
|
||||||
|
|
||||||
|
# ❌ Adding co-author tags
|
||||||
|
git commit -m "feat: something
|
||||||
|
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>" # WRONG
|
||||||
|
|
||||||
|
# ✅ Clean commit message
|
||||||
|
git commit -m "feat(scope): something" # CORRECT
|
||||||
|
|
||||||
|
# ❌ Forgetting task ID in branch name
|
||||||
|
git checkout -b feature/new-checkout-flow # WRONG
|
||||||
|
|
||||||
|
# ✅ Include task ID
|
||||||
|
git checkout -b feature/5391-new-checkout-flow # CORRECT
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with Claude Code
|
||||||
|
|
||||||
|
When Claude Code creates commits or PRs:
|
||||||
|
|
||||||
|
### Commit Creation
|
||||||
|
```bash
|
||||||
|
# Claude uses conventional commits WITHOUT attribution
|
||||||
|
git commit -m "feat(checkout): implement bonus card selection
|
||||||
|
|
||||||
|
Adds logic for selecting primary bonus card during checkout
|
||||||
|
for delivery orders. Includes validation and error handling.
|
||||||
|
|
||||||
|
Refs #5391"
|
||||||
|
```
|
||||||
|
|
||||||
|
### PR Creation
|
||||||
|
```bash
|
||||||
|
# Target develop by default
|
||||||
|
gh pr create --base develop \
|
||||||
|
--title "feat(checkout): implement bonus card selection" \
|
||||||
|
--body "## Summary
|
||||||
|
- Add primary bonus card selection logic
|
||||||
|
- Implement validation for delivery orders
|
||||||
|
- Add error handling for API failures
|
||||||
|
|
||||||
|
## Related Tasks
|
||||||
|
- Closes #5391
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- [x] Unit tests added
|
||||||
|
- [x] E2E attributes added
|
||||||
|
- [x] Manual testing completed"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Branch Cleanup
|
||||||
|
|
||||||
|
### After PR Merge
|
||||||
|
```bash
|
||||||
|
# Update develop
|
||||||
|
git checkout develop
|
||||||
|
git pull origin develop
|
||||||
|
|
||||||
|
# Delete local feature branch
|
||||||
|
git branch -d feature/5391-praemie-checkout
|
||||||
|
|
||||||
|
# Delete remote branch (usually done by PR merge)
|
||||||
|
git push origin --delete feature/5391-praemie-checkout
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Branch naming
|
||||||
|
feature/{task-id}-{description}
|
||||||
|
bugfix/{task-id}-{description}
|
||||||
|
hotfix/{task-id}-{description}
|
||||||
|
|
||||||
|
# Commit format
|
||||||
|
<type>(<scope>): <description>
|
||||||
|
|
||||||
|
# Common types
|
||||||
|
feat, fix, docs, style, refactor, perf, test, build, ci, chore
|
||||||
|
|
||||||
|
# PR target
|
||||||
|
Always: develop (NOT main)
|
||||||
|
|
||||||
|
# Banned in commits
|
||||||
|
- "Generated with Claude Code"
|
||||||
|
- "Co-Authored-By: Claude"
|
||||||
|
- Any AI attribution
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Conventional Commits](https://www.conventionalcommits.org/)
|
||||||
|
- Project PR template: `.github/pull_request_template.md`
|
||||||
|
- Code review standards: `.github/review-instructions.md`
|
||||||
291
.claude/skills/html-template/SKILL.md
Normal file
291
.claude/skills/html-template/SKILL.md
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
# HTML Template - Testing & Accessibility Attributes
|
||||||
|
|
||||||
|
This skill should be used when writing or reviewing HTML templates to ensure proper testing and accessibility attributes are included.
|
||||||
|
|
||||||
|
## When to Use This Skill
|
||||||
|
|
||||||
|
Use this skill when:
|
||||||
|
- Writing or modifying Angular component templates
|
||||||
|
- Creating any HTML templates or markup
|
||||||
|
- Reviewing code for testing and accessibility compliance
|
||||||
|
- Adding interactive elements (buttons, inputs, links, etc.)
|
||||||
|
- Implementing forms, lists, navigation, or dialogs
|
||||||
|
|
||||||
|
**Works seamlessly with:** `angular-template` skill for complete Angular template guidance.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This skill provides comprehensive guidance for two critical HTML attribute categories:
|
||||||
|
|
||||||
|
### 1. E2E Testing Attributes
|
||||||
|
Enable automated end-to-end testing by providing stable selectors for QA automation:
|
||||||
|
- **`data-what`**: Semantic description of element's purpose
|
||||||
|
- **`data-which`**: Unique identifier for specific instances
|
||||||
|
- **`data-*`**: Additional contextual information
|
||||||
|
|
||||||
|
### 2. ARIA Accessibility Attributes
|
||||||
|
Ensure web applications are accessible to all users, including those using assistive technologies:
|
||||||
|
- **Roles**: Define element purpose (button, navigation, dialog, etc.)
|
||||||
|
- **Properties**: Provide additional context (aria-label, aria-describedby)
|
||||||
|
- **States**: Indicate dynamic states (aria-expanded, aria-disabled)
|
||||||
|
- **Live Regions**: Announce dynamic content changes
|
||||||
|
|
||||||
|
## Why Both Are Essential
|
||||||
|
|
||||||
|
- **E2E Attributes**: Enable reliable automated testing without brittle CSS or XPath selectors
|
||||||
|
- **ARIA Attributes**: Ensure compliance with WCAG standards and improve user experience for people with disabilities
|
||||||
|
- **Together**: Create robust, testable, and accessible web applications
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
### Button Example
|
||||||
|
```html
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
(click)="onSubmit()"
|
||||||
|
data-what="submit-button"
|
||||||
|
data-which="registration-form"
|
||||||
|
aria-label="Submit registration form">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Input Example
|
||||||
|
```html
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="email"
|
||||||
|
data-what="email-input"
|
||||||
|
data-which="registration-form"
|
||||||
|
aria-label="Email address"
|
||||||
|
aria-describedby="email-hint"
|
||||||
|
aria-required="true" />
|
||||||
|
<span id="email-hint">We'll never share your email</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dynamic List Example
|
||||||
|
```html
|
||||||
|
@for (item of items; track item.id) {
|
||||||
|
<li
|
||||||
|
(click)="selectItem(item)"
|
||||||
|
data-what="list-item"
|
||||||
|
[attr.data-which]="item.id"
|
||||||
|
[attr.data-status]="item.status"
|
||||||
|
[attr.aria-label]="'Select ' + item.name"
|
||||||
|
role="button"
|
||||||
|
tabindex="0">
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Link Example
|
||||||
|
```html
|
||||||
|
<a
|
||||||
|
[routerLink]="['/orders', orderId]"
|
||||||
|
data-what="order-link"
|
||||||
|
[attr.data-which]="orderId"
|
||||||
|
[attr.aria-label]="'View order ' + orderNumber">
|
||||||
|
View Order #{{ orderNumber }}
|
||||||
|
</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dialog Example
|
||||||
|
```html
|
||||||
|
<div
|
||||||
|
class="dialog"
|
||||||
|
data-what="confirmation-dialog"
|
||||||
|
data-which="delete-item"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby="dialog-title"
|
||||||
|
aria-describedby="dialog-description">
|
||||||
|
|
||||||
|
<h2 id="dialog-title">Confirm Deletion</h2>
|
||||||
|
<p id="dialog-description">Are you sure you want to delete this item?</p>
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="confirm()"
|
||||||
|
data-what="confirm-button"
|
||||||
|
data-which="delete-dialog"
|
||||||
|
aria-label="Confirm deletion">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="cancel()"
|
||||||
|
data-what="cancel-button"
|
||||||
|
data-which="delete-dialog"
|
||||||
|
aria-label="Cancel deletion">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Patterns by Element Type
|
||||||
|
|
||||||
|
### Interactive Elements That Need Attributes
|
||||||
|
|
||||||
|
**Required attributes for:**
|
||||||
|
- Buttons (`<button>`, `<ui-button>`, custom button components)
|
||||||
|
- Form inputs (`<input>`, `<textarea>`, `<select>`)
|
||||||
|
- Links (`<a>`, `[routerLink]`)
|
||||||
|
- Clickable elements (elements with `(click)` handlers)
|
||||||
|
- Custom interactive components
|
||||||
|
- List items in dynamic lists
|
||||||
|
- Navigation items
|
||||||
|
- Dialog/modal controls
|
||||||
|
|
||||||
|
### Naming Conventions
|
||||||
|
|
||||||
|
**E2E `data-what` patterns:**
|
||||||
|
- `*-button` (submit-button, cancel-button, delete-button)
|
||||||
|
- `*-input` (email-input, search-input, quantity-input)
|
||||||
|
- `*-link` (product-link, order-link, customer-link)
|
||||||
|
- `*-item` (list-item, menu-item, card-item)
|
||||||
|
- `*-dialog` (confirm-dialog, error-dialog, info-dialog)
|
||||||
|
- `*-dropdown` (status-dropdown, category-dropdown)
|
||||||
|
|
||||||
|
**E2E `data-which` guidelines:**
|
||||||
|
- Use unique identifiers: `data-which="primary"`, `data-which="customer-list"`
|
||||||
|
- Bind dynamically for lists: `[attr.data-which]="item.id"`
|
||||||
|
- Combine with context: `data-which="customer-{{ customerId }}-edit"`
|
||||||
|
|
||||||
|
**ARIA role patterns:**
|
||||||
|
- Interactive elements: `button`, `link`, `menuitem`
|
||||||
|
- Structural: `navigation`, `main`, `complementary`, `contentinfo`
|
||||||
|
- Widget: `dialog`, `alertdialog`, `tooltip`, `tablist`, `tab`
|
||||||
|
- Landmark: `banner`, `search`, `form`, `region`
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### E2E Attributes
|
||||||
|
1. ✅ Add to ALL interactive elements
|
||||||
|
2. ✅ Use kebab-case for `data-what` values
|
||||||
|
3. ✅ Ensure `data-which` is unique within the view
|
||||||
|
4. ✅ Use Angular binding for dynamic values: `[attr.data-*]`
|
||||||
|
5. ✅ Avoid including sensitive data in attributes
|
||||||
|
6. ✅ Document complex attribute patterns in template comments
|
||||||
|
|
||||||
|
### ARIA Attributes
|
||||||
|
1. ✅ Use semantic HTML first (use `<button>` instead of `<div role="button">`)
|
||||||
|
2. ✅ Provide text alternatives for all interactive elements
|
||||||
|
3. ✅ Ensure proper keyboard navigation (tabindex, focus management)
|
||||||
|
4. ✅ Use `aria-label` when visual label is missing
|
||||||
|
5. ✅ Use `aria-labelledby` to reference existing visible labels
|
||||||
|
6. ✅ Keep ARIA attributes in sync with visual states
|
||||||
|
7. ✅ Test with screen readers (NVDA, JAWS, VoiceOver)
|
||||||
|
|
||||||
|
### Combined Best Practices
|
||||||
|
1. ✅ Add both E2E and ARIA attributes to every interactive element
|
||||||
|
2. ✅ Keep attributes close together in the HTML for readability
|
||||||
|
3. ✅ Update tests to use `data-what` and `data-which` selectors
|
||||||
|
4. ✅ Validate coverage: all interactive elements should have both types
|
||||||
|
5. ✅ Review with QA and accessibility teams
|
||||||
|
|
||||||
|
## Detailed References
|
||||||
|
|
||||||
|
For comprehensive guides, examples, and patterns, see:
|
||||||
|
|
||||||
|
- **[E2E Testing Attributes](references/e2e-attributes.md)** - Complete E2E attribute patterns and conventions
|
||||||
|
- **[ARIA Accessibility Attributes](references/aria-attributes.md)** - Comprehensive ARIA guidance and WCAG compliance
|
||||||
|
- **[Combined Patterns](references/combined-patterns.md)** - Real-world examples with both attribute types
|
||||||
|
|
||||||
|
## Project-Specific Links
|
||||||
|
|
||||||
|
- **Testing Guidelines**: `docs/guidelines/testing.md` - Project testing standards including E2E attributes
|
||||||
|
- **CLAUDE.md**: Project conventions and requirements
|
||||||
|
- **Angular Template Skill**: `.claude/skills/angular-template` - For Angular-specific syntax
|
||||||
|
|
||||||
|
## Validation Checklist
|
||||||
|
|
||||||
|
Before considering template complete:
|
||||||
|
- [ ] All buttons have `data-what`, `data-which`, and `aria-label`
|
||||||
|
- [ ] All inputs have `data-what`, `data-which`, and appropriate ARIA attributes
|
||||||
|
- [ ] All links have `data-what`, `data-which`, and descriptive ARIA labels
|
||||||
|
- [ ] Dynamic lists use `[attr.data-*]` bindings with unique identifiers
|
||||||
|
- [ ] Dialogs have proper ARIA roles and relationships
|
||||||
|
- [ ] Forms have proper field associations and error announcements
|
||||||
|
- [ ] Interactive elements are keyboard accessible (tabindex where needed)
|
||||||
|
- [ ] No duplicate `data-which` values within the same view
|
||||||
|
- [ ] Screen reader testing completed (if applicable)
|
||||||
|
|
||||||
|
## Example: Complete Form
|
||||||
|
|
||||||
|
```html
|
||||||
|
<form
|
||||||
|
data-what="registration-form"
|
||||||
|
data-which="user-signup"
|
||||||
|
role="form"
|
||||||
|
aria-labelledby="form-title">
|
||||||
|
|
||||||
|
<h2 id="form-title">User Registration</h2>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label for="username-input">Username</label>
|
||||||
|
<input
|
||||||
|
id="username-input"
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="username"
|
||||||
|
data-what="username-input"
|
||||||
|
data-which="registration-form"
|
||||||
|
aria-required="true"
|
||||||
|
aria-describedby="username-hint" />
|
||||||
|
<span id="username-hint">Must be at least 3 characters</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-field">
|
||||||
|
<label for="email-input">Email</label>
|
||||||
|
<input
|
||||||
|
id="email-input"
|
||||||
|
type="email"
|
||||||
|
[(ngModel)]="email"
|
||||||
|
data-what="email-input"
|
||||||
|
data-which="registration-form"
|
||||||
|
aria-required="true"
|
||||||
|
[attr.aria-invalid]="emailError ? 'true' : null"
|
||||||
|
aria-describedby="email-error" />
|
||||||
|
@if (emailError) {
|
||||||
|
<span
|
||||||
|
id="email-error"
|
||||||
|
role="alert"
|
||||||
|
aria-live="polite">
|
||||||
|
{{ emailError }}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
(click)="onSubmit()"
|
||||||
|
data-what="submit-button"
|
||||||
|
data-which="registration-form"
|
||||||
|
[attr.aria-disabled]="!isValid"
|
||||||
|
aria-label="Submit registration form">
|
||||||
|
Register
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
(click)="onCancel()"
|
||||||
|
data-what="cancel-button"
|
||||||
|
data-which="registration-form"
|
||||||
|
aria-label="Cancel registration">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Remember
|
||||||
|
|
||||||
|
- **Always use both E2E and ARIA attributes together**
|
||||||
|
- **E2E attributes enable automated testing** - your QA team relies on them
|
||||||
|
- **ARIA attributes enable accessibility** - legal requirement and right thing to do
|
||||||
|
- **Test with real users and assistive technologies** - automated checks aren't enough
|
||||||
|
- **Keep attributes up-to-date** - maintain as code changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**This skill works automatically with Angular templates. Both E2E and ARIA attributes should be added to every interactive element.**
|
||||||
1107
.claude/skills/html-template/references/aria-attributes.md
Normal file
1107
.claude/skills/html-template/references/aria-attributes.md
Normal file
File diff suppressed because it is too large
Load Diff
1082
.claude/skills/html-template/references/combined-patterns.md
Normal file
1082
.claude/skills/html-template/references/combined-patterns.md
Normal file
File diff suppressed because it is too large
Load Diff
842
.claude/skills/html-template/references/e2e-attributes.md
Normal file
842
.claude/skills/html-template/references/e2e-attributes.md
Normal file
@@ -0,0 +1,842 @@
|
|||||||
|
# E2E Testing Attributes - Complete Reference
|
||||||
|
|
||||||
|
This reference provides comprehensive guidance for adding E2E (End-to-End) testing attributes to HTML templates for reliable automated testing.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Core Attribute Types](#core-attribute-types)
|
||||||
|
- [Why E2E Attributes?](#why-e2e-attributes)
|
||||||
|
- [Naming Conventions](#naming-conventions)
|
||||||
|
- [Patterns by Element Type](#patterns-by-element-type)
|
||||||
|
- [Patterns by Component Type](#patterns-by-component-type)
|
||||||
|
- [Dynamic Attributes](#dynamic-attributes)
|
||||||
|
- [Best Practices](#best-practices)
|
||||||
|
- [Validation](#validation)
|
||||||
|
- [Testing Integration](#testing-integration)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
E2E testing attributes provide stable, semantic selectors for automated testing. They enable QA automation without relying on brittle CSS classes, IDs, or XPath selectors that frequently break when styling changes.
|
||||||
|
|
||||||
|
## Core Attribute Types
|
||||||
|
|
||||||
|
### 1. `data-what` (Required)
|
||||||
|
**Purpose**: Semantic description of the element's purpose or type
|
||||||
|
|
||||||
|
**Format**: kebab-case string
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
- `data-what="submit-button"`
|
||||||
|
- `data-what="search-input"`
|
||||||
|
- `data-what="product-link"`
|
||||||
|
- `data-what="list-item"`
|
||||||
|
|
||||||
|
**Guidelines**:
|
||||||
|
- Describes WHAT the element is or does
|
||||||
|
- Should be consistent across similar elements
|
||||||
|
- Use descriptive, semantic names
|
||||||
|
- Keep it concise but clear
|
||||||
|
|
||||||
|
### 2. `data-which` (Required)
|
||||||
|
**Purpose**: Unique identifier for the specific instance of this element type
|
||||||
|
|
||||||
|
**Format**: kebab-case string or dynamic binding
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
- `data-which="primary"` (static)
|
||||||
|
- `data-which="customer-form"` (static)
|
||||||
|
- `[attr.data-which]="item.id"` (dynamic)
|
||||||
|
- `[attr.data-which]="'customer-' + customerId"` (dynamic with context)
|
||||||
|
|
||||||
|
**Guidelines**:
|
||||||
|
- Identifies WHICH specific instance of this element type
|
||||||
|
- Must be unique within the same view/component
|
||||||
|
- Use dynamic binding for list items: `[attr.data-which]="item.id"`
|
||||||
|
- Can combine multiple identifiers: `data-which="customer-123-edit"`
|
||||||
|
|
||||||
|
### 3. `data-*` (Contextual)
|
||||||
|
**Purpose**: Additional contextual information about state, status, or data
|
||||||
|
|
||||||
|
**Format**: Custom attributes with kebab-case names
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
- `data-status="active"`
|
||||||
|
- `data-index="0"`
|
||||||
|
- `data-role="admin"`
|
||||||
|
- `[attr.data-count]="items.length"`
|
||||||
|
|
||||||
|
**Guidelines**:
|
||||||
|
- Use for additional context that helps testing
|
||||||
|
- Avoid sensitive data (passwords, tokens, PII)
|
||||||
|
- Use Angular binding for dynamic values: `[attr.data-*]`
|
||||||
|
- Keep attribute names semantic and clear
|
||||||
|
|
||||||
|
## Why E2E Attributes?
|
||||||
|
|
||||||
|
### Problems with Traditional Selectors
|
||||||
|
|
||||||
|
**CSS Classes (Bad)**:
|
||||||
|
```html
|
||||||
|
<!-- Brittle - breaks when styling changes -->
|
||||||
|
<button class="btn btn-primary submit">Submit</button>
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
// Test breaks when class names change
|
||||||
|
await page.click('.btn-primary.submit');
|
||||||
|
```
|
||||||
|
|
||||||
|
**XPath (Bad)**:
|
||||||
|
```javascript
|
||||||
|
// Brittle - breaks when structure changes
|
||||||
|
await page.click('//div[@class="form"]/button[2]');
|
||||||
|
```
|
||||||
|
|
||||||
|
**IDs (Better, but limited)**:
|
||||||
|
```html
|
||||||
|
<!-- IDs must be unique across entire page -->
|
||||||
|
<button id="submit-btn">Submit</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Benefits of E2E Attributes
|
||||||
|
|
||||||
|
**Stable, Semantic Selectors (Good)**:
|
||||||
|
```html
|
||||||
|
<button
|
||||||
|
class="btn btn-primary"
|
||||||
|
data-what="submit-button"
|
||||||
|
data-which="registration-form">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
// Stable - survives styling and structure changes
|
||||||
|
await page.click('[data-what="submit-button"][data-which="registration-form"]');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages**:
|
||||||
|
- ✅ Decoupled from styling (CSS classes can change freely)
|
||||||
|
- ✅ Semantic and self-documenting
|
||||||
|
- ✅ Consistent across the application
|
||||||
|
- ✅ Easy to read and maintain
|
||||||
|
- ✅ Survives refactoring and restructuring
|
||||||
|
- ✅ QA and developers speak the same language
|
||||||
|
|
||||||
|
## Naming Conventions
|
||||||
|
|
||||||
|
### Common `data-what` Patterns
|
||||||
|
|
||||||
|
| Pattern | Use Case | Examples |
|
||||||
|
|---------|----------|----------|
|
||||||
|
| `*-button` | All button elements | `submit-button`, `cancel-button`, `delete-button`, `save-button` |
|
||||||
|
| `*-input` | Text inputs and textareas | `email-input`, `search-input`, `quantity-input`, `password-input` |
|
||||||
|
| `*-select` | Dropdown/select elements | `status-select`, `category-select`, `country-select` |
|
||||||
|
| `*-checkbox` | Checkbox inputs | `terms-checkbox`, `subscribe-checkbox`, `remember-checkbox` |
|
||||||
|
| `*-radio` | Radio button inputs | `payment-radio`, `shipping-radio` |
|
||||||
|
| `*-link` | Navigation links | `product-link`, `order-link`, `customer-link`, `home-link` |
|
||||||
|
| `*-item` | List/grid items | `list-item`, `menu-item`, `card-item`, `row-item` |
|
||||||
|
| `*-dialog` | Modals and dialogs | `confirm-dialog`, `error-dialog`, `info-dialog` |
|
||||||
|
| `*-dropdown` | Dropdown menus | `actions-dropdown`, `filter-dropdown` |
|
||||||
|
| `*-toggle` | Toggle switches | `theme-toggle`, `notifications-toggle` |
|
||||||
|
| `*-tab` | Tab navigation | `profile-tab`, `settings-tab` |
|
||||||
|
| `*-badge` | Status badges | `status-badge`, `count-badge` |
|
||||||
|
| `*-icon` | Interactive icons | `close-icon`, `menu-icon`, `search-icon` |
|
||||||
|
|
||||||
|
### `data-which` Naming Guidelines
|
||||||
|
|
||||||
|
**Static unique identifiers** (single instance):
|
||||||
|
- `data-which="primary"` - Primary action button
|
||||||
|
- `data-which="secondary"` - Secondary action button
|
||||||
|
- `data-which="main-search"` - Main search input
|
||||||
|
- `data-which="customer-form"` - Customer form context
|
||||||
|
|
||||||
|
**Dynamic identifiers** (multiple instances):
|
||||||
|
- `[attr.data-which]="item.id"` - List item by ID
|
||||||
|
- `[attr.data-which]="'product-' + product.id"` - Product item
|
||||||
|
- `[attr.data-which]="index"` - By array index (use sparingly)
|
||||||
|
|
||||||
|
**Contextual identifiers** (combine context):
|
||||||
|
- `data-which="customer-{{ customerId }}-edit"` - Edit button for specific customer
|
||||||
|
- `data-which="order-{{ orderId }}-cancel"` - Cancel button for specific order
|
||||||
|
|
||||||
|
## Patterns by Element Type
|
||||||
|
|
||||||
|
### Buttons
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Submit Button -->
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
(click)="onSubmit()"
|
||||||
|
data-what="submit-button"
|
||||||
|
data-which="registration-form">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Cancel Button -->
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
(click)="onCancel()"
|
||||||
|
data-what="cancel-button"
|
||||||
|
data-which="registration-form">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Delete Button with Confirmation -->
|
||||||
|
<button
|
||||||
|
(click)="onDelete(item)"
|
||||||
|
data-what="delete-button"
|
||||||
|
[attr.data-which]="item.id"
|
||||||
|
[attr.data-status]="item.canDelete ? 'enabled' : 'disabled'">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Icon Button -->
|
||||||
|
<button
|
||||||
|
(click)="toggleMenu()"
|
||||||
|
data-what="menu-button"
|
||||||
|
data-which="main-nav"
|
||||||
|
aria-label="Toggle menu">
|
||||||
|
<i class="icon-menu"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Custom Button Component -->
|
||||||
|
<ui-button
|
||||||
|
(click)="save()"
|
||||||
|
data-what="save-button"
|
||||||
|
data-which="order-form">
|
||||||
|
Save Order
|
||||||
|
</ui-button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inputs
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Text Input -->
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="email"
|
||||||
|
placeholder="Email address"
|
||||||
|
data-what="email-input"
|
||||||
|
data-which="registration-form" />
|
||||||
|
|
||||||
|
<!-- Textarea -->
|
||||||
|
<textarea
|
||||||
|
[(ngModel)]="comments"
|
||||||
|
data-what="comments-textarea"
|
||||||
|
data-which="feedback-form"
|
||||||
|
rows="4"></textarea>
|
||||||
|
|
||||||
|
<!-- Number Input with State -->
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
[(ngModel)]="quantity"
|
||||||
|
data-what="quantity-input"
|
||||||
|
data-which="order-form"
|
||||||
|
[attr.data-min]="minQuantity"
|
||||||
|
[attr.data-max]="maxQuantity" />
|
||||||
|
|
||||||
|
<!-- Search Input -->
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
[(ngModel)]="searchTerm"
|
||||||
|
(input)="onSearch()"
|
||||||
|
placeholder="Search products..."
|
||||||
|
data-what="search-input"
|
||||||
|
data-which="product-catalog" />
|
||||||
|
|
||||||
|
<!-- Password Input -->
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
[(ngModel)]="password"
|
||||||
|
data-what="password-input"
|
||||||
|
data-which="login-form" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Select/Dropdown
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Basic Select -->
|
||||||
|
<select
|
||||||
|
[(ngModel)]="selectedStatus"
|
||||||
|
data-what="status-select"
|
||||||
|
data-which="order-filter">
|
||||||
|
<option value="">All Statuses</option>
|
||||||
|
<option value="pending">Pending</option>
|
||||||
|
<option value="completed">Completed</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Custom Dropdown Component -->
|
||||||
|
<ui-dropdown
|
||||||
|
[(value)]="selectedCategory"
|
||||||
|
data-what="category-dropdown"
|
||||||
|
data-which="product-filter">
|
||||||
|
</ui-dropdown>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Checkboxes and Radios
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Checkbox -->
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
[(ngModel)]="agreedToTerms"
|
||||||
|
data-what="terms-checkbox"
|
||||||
|
data-which="registration-form" />
|
||||||
|
I agree to the terms
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- Radio Group -->
|
||||||
|
<div data-what="payment-radio-group" data-which="checkout-form">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="payment"
|
||||||
|
value="credit"
|
||||||
|
[(ngModel)]="paymentMethod"
|
||||||
|
data-what="payment-radio"
|
||||||
|
data-which="credit-card" />
|
||||||
|
Credit Card
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="payment"
|
||||||
|
value="paypal"
|
||||||
|
[(ngModel)]="paymentMethod"
|
||||||
|
data-what="payment-radio"
|
||||||
|
data-which="paypal" />
|
||||||
|
PayPal
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Links
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Static Link -->
|
||||||
|
<a
|
||||||
|
routerLink="/about"
|
||||||
|
data-what="nav-link"
|
||||||
|
data-which="about">
|
||||||
|
About Us
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Dynamic Link with ID -->
|
||||||
|
<a
|
||||||
|
[routerLink]="['/products', product.id]"
|
||||||
|
data-what="product-link"
|
||||||
|
[attr.data-which]="product.id">
|
||||||
|
{{ product.name }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- External Link -->
|
||||||
|
<a
|
||||||
|
href="https://example.com"
|
||||||
|
target="_blank"
|
||||||
|
data-what="external-link"
|
||||||
|
data-which="documentation">
|
||||||
|
Documentation
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Action Link (not navigation) -->
|
||||||
|
<a
|
||||||
|
(click)="downloadReport()"
|
||||||
|
data-what="download-link"
|
||||||
|
data-which="sales-report">
|
||||||
|
Download Report
|
||||||
|
</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lists and Tables
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Dynamic List with @for -->
|
||||||
|
<ul data-what="product-list" data-which="catalog">
|
||||||
|
@for (product of products; track product.id) {
|
||||||
|
<li
|
||||||
|
(click)="selectProduct(product)"
|
||||||
|
data-what="list-item"
|
||||||
|
[attr.data-which]="product.id"
|
||||||
|
[attr.data-status]="product.stock > 0 ? 'in-stock' : 'out-of-stock'">
|
||||||
|
{{ product.name }}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Table Row -->
|
||||||
|
<table data-what="orders-table" data-which="customer-orders">
|
||||||
|
<tbody>
|
||||||
|
@for (order of orders; track order.id) {
|
||||||
|
<tr
|
||||||
|
data-what="table-row"
|
||||||
|
[attr.data-which]="order.id">
|
||||||
|
<td>{{ order.id }}</td>
|
||||||
|
<td>{{ order.date }}</td>
|
||||||
|
<td>
|
||||||
|
<button
|
||||||
|
data-what="view-button"
|
||||||
|
[attr.data-which]="order.id">
|
||||||
|
View
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dialogs and Modals
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Confirmation Dialog -->
|
||||||
|
<div
|
||||||
|
*ngIf="showDialog"
|
||||||
|
data-what="confirmation-dialog"
|
||||||
|
data-which="delete-item">
|
||||||
|
|
||||||
|
<h2>Confirm Deletion</h2>
|
||||||
|
<p>Are you sure you want to delete this item?</p>
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="confirmDelete()"
|
||||||
|
data-what="confirm-button"
|
||||||
|
data-which="delete-dialog">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="cancelDelete()"
|
||||||
|
data-what="cancel-button"
|
||||||
|
data-which="delete-dialog">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Dialog with Close -->
|
||||||
|
<div
|
||||||
|
data-what="info-dialog"
|
||||||
|
data-which="welcome-message">
|
||||||
|
|
||||||
|
<button
|
||||||
|
(click)="closeDialog()"
|
||||||
|
data-what="close-button"
|
||||||
|
data-which="dialog">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div data-what="dialog-content" data-which="welcome">
|
||||||
|
<h2>Welcome!</h2>
|
||||||
|
<p>Thank you for joining us.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Patterns by Component Type
|
||||||
|
|
||||||
|
### Form Components
|
||||||
|
|
||||||
|
```html
|
||||||
|
<form data-what="user-form" data-which="registration">
|
||||||
|
<!-- Field inputs -->
|
||||||
|
<input
|
||||||
|
data-what="username-input"
|
||||||
|
data-which="registration-form"
|
||||||
|
type="text" />
|
||||||
|
|
||||||
|
<input
|
||||||
|
data-what="email-input"
|
||||||
|
data-which="registration-form"
|
||||||
|
type="email" />
|
||||||
|
|
||||||
|
<!-- Action buttons -->
|
||||||
|
<button
|
||||||
|
data-what="submit-button"
|
||||||
|
data-which="registration-form"
|
||||||
|
type="submit">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
data-what="cancel-button"
|
||||||
|
data-which="registration-form"
|
||||||
|
type="button">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
### List/Table Components
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Each item needs unique data-which -->
|
||||||
|
@for (item of items; track item.id) {
|
||||||
|
<div
|
||||||
|
data-what="list-item"
|
||||||
|
[attr.data-which]="item.id">
|
||||||
|
|
||||||
|
<span data-what="item-name" [attr.data-which]="item.id">
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<button
|
||||||
|
data-what="edit-button"
|
||||||
|
[attr.data-which]="item.id">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
data-what="delete-button"
|
||||||
|
[attr.data-which]="item.id">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Navigation Components
|
||||||
|
|
||||||
|
```html
|
||||||
|
<nav data-what="main-navigation" data-which="header">
|
||||||
|
<a
|
||||||
|
routerLink="/dashboard"
|
||||||
|
data-what="nav-link"
|
||||||
|
data-which="dashboard">
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
routerLink="/orders"
|
||||||
|
data-what="nav-link"
|
||||||
|
data-which="orders">
|
||||||
|
Orders
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
routerLink="/customers"
|
||||||
|
data-what="nav-link"
|
||||||
|
data-which="customers">
|
||||||
|
Customers
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Breadcrumbs -->
|
||||||
|
<nav data-what="breadcrumb" data-which="page-navigation">
|
||||||
|
@for (crumb of breadcrumbs; track $index) {
|
||||||
|
<a
|
||||||
|
[routerLink]="crumb.url"
|
||||||
|
data-what="breadcrumb-link"
|
||||||
|
[attr.data-which]="crumb.id">
|
||||||
|
{{ crumb.label }}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</nav>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dialog/Modal Components
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- All dialog buttons need clear identifiers -->
|
||||||
|
<div data-what="modal" data-which="user-settings">
|
||||||
|
<button
|
||||||
|
data-what="close-button"
|
||||||
|
data-which="modal">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
data-what="save-button"
|
||||||
|
data-which="modal">
|
||||||
|
Save Changes
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
data-what="reset-button"
|
||||||
|
data-which="modal">
|
||||||
|
Reset to Defaults
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dynamic Attributes
|
||||||
|
|
||||||
|
### Using Angular Binding
|
||||||
|
|
||||||
|
When values need to be dynamic, use Angular's attribute binding:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Static (simple values) -->
|
||||||
|
<button data-what="submit-button" data-which="form">
|
||||||
|
|
||||||
|
<!-- Dynamic (from component properties) -->
|
||||||
|
<button
|
||||||
|
data-what="submit-button"
|
||||||
|
[attr.data-which]="formId">
|
||||||
|
|
||||||
|
<!-- Dynamic (from loop variables) -->
|
||||||
|
@for (item of items; track item.id) {
|
||||||
|
<div
|
||||||
|
data-what="list-item"
|
||||||
|
[attr.data-which]="item.id"
|
||||||
|
[attr.data-status]="item.status"
|
||||||
|
[attr.data-index]="$index">
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Dynamic (computed values) -->
|
||||||
|
<button
|
||||||
|
data-what="action-button"
|
||||||
|
[attr.data-which]="'customer-' + customerId + '-' + action">
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loop Variables
|
||||||
|
|
||||||
|
Angular's `@for` provides special variables:
|
||||||
|
|
||||||
|
```html
|
||||||
|
@for (item of items; track item.id; let idx = $index; let isFirst = $first) {
|
||||||
|
<div
|
||||||
|
data-what="list-item"
|
||||||
|
[attr.data-which]="item.id"
|
||||||
|
[attr.data-index]="idx"
|
||||||
|
[attr.data-first]="isFirst">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Do's ✅
|
||||||
|
|
||||||
|
1. **Add to ALL interactive elements**
|
||||||
|
- Buttons, inputs, links, clickable elements
|
||||||
|
- Custom components that handle user interaction
|
||||||
|
- Form controls and navigation items
|
||||||
|
|
||||||
|
2. **Use consistent naming**
|
||||||
|
- Follow the naming patterns (e.g., `*-button`, `*-input`)
|
||||||
|
- Use kebab-case consistently
|
||||||
|
- Be descriptive but concise
|
||||||
|
|
||||||
|
3. **Ensure uniqueness**
|
||||||
|
- `data-which` must be unique within the view
|
||||||
|
- Use item IDs for list items: `[attr.data-which]="item.id"`
|
||||||
|
- Combine context when needed: `data-which="form-primary-submit"`
|
||||||
|
|
||||||
|
4. **Use Angular binding for dynamic values**
|
||||||
|
- `[attr.data-which]="item.id"` ✅
|
||||||
|
- `data-which="{{ item.id }}"` ❌ (avoid interpolation)
|
||||||
|
|
||||||
|
5. **Document complex patterns**
|
||||||
|
- Add comments for non-obvious attribute choices
|
||||||
|
- Document the expected test selectors
|
||||||
|
|
||||||
|
6. **Keep attributes updated**
|
||||||
|
- Update when element purpose changes
|
||||||
|
- Remove when elements are removed
|
||||||
|
- Maintain consistency across refactoring
|
||||||
|
|
||||||
|
### Don'ts ❌
|
||||||
|
|
||||||
|
1. **Don't include sensitive data**
|
||||||
|
- ❌ `data-which="password-{{ userPassword }}"`
|
||||||
|
- ❌ `data-token="{{ authToken }}"`
|
||||||
|
- ❌ `data-ssn="{{ socialSecurity }}"`
|
||||||
|
|
||||||
|
2. **Don't use generic values**
|
||||||
|
- ❌ `data-what="button"` (too generic)
|
||||||
|
- ✅ `data-what="submit-button"` (specific)
|
||||||
|
|
||||||
|
3. **Don't duplicate `data-which` in the same view**
|
||||||
|
- ❌ Two buttons with `data-which="primary"`
|
||||||
|
- ✅ `data-which="form-primary"` and `data-which="dialog-primary"`
|
||||||
|
|
||||||
|
4. **Don't rely only on index for lists**
|
||||||
|
- ❌ `[attr.data-which]="$index"` (changes when list reorders)
|
||||||
|
- ✅ `[attr.data-which]="item.id"` (stable identifier)
|
||||||
|
|
||||||
|
5. **Don't forget about custom components**
|
||||||
|
- Custom components need attributes too
|
||||||
|
- Attributes should be on the component tag, not just internal elements
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
### Coverage Check
|
||||||
|
|
||||||
|
Ensure all interactive elements have E2E attributes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Count interactive elements
|
||||||
|
grep -E '\(click\)|routerLink|button|input|select|textarea' component.html | wc -l
|
||||||
|
|
||||||
|
# Count elements with data-what
|
||||||
|
grep -c 'data-what=' component.html
|
||||||
|
|
||||||
|
# Find elements missing E2E attributes
|
||||||
|
grep -E '\(click\)|button' component.html | grep -v 'data-what='
|
||||||
|
```
|
||||||
|
|
||||||
|
### Uniqueness Check
|
||||||
|
|
||||||
|
Verify no duplicate `data-which` values in the same template:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// In component tests
|
||||||
|
it('should have unique data-which attributes', () => {
|
||||||
|
const elements = fixture.nativeElement.querySelectorAll('[data-which]');
|
||||||
|
const dataWhichValues = Array.from(elements).map(
|
||||||
|
(el: any) => el.getAttribute('data-which')
|
||||||
|
);
|
||||||
|
|
||||||
|
const uniqueValues = new Set(dataWhichValues);
|
||||||
|
expect(dataWhichValues.length).toBe(uniqueValues.size);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Checklist
|
||||||
|
|
||||||
|
- [ ] All buttons have `data-what` and `data-which`
|
||||||
|
- [ ] All inputs have `data-what` and `data-which`
|
||||||
|
- [ ] All links have `data-what` and `data-which`
|
||||||
|
- [ ] All clickable elements have attributes
|
||||||
|
- [ ] Dynamic lists use `[attr.data-which]="item.id"`
|
||||||
|
- [ ] No duplicate `data-which` values in the same view
|
||||||
|
- [ ] No sensitive data in attributes
|
||||||
|
- [ ] Custom components have attributes
|
||||||
|
- [ ] Attributes use kebab-case
|
||||||
|
- [ ] Coverage: 100% of interactive elements
|
||||||
|
|
||||||
|
## Testing Integration
|
||||||
|
|
||||||
|
### Using E2E Attributes in Tests
|
||||||
|
|
||||||
|
**Unit Tests (Angular Testing Utilities)**:
|
||||||
|
```typescript
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
describe('MyComponent', () => {
|
||||||
|
let fixture: ComponentFixture<MyComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [MyComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(MyComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have submit button with E2E attributes', () => {
|
||||||
|
const button = fixture.nativeElement.querySelector(
|
||||||
|
'[data-what="submit-button"][data-which="registration-form"]'
|
||||||
|
);
|
||||||
|
expect(button).toBeTruthy();
|
||||||
|
expect(button.textContent).toContain('Submit');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have unique data-which for list items', () => {
|
||||||
|
const items = fixture.nativeElement.querySelectorAll('[data-what="list-item"]');
|
||||||
|
const dataWhichValues = Array.from(items).map(
|
||||||
|
(item: any) => item.getAttribute('data-which')
|
||||||
|
);
|
||||||
|
|
||||||
|
// All should have unique IDs
|
||||||
|
const uniqueValues = new Set(dataWhichValues);
|
||||||
|
expect(dataWhichValues.length).toBe(uniqueValues.size);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**E2E Tests (Playwright)**:
|
||||||
|
```typescript
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('user registration flow', async ({ page }) => {
|
||||||
|
await page.goto('/register');
|
||||||
|
|
||||||
|
// Fill form using E2E attributes
|
||||||
|
await page.fill(
|
||||||
|
'[data-what="username-input"][data-which="registration-form"]',
|
||||||
|
'johndoe'
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.fill(
|
||||||
|
'[data-what="email-input"][data-which="registration-form"]',
|
||||||
|
'john@example.com'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Click submit using E2E attributes
|
||||||
|
await page.click(
|
||||||
|
'[data-what="submit-button"][data-which="registration-form"]'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify success
|
||||||
|
await expect(page.locator('[data-what="success-message"]')).toBeVisible();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**E2E Tests (Cypress)**:
|
||||||
|
```typescript
|
||||||
|
describe('Order Management', () => {
|
||||||
|
it('should edit an order', () => {
|
||||||
|
cy.visit('/orders');
|
||||||
|
|
||||||
|
// Find specific order by ID using data-which
|
||||||
|
cy.get('[data-what="list-item"][data-which="order-123"]')
|
||||||
|
.should('be.visible');
|
||||||
|
|
||||||
|
// Click edit button for that specific order
|
||||||
|
cy.get('[data-what="edit-button"][data-which="order-123"]')
|
||||||
|
.click();
|
||||||
|
|
||||||
|
// Update quantity
|
||||||
|
cy.get('[data-what="quantity-input"][data-which="order-form"]')
|
||||||
|
.clear()
|
||||||
|
.type('5');
|
||||||
|
|
||||||
|
// Save changes
|
||||||
|
cy.get('[data-what="save-button"][data-which="order-form"]')
|
||||||
|
.click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation in Templates
|
||||||
|
|
||||||
|
Add comment blocks to document E2E attributes:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!--
|
||||||
|
E2E Test Attributes:
|
||||||
|
- data-what="submit-button" data-which="registration-form" - Main form submission
|
||||||
|
- data-what="cancel-button" data-which="registration-form" - Cancel registration
|
||||||
|
- data-what="username-input" data-which="registration-form" - Username field
|
||||||
|
- data-what="email-input" data-which="registration-form" - Email field
|
||||||
|
- data-what="password-input" data-which="registration-form" - Password field
|
||||||
|
-->
|
||||||
|
|
||||||
|
<form data-what="registration-form" data-which="user-signup">
|
||||||
|
<!-- Form content -->
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- **[ARIA Accessibility Attributes](aria-attributes.md)** - Accessibility guidance
|
||||||
|
- **[Combined Patterns](combined-patterns.md)** - Examples with E2E + ARIA together
|
||||||
|
- **Testing Guidelines**: `docs/guidelines/testing.md` - Project testing standards
|
||||||
|
- **CLAUDE.md**: Project code quality requirements
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
E2E testing attributes are essential for:
|
||||||
|
- ✅ Stable, maintainable automated tests
|
||||||
|
- ✅ Clear communication between developers and QA
|
||||||
|
- ✅ Tests that survive styling and structural changes
|
||||||
|
- ✅ Self-documenting code that expresses intent
|
||||||
|
- ✅ Reliable CI/CD pipelines
|
||||||
|
|
||||||
|
**Always add `data-what` and `data-which` to every interactive element.**
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: tailwind-isa
|
name: tailwind
|
||||||
description: This skill should be used when working with Tailwind CSS styling in the ISA-Frontend project. Use it when writing component styles, choosing color values, applying typography, creating buttons, or determining appropriate spacing and layout utilities. Essential for maintaining design system consistency.
|
description: This skill should be used when working with Tailwind CSS styling in the ISA-Frontend project. Use it when writing component styles, choosing color values, applying typography, creating buttons, or determining appropriate spacing and layout utilities. Essential for maintaining design system consistency.
|
||||||
---
|
---
|
||||||
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -78,3 +78,5 @@ vitest.config.*.timestamp*
|
|||||||
nx.instructions.md
|
nx.instructions.md
|
||||||
CLAUDE.md
|
CLAUDE.md
|
||||||
*.pyc
|
*.pyc
|
||||||
|
.vite
|
||||||
|
reports/
|
||||||
|
|||||||
@@ -17,6 +17,13 @@
|
|||||||
"figma-desktop": {
|
"figma-desktop": {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
"url": "http://127.0.0.1:3845/mcp"
|
"url": "http://127.0.0.1:3845/mcp"
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@modelcontextprotocol/server-memory"],
|
||||||
|
"env": {
|
||||||
|
"MEMORY_FILE_PATH": "~/Projects/ISA-Frontend/memory.json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
139
CHANGELOG.md
Normal file
139
CHANGELOG.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (checkout-reward) Disable and hide delivery options for reward feature purchases
|
||||||
|
- (purchase-options) Add disabledPurchaseOptions with flexible visibility control
|
||||||
|
- (reward-catalog) Pre-select in-store option for reward purchases
|
||||||
|
- (checkout) Complete reward order confirmation with reusable product info component
|
||||||
|
- (checkout) Implement reward order confirmation UI and confirmation list item action card component
|
||||||
|
- (checkout) Add reward order confirmation feature with schema migrations
|
||||||
|
- (stock-info) Implement request batching with BatchingResource
|
||||||
|
- (crm) Introduce PrimaryCustomerCardResource and format-name utility
|
||||||
|
- Angular template skill for modern template patterns
|
||||||
|
- Tailwind ISA design system skill
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (checkout-reward) Implement hierarchical grouping on rewards order confirmation
|
||||||
|
- (checkout) Move reward selection helpers to data-access for reusability
|
||||||
|
- (common) Add validation for notification channel flag combinations
|
||||||
|
- (customer) Merge continueReward and continue methods into unified flow
|
||||||
|
- Comprehensive CLAUDE.md overhaul with library reference system
|
||||||
|
- Add Claude Code agents, commands, and skills infrastructure
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- (checkout) Resolve currency constraint violations in price handling
|
||||||
|
- (checkout) Add complete price structure for reward delivery orders
|
||||||
|
- (checkout) Correct reward output desktop/mobile layout and add insufficient stock warnings
|
||||||
|
- (customer-card) Implement navigation flow from customer card to reward search
|
||||||
|
- (purchase-options) Correct customer features mapping
|
||||||
|
- (reward-order-confirmation) Group items by item-level delivery type
|
||||||
|
- (reward-order-confirmation) Correct typo and add loading state to collect button
|
||||||
|
- (reward-confirmation) Improve action card visibility and status messages
|
||||||
|
- (reward-selection-pop-up) Fix width issue
|
||||||
|
|
||||||
|
## [4.2] - 2025-10-23
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (checkout-reward) Add reward checkout feature (#5258)
|
||||||
|
- (crm) Add crm-data-access library with initial component and tests
|
||||||
|
- (shared-filter) Add canApply input to filter input menu components
|
||||||
|
- Architecture Decision Records (ADRs) documentation
|
||||||
|
- Error handling and validation infrastructure enhancements
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (tabs) Implement backwards compatibility for Process → Tabs migration
|
||||||
|
- (notifications) Update remission path logic to use Date.now()
|
||||||
|
- (customer-card) Deactivate Create Customer with Card feature
|
||||||
|
- Update package.json and recreate package-lock.json for npm@11.6
|
||||||
|
- Disable markdown format on save in VSCode settings
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- (process) Simulate "old tab logic" for compatibility
|
||||||
|
- (tabs) Correct singleton tabs interaction with new tab areas
|
||||||
|
- (remission-list) Prioritize reload trigger over exact search
|
||||||
|
- (remission-list-item, remission-list-empty-state) Improve empty state handling
|
||||||
|
|
||||||
|
## [4.1] - 2025-10-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (isa-app) Migrate remission navigation to tab-based routing system
|
||||||
|
- (utils) Add scroll-top button component
|
||||||
|
- (remission-list, empty-state) Add comprehensive empty state handling with user guidance
|
||||||
|
- (remission) Ensure package assignment before completing return receipts
|
||||||
|
- (libs-ui-dialog-feedback-dialog) Add auto-close functionality with configurable delay
|
||||||
|
- (old-ui-tooltip) Add pointer-events-auto to tooltip panel
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (remission-list) Improve item update handling and UI feedback
|
||||||
|
- (remission-list, search-item-to-remit-dialog) Simplify dialog flow by removing intermediate steps
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- (remission-list) Ensure list reload after search dialog closes
|
||||||
|
- (remission-list) Auto-select single search result when remission started
|
||||||
|
- (remission-list, remission-return-receipt-details, libs-dialog) Improve error handling with dedicated error dialog
|
||||||
|
- (remission-error) Simplify error handling in remission components
|
||||||
|
- (remission) Filter search results by stock availability and display stock info
|
||||||
|
- (remission-list, remission-data-access) Add impediment comment and remaining quantity tracking
|
||||||
|
- (remission-quantity-and-reason-item) Correct quantity input binding and dropdown behavior
|
||||||
|
- (remission-quantity-reason) Correct dropdown placeholder and remove hardcoded values
|
||||||
|
- (remission-filter-label) Improve filter button label display and default text
|
||||||
|
- (remission-data-access) Remove automatic date defaulting in fetchRemissions
|
||||||
|
- (remission-shared-search-item-to-remit-dialog) Display context-aware feedback on errors
|
||||||
|
- (isa-app-shell) Improve navigation link targeting for remission sub-routes
|
||||||
|
- (oms-data-access) Adjust tolino return eligibility logic for display damage
|
||||||
|
- (ui-input-controls-dropdown) Prevent multiple dropdowns from being open simultaneously
|
||||||
|
|
||||||
|
## [4.0] - 2025-07-23
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (oms-data-access) Initial implementation of OMS data access layer
|
||||||
|
- (oms-return-review) Implement return review feature
|
||||||
|
- (print-button) Implement reusable print button component with service integration
|
||||||
|
- (scanner) Add full-screen scanner styles and components
|
||||||
|
- (product-router-link) Add shared product router link directive and builder
|
||||||
|
- (tooltip) Add tooltip component and directive with customizable triggers
|
||||||
|
- (shared-scanner) Move scanner to shared/scanner location
|
||||||
|
- (common-data-access) Add takeUntil operators for keydown events
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (oms-return-review, oms-return-summary) Fix return receipt mapping and ensure process completion
|
||||||
|
- (ui-tooltip) Remove native title attribute from tooltip icon host
|
||||||
|
- (oms-return-details) Improve layout and styling of order group item controls
|
||||||
|
- (searchbox) Improve formatting and add showScannerButton getter
|
||||||
|
- (libs-ui-item-rows) Improve data value wrapping and label sizing
|
||||||
|
- (shared-filter, search-bar, search-main) Add E2E data attributes for filtering and search
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- (return-details) Update email validation and improve error handling
|
||||||
|
- (return-details) Correct storage key retrieval in ReturnDetailsStore
|
||||||
|
- (return-details) Small layout fix (#5171)
|
||||||
|
- (isa-app-moment-locale) Correct locale initialization for date formatting
|
||||||
|
- (oms-return-search) Fix display and logic issues in return search results
|
||||||
|
- (oms-return-search) Resolve issues in return search result item rendering
|
||||||
|
- (oms-task-list-item) Address styling and layout issues in return task list
|
||||||
|
- (ui-dropdown) Improve dropdown usability and conditional rendering
|
||||||
|
- (return-search) Correct typo in tooltip content
|
||||||
|
- (libs-shared-filter) Improve date range equality for default filter inputs
|
||||||
|
|
||||||
|
## [3.4] - 2025-02-10
|
||||||
|
|
||||||
|
_Earlier versions available in git history. Detailed changelog entries start from version 4.0._
|
||||||
|
|
||||||
|
### Historical Versions
|
||||||
|
|
||||||
|
Previous versions (3.3, 3.2, 3.1, 3.0, 2.x, 1.x) are available in the git repository.
|
||||||
|
For detailed information about changes in these versions, please refer to:
|
||||||
|
- Git tags: `git tag --sort=-creatordate`
|
||||||
|
- Commit history: `git log <tag-from>..<tag-to>`
|
||||||
|
- Pull requests in the repository
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_This changelog was initially generated from git commit history. Future entries will be maintained manually following the Keep a Changelog format._
|
||||||
348
CLAUDE.md
348
CLAUDE.md
@@ -1,277 +1,34 @@
|
|||||||
# CLAUDE.md
|
# CLAUDE.md
|
||||||
|
|
||||||
> **Last Updated:** 2025-10-22
|
This file contains meta-instructions for how Claude should work with the ISA-Frontend codebase.
|
||||||
> **Angular Version:** 20.1.2
|
|
||||||
> **Nx Version:** 21.3.2
|
|
||||||
> **Node.js:** ≥22.0.0
|
|
||||||
> **npm:** ≥10.0.0
|
|
||||||
|
|
||||||
## 🔴 CRITICAL: Mandatory Agent Usage
|
## 🔴 CRITICAL: Mandatory Agent Usage
|
||||||
|
|
||||||
**You MUST use these subagents for ALL research tasks:**
|
**You MUST use these subagents for ALL research and knowledge management tasks:**
|
||||||
- **`docs-researcher`**: For ALL documentation (packages, libraries, READMEs)
|
- **`docs-researcher`**: For ALL documentation (packages, libraries, READMEs)
|
||||||
- **`docs-researcher-advanced`**: Auto-escalate when docs-researcher fails
|
- **`docs-researcher-advanced`**: Auto-escalate when docs-researcher fails
|
||||||
- **`Explore`**: For ALL code pattern searches and multi-file analysis
|
- **`Explore`**: For ALL code pattern searches and multi-file analysis
|
||||||
|
- **`context-manager`**: For complex projects and knowledge preservation with **persistent memory**
|
||||||
- **Direct tools (Read/Bash)**: ONLY for single specific files or commands
|
- **Direct tools (Read/Bash)**: ONLY for single specific files or commands
|
||||||
|
|
||||||
|
**NEW**: The `context-manager` now autonomously stores project knowledge (decisions, patterns, solutions) in persistent memory for cross-session learning.
|
||||||
|
|
||||||
**Violations of this rule degrade performance and context quality. NO EXCEPTIONS.**
|
**Violations of this rule degrade performance and context quality. NO EXCEPTIONS.**
|
||||||
|
|
||||||
## Project Overview
|
## Communication Guidelines
|
||||||
|
|
||||||
This is a sophisticated Angular 20.1.2 monorepo managed by Nx 21.3.2. The main application is `isa-app`, a comprehensive inventory and returns management system for retail/e-commerce operations. The system handles complex workflows including order management (OMS), returns processing (remission), customer relationship management (CRM), product cataloging, and checkout/reward systems.
|
**Keep answers concise and focused:**
|
||||||
|
- Provide direct, actionable responses without unnecessary elaboration
|
||||||
|
- Skip verbose explanations unless specifically requested
|
||||||
|
- Focus on what the user needs to know, not everything you know
|
||||||
|
- Use bullet points and structured formatting for clarity
|
||||||
|
- Only provide detailed explanations when complexity requires it
|
||||||
|
|
||||||
## Architecture
|
## Researching and Investigating the Codebase
|
||||||
|
|
||||||
### Monorepo Structure
|
|
||||||
- **apps/isa-app**: Main Angular application
|
|
||||||
- **libs/**: Reusable libraries organized by domain and type
|
|
||||||
- **core/**: Core utilities (config, logging, storage, tabs, navigation)
|
|
||||||
- **common/**: Shared utilities (data-access, decorators, print)
|
|
||||||
- **ui/**: UI component libraries (buttons, dialogs, inputs, etc.)
|
|
||||||
- **shared/**: Shared domain components (filter, scanner, product components)
|
|
||||||
- **oms/**: Order Management System features and utilities
|
|
||||||
- **remission/**: Remission/returns management features
|
|
||||||
- **catalogue/**: Product catalogue functionality
|
|
||||||
- **utils/**: General utilities (validation, scroll position, parsing)
|
|
||||||
- **icons/**: Icon library
|
|
||||||
- **generated/swagger/**: Auto-generated API client code from OpenAPI specs
|
|
||||||
|
|
||||||
### Key Architectural Patterns
|
|
||||||
- **Domain-Driven Design**: Clear domain boundaries with dedicated modules (OMS, remission, CRM, catalogue, checkout)
|
|
||||||
- **Layered Architecture**: Strict dependency hierarchy (Feature → Shared/UI → Data Access → Infrastructure)
|
|
||||||
- **Standalone Components**: All new components use Angular standalone architecture with explicit imports
|
|
||||||
- **Feature Libraries**: Domain features organized as separate libraries (e.g., `oms-feature-return-search`, `remission-feature-remission-list`)
|
|
||||||
- **Data Access Layer**: Separate data-access libraries for each domain with NgRx Signals stores
|
|
||||||
- **Shared UI Components**: 17 dedicated UI component libraries with design system integration
|
|
||||||
- **Generated API Clients**: 10 auto-generated Swagger/OpenAPI clients with post-processing pipeline
|
|
||||||
- **Path Aliases**: Comprehensive TypeScript path mapping (`@isa/domain/layer/feature`)
|
|
||||||
- **Component Prefixes**: Domain-specific prefixes (OMS: `oms-feature-*`, Remission: `remi-*`, UI: `ui-*`)
|
|
||||||
- **Modern State Management**: NgRx Signals with entities, session persistence, and reactive patterns
|
|
||||||
|
|
||||||
## Common Development Commands
|
|
||||||
|
|
||||||
### Essential Commands (Project-Specific)
|
|
||||||
```bash
|
|
||||||
# Start development server with SSL (required for authentication flows)
|
|
||||||
npm start
|
|
||||||
|
|
||||||
# Run tests for all libraries (excludes main app)
|
|
||||||
npm test
|
|
||||||
|
|
||||||
# Build for development
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Build for production
|
|
||||||
npm run build-prod
|
|
||||||
|
|
||||||
# Regenerate all API clients from Swagger/OpenAPI specs
|
|
||||||
npm run generate:swagger
|
|
||||||
|
|
||||||
# Regenerate library reference documentation
|
|
||||||
npm run docs:generate
|
|
||||||
|
|
||||||
# Format code with Prettier
|
|
||||||
npm run prettier
|
|
||||||
|
|
||||||
# Format only staged files (pre-commit hook)
|
|
||||||
npm run pretty-quick
|
|
||||||
|
|
||||||
# Run CI tests with coverage
|
|
||||||
npm run ci
|
|
||||||
```
|
|
||||||
|
|
||||||
### Standard Nx Commands
|
|
||||||
For complete command reference, see [Nx Documentation](https://nx.dev/reference/commands).
|
|
||||||
|
|
||||||
**Common patterns:**
|
|
||||||
```bash
|
|
||||||
# Test specific library (always use --skip-nx-cache)
|
|
||||||
npx nx test <project-name> --skip-nx-cache
|
|
||||||
|
|
||||||
# Lint a project
|
|
||||||
npx nx lint <project-name>
|
|
||||||
|
|
||||||
# Show project dependencies
|
|
||||||
npx nx graph
|
|
||||||
|
|
||||||
# Run tests for affected projects (CI/CD)
|
|
||||||
npx nx affected:test --skip-nx-cache
|
|
||||||
```
|
|
||||||
|
|
||||||
**Important:** Always use `--skip-nx-cache` flag when running tests to ensure fresh results.
|
|
||||||
|
|
||||||
## Testing Framework
|
|
||||||
|
|
||||||
> **Last Reviewed:** 2025-10-22
|
|
||||||
> **Status:** Migration in Progress (Jest → Vitest)
|
|
||||||
|
|
||||||
### Current Setup (Migration in Progress)
|
|
||||||
- **Jest**: 40 libraries (65.6% - legacy/existing code)
|
|
||||||
- **Vitest**: 21 libraries (34.4% - new standard)
|
|
||||||
- All formal libraries now have test executors configured
|
|
||||||
|
|
||||||
### Testing Strategy
|
|
||||||
- **New libraries**: Use Vitest + Angular Testing Utilities (TestBed, ComponentFixture)
|
|
||||||
- **Legacy libraries**: Continue with Jest + Spectator until migrated
|
|
||||||
- **Advanced mocking**: Use ng-mocks for complex scenarios
|
|
||||||
|
|
||||||
### Key Requirements
|
|
||||||
- Test files must end with `.spec.ts`
|
|
||||||
- Use AAA pattern (Arrange-Act-Assert)
|
|
||||||
- **Always include E2E attributes**: `data-what`, `data-which`, and dynamic `data-*` in HTML templates
|
|
||||||
- Mock external dependencies appropriately for your framework
|
|
||||||
|
|
||||||
**For detailed testing guidelines, framework comparison, and migration instructions, see [`docs/guidelines/testing.md`](docs/guidelines/testing.md).**
|
|
||||||
|
|
||||||
**References:**
|
|
||||||
- [Jest Documentation](https://jestjs.io/)
|
|
||||||
- [Vitest Documentation](https://vitest.dev/)
|
|
||||||
- [Angular Testing Guide](https://angular.io/guide/testing)
|
|
||||||
- [Spectator](https://ngneat.github.io/spectator/)
|
|
||||||
|
|
||||||
## State Management
|
|
||||||
- **NgRx Signals**: Primary state management with modern functional approach using `signalStore()`
|
|
||||||
- **Entity Management**: Uses `withEntities()` for normalized data storage
|
|
||||||
- **Session Persistence**: State persistence with `withStorage()` using SessionStorageProvider
|
|
||||||
- **Reactive Methods**: `rxMethod()` with `takeUntilKeydownEscape()` for user-cancellable operations
|
|
||||||
- **Custom RxJS Operators**: Specialized operators like `takeUntilAborted()`, `takeUntilKeydown()`
|
|
||||||
- **Error Handling**: `tapResponse()` for handling success/error states in stores
|
|
||||||
- **Lifecycle Hooks**: `withHooks()` for cleanup and initialization (e.g., orphaned entity cleanup)
|
|
||||||
- **Navigation State**: Use `@isa/core/navigation` for temporary navigation context (return URLs, wizard state) instead of query parameters
|
|
||||||
|
|
||||||
## Styling and Design System
|
|
||||||
- **Framework**: [Tailwind CSS](https://tailwindcss.com/docs) with extensive ISA-specific customization
|
|
||||||
- **Custom Breakpoints**: `isa-desktop` (1024px), `isa-desktop-l` (1440px), `isa-desktop-xl` (1920px)
|
|
||||||
- **Brand Color System**: `isa-*` color palette with semantic naming
|
|
||||||
- **Custom Tailwind Plugins** (7): button, typography, menu, label, input, section, select-bullet
|
|
||||||
- **Typography System**: 14 custom utilities (`.isa-text-heading-1-bold`, `.isa-text-body-2-regular`, etc.)
|
|
||||||
- **UI Component Libraries**: 17 specialized libraries with consistent APIs (see Library Reference)
|
|
||||||
- **Storybook**: Component documentation and development at `npm run storybook`
|
|
||||||
|
|
||||||
### Responsive Design with Breakpoint Service
|
|
||||||
Use `@isa/ui/layout` for reactive breakpoint detection instead of CSS-only solutions:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { breakpoint, Breakpoint } from '@isa/ui/layout';
|
|
||||||
|
|
||||||
// Detect screen size reactively
|
|
||||||
isDesktop = breakpoint([Breakpoint.Desktop, Breakpoint.DekstopL, Breakpoint.DekstopXL]);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Available Breakpoints:**
|
|
||||||
- `Tablet`: max-width: 1279px (mobile/tablet)
|
|
||||||
- `Desktop`: 1280px - 1439px (standard desktop)
|
|
||||||
- `DekstopL`: 1440px - 1919px (large desktop)
|
|
||||||
- `DekstopXL`: 1920px+ (extra large)
|
|
||||||
|
|
||||||
**Template Usage:**
|
|
||||||
```html
|
|
||||||
@if (isDesktop) {
|
|
||||||
<!-- Desktop-specific content -->
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Why:** Prefer breakpoint service over CSS-only (hidden/flex) for SSR and maintainability.
|
|
||||||
|
|
||||||
## API Integration and Data Access
|
|
||||||
|
|
||||||
**Generated Swagger Clients:** 10 auto-generated TypeScript clients in `generated/swagger/`
|
|
||||||
- Available APIs: availability-api, cat-search-api, checkout-api, crm-api, eis-api, inventory-api, isa-api, oms-api, print-api, wws-api
|
|
||||||
- Tool: [ng-swagger-gen](https://www.npmjs.com/package/ng-swagger-gen) with custom per-API configuration
|
|
||||||
- Post-processing: Automatic Unicode cleanup via `tools/fix-files.js`
|
|
||||||
- Regenerate: `npm run generate:swagger`
|
|
||||||
|
|
||||||
**Architecture Pattern:**
|
|
||||||
- Business logic services wrap generated API clients
|
|
||||||
- Type safety: TypeScript + [Zod](https://zod.dev/) schema validation
|
|
||||||
- Error handling: Global HTTP interceptor with automatic re-authentication
|
|
||||||
- Modern injection: Uses `inject()` function with private field pattern
|
|
||||||
- Request cancellation: Built-in via AbortSignal and custom RxJS operators (`takeUntilAborted()`, `takeUntilKeydown()`)
|
|
||||||
|
|
||||||
**Data Access Libraries:** See Library Reference section for domain-specific implementations (`@isa/[domain]/data-access`).
|
|
||||||
|
|
||||||
## Build Configuration
|
|
||||||
- **Framework**: Angular with TypeScript (see `package.json` for current versions)
|
|
||||||
- **Requirements**:
|
|
||||||
- Node.js >= 22.0.0 (specified in package.json engines)
|
|
||||||
- npm >= 10.0.0 (specified in package.json engines)
|
|
||||||
- **Build System**: Nx monorepo with Vite for testing (Vitest)
|
|
||||||
- **Development Server**: Serves with SSL by default (required for authentication flows)
|
|
||||||
|
|
||||||
## Important Conventions and Patterns
|
|
||||||
|
|
||||||
### Library Organization
|
|
||||||
- **Naming Pattern**: `[domain]-[layer]-[feature]` (e.g., `oms-feature-return-search`, `ui-buttons`)
|
|
||||||
- **Path Aliases**: `@isa/[domain]/[layer]/[feature]` (e.g., `@isa/oms/data-access`, `@isa/ui/buttons`)
|
|
||||||
- **Project Names**: Found in each library's `project.json` file, following consistent naming
|
|
||||||
|
|
||||||
### Component Architecture
|
|
||||||
- **Standalone Components**: All new components must be standalone with explicit imports
|
|
||||||
- **Component Prefixes**: Domain-specific prefixes for clear identification
|
|
||||||
- OMS features: `oms-feature-*` (e.g., `oms-feature-return-search-main`)
|
|
||||||
- Remission features: `remi-*`
|
|
||||||
- UI components: `ui-*`
|
|
||||||
- Core utilities: `core-*`
|
|
||||||
- **Signal-based Inputs**: Use Angular signals (`input()`, `computed()`) for reactive properties
|
|
||||||
- **Host Binding**: Dynamic CSS classes via Angular host properties
|
|
||||||
|
|
||||||
### Dependency Rules
|
|
||||||
- **Unidirectional Dependencies**: Feature → Shared/UI → Data Access → Infrastructure
|
|
||||||
- **Import Boundaries**: Use path aliases, avoid relative imports across domain boundaries
|
|
||||||
- **Generated API Imports**: Import from `@generated/swagger/[api-name]` for API clients
|
|
||||||
|
|
||||||
### Code Quality
|
|
||||||
- **Modern Angular Patterns**: Prefer `inject()` over constructor injection
|
|
||||||
- **Type Safety**: Use Zod schemas for runtime validation alongside TypeScript
|
|
||||||
- **Error Handling**: Custom error classes with specific error codes
|
|
||||||
- **E2E Testing**: Always include `data-what` and `data-which` attributes in templates
|
|
||||||
|
|
||||||
## Development Workflow and Best Practices
|
|
||||||
|
|
||||||
### Project Conventions
|
|
||||||
- **Default Branch**: `develop` (not main) - Always create PRs against develop
|
|
||||||
- **Branch Naming**: When starting work on a new feature or bug, create a branch following this pattern:
|
|
||||||
- Format: `feature/{task-id}-{short-description}` or `bugfix/{task-id}-{short-description}`
|
|
||||||
- Use English kebab-case for the description
|
|
||||||
- Start with the task/issue ID (e.g., `5391`)
|
|
||||||
- Keep description concise - shorten if the full title is too long
|
|
||||||
- Example: For task "#5391 Prämie Checkout // Action Card - Versandbestellung"
|
|
||||||
- Branch: `feature/5391-praemie-checkout-action-card-delivery-order`
|
|
||||||
- **Commit Style**: [Conventional commits](https://www.conventionalcommits.org/) without co-author tags
|
|
||||||
- **Nx Cache**: Always use `--skip-nx-cache` for tests to ensure fresh results
|
|
||||||
- **Testing**: New libraries use Vitest + Angular Testing Utilities; legacy use Jest + Spectator
|
|
||||||
- **E2E Attributes**: Always include `data-what`, `data-which`, and dynamic `data-*` in templates
|
|
||||||
- **Design System**: Use ISA-specific Tailwind utilities (`isa-accent-*`, `isa-text-*`)
|
|
||||||
|
|
||||||
### Code Quality Tools
|
|
||||||
- **Linting**: [ESLint](https://eslint.org/) with Nx dependency checks
|
|
||||||
- **Formatting**: [Prettier](https://prettier.io/) with Husky + lint-staged pre-commit hooks
|
|
||||||
- **Type Safety**: [TypeScript](https://www.typescriptlang.org/) strict mode + [Zod](https://zod.dev/) validation
|
|
||||||
- **Bundle Size**: Monitor carefully (2MB warning, 5MB error for main bundle)
|
|
||||||
|
|
||||||
### Nx Workflow Tips
|
|
||||||
- Use `npx nx graph` to visualize dependencies
|
|
||||||
- Use `npx nx affected:test` for CI/CD optimization
|
|
||||||
- Reference: [Nx Documentation](https://nx.dev/getting-started/intro)
|
|
||||||
|
|
||||||
## Development Notes and Guidelines
|
|
||||||
|
|
||||||
### Getting Started
|
|
||||||
- **Application Startup**: Only `isa-app` can be started - it's the main application entry point
|
|
||||||
- **SSL Development**: The development server runs with SSL by default (`npm start`), which is crucial for production-like authentication flows
|
|
||||||
- **Node Requirements**: Ensure Node.js ≥22.0.0 and npm ≥10.0.0 before starting development
|
|
||||||
- **First-Time Setup**: After cloning, run `npm install` then `npm start` to verify everything works
|
|
||||||
|
|
||||||
### Essential Documentation References
|
|
||||||
- **Testing Guidelines**: Review `docs/guidelines/testing.md` before writing any tests - it covers the Jest→Vitest migration, Spectator→Angular Testing Utilities transition, and E2E attribute requirements
|
|
||||||
- **Code Review Standards**: Follow the structured review process in `.github/review-instructions.md` with categorized feedback (🚨 Critical, ❗ Minor, ⚠️ Warnings, ✅ Good Practices)
|
|
||||||
- **E2E Testing Requirements**: Always include `data-what`, `data-which`, and dynamic `data-*` attributes in HTML templates - these are essential for automated testing by QA colleagues
|
|
||||||
|
|
||||||
### Researching and Investigating the Codebase
|
|
||||||
|
|
||||||
**🔴 MANDATORY: You MUST use subagents for research. Direct file reading/searching is FORBIDDEN except for single specific files.**
|
**🔴 MANDATORY: You MUST use subagents for research. Direct file reading/searching is FORBIDDEN except for single specific files.**
|
||||||
|
|
||||||
#### Required Agent Usage
|
### Required Agent Usage
|
||||||
|
|
||||||
| Task Type | Required Agent | Escalation Path |
|
| Task Type | Required Agent | Escalation Path |
|
||||||
|-----------|---------------|-----------------|
|
|-----------|---------------|-----------------|
|
||||||
@@ -281,7 +38,7 @@ isDesktop = breakpoint([Breakpoint.Desktop, Breakpoint.DekstopL, Breakpoint.Deks
|
|||||||
| **Implementation Analysis** | `Explore` | Multiple file analysis |
|
| **Implementation Analysis** | `Explore` | Multiple file analysis |
|
||||||
| **Single Specific File** | Read tool directly | No agent needed |
|
| **Single Specific File** | Read tool directly | No agent needed |
|
||||||
|
|
||||||
#### Documentation Research System (Two-Tier)
|
### Documentation Research System (Two-Tier)
|
||||||
|
|
||||||
1. **ALWAYS start with `docs-researcher`** (Haiku, 30-120s) for any documentation need
|
1. **ALWAYS start with `docs-researcher`** (Haiku, 30-120s) for any documentation need
|
||||||
2. **Auto-escalate to `docs-researcher-advanced`** (Sonnet, 2-7min) when:
|
2. **Auto-escalate to `docs-researcher-advanced`** (Sonnet, 2-7min) when:
|
||||||
@@ -290,7 +47,7 @@ isDesktop = breakpoint([Breakpoint.Desktop, Breakpoint.DekstopL, Breakpoint.Deks
|
|||||||
- Need code inference
|
- Need code inference
|
||||||
- Complex architectural questions
|
- Complex architectural questions
|
||||||
|
|
||||||
#### Enforcement Examples
|
### Enforcement Examples
|
||||||
|
|
||||||
```
|
```
|
||||||
❌ WRONG: Read libs/ui/buttons/README.md
|
❌ WRONG: Read libs/ui/buttons/README.md
|
||||||
@@ -305,60 +62,35 @@ isDesktop = breakpoint([Breakpoint.Desktop, Breakpoint.DekstopL, Breakpoint.Deks
|
|||||||
|
|
||||||
**Remember: Using subagents is NOT optional - it's mandatory for maintaining context efficiency and search quality.**
|
**Remember: Using subagents is NOT optional - it's mandatory for maintaining context efficiency and search quality.**
|
||||||
|
|
||||||
#### Common Research Patterns
|
## Project Knowledge Management with Context-Manager
|
||||||
|
|
||||||
| Information Need | Required Approach |
|
**NEW CAPABILITY**: The `context-manager` subagent has **persistent memory** that autonomously stores and retrieves project knowledge across sessions.
|
||||||
|-----------------|-------------------|
|
|
||||||
| **Library documentation** | `docs-researcher` → Check library-reference.md → Escalate if needed |
|
|
||||||
| **Code patterns/examples** | `Explore` with "medium" or "very thorough" |
|
|
||||||
| **Architecture understanding** | `npx nx graph` + `Explore` for implementation |
|
|
||||||
| **Debugging/errors** | Direct tool use (Read specific error file, check console) |
|
|
||||||
|
|
||||||
#### Debugging Tips
|
### What Gets Stored Automatically
|
||||||
- **TypeScript errors**: Follow error path to exact file:line
|
|
||||||
- **Test failures**: Use `--skip-nx-cache` for fresh output
|
|
||||||
- **Module resolution**: Check `tsconfig.base.json` path aliases
|
|
||||||
- **State issues**: Use Angular DevTools browser extension
|
|
||||||
|
|
||||||
### Library Development Patterns
|
- **Assigned Tasks**: User-assigned tasks with context ("Remember to look up X because of Y"), TODO items, status tracking
|
||||||
- **Library Documentation**: Use `docs-researcher` for ALL library READMEs (mandatory for context management)
|
- **Architectural Decisions**: State management patterns, API integration approaches, component architecture choices
|
||||||
- **New Library Creation**: Use Nx generators with domain-specific naming (`[domain]-[layer]-[feature]`)
|
- **Reusable Patterns**: Code conventions, testing patterns, error handling approaches
|
||||||
- **Standalone Components**: All new components must be standalone with explicit imports - no NgModules
|
- **Integration Points**: API contracts, data flows, module boundaries
|
||||||
- **Testing Framework**: New = Vitest + Angular Testing Utilities, Legacy = Jest + Spectator
|
- **Domain Knowledge**: Business workflows, business rules, user roles/permissions
|
||||||
- **Path Aliases**: Always use `@isa/[domain]/[layer]/[feature]` - avoid relative imports
|
- **Technical Solutions**: Bug fixes with root causes, performance optimizations
|
||||||
|
|
||||||
#### Library Reference Guide
|
### When to Use Context-Manager
|
||||||
|
|
||||||
The monorepo contains **62 libraries** organized across 12 domains. For quick lookup, see **[`docs/library-reference.md`](docs/library-reference.md)**.
|
Use the `context-manager` subagent PROACTIVELY for:
|
||||||
|
- **Task Management**: Assigning tasks for later ("Remember to investigate X because of Y")
|
||||||
|
- **Session Continuity**: Starting a new session (it will remind you of pending tasks)
|
||||||
|
- Complex, multi-step projects requiring coordination
|
||||||
|
- Long-running tasks that span multiple sessions
|
||||||
|
- Preserving architectural context
|
||||||
|
- Learning about resolved issues and their solutions
|
||||||
|
|
||||||
**Quick Overview by Domain:**
|
### How It Works
|
||||||
- Availability (1) | Catalogue (1) | Checkout (6) | Common (3) | Core (5) | CRM (1) | Icons (1)
|
|
||||||
- OMS (9) | Remission (8) | Shared Components (7) | UI Components (17) | Utilities (3)
|
|
||||||
|
|
||||||
### API Integration Workflow
|
1. **Task Capture**: Listens for "Remember to...", "TODO:", "Don't forget...", stores them with full context
|
||||||
- **Swagger Generation**: Run `npm run generate:swagger` to regenerate all 10 API clients when backend changes
|
2. **Automatic Storage**: Proactively stores important discoveries in persistent memory
|
||||||
- **Data Services**: Wrap generated API clients in domain-specific data-access services with proper error handling and Zod validation
|
3. **Knowledge Retrieval**: Queries stored knowledge before starting new work
|
||||||
- **State Management**: Use NgRx Signals with `signalStore()`, entity management, and session persistence for complex state
|
4. **Task Reminders**: Proactively reminds you of pending/incomplete tasks at session start
|
||||||
|
5. **Cross-Session Persistence**: Information persists across Claude Code sessions
|
||||||
|
|
||||||
### Performance and Quality Considerations
|
**Benefits**: Eliminates context loss, maintains project knowledge, provides task continuity across sessions.
|
||||||
- **Bundle Monitoring**: Watch bundle sizes (2MB warning, 5MB error for main bundle)
|
|
||||||
- **Testing Cache**: Always use `--skip-nx-cache` flag when running tests to ensure reliable results
|
|
||||||
- **Code Quality**: Pre-commit hooks enforce Prettier formatting and ESLint rules automatically
|
|
||||||
- **Memory Management**: Clean up subscriptions and use OnPush change detection for optimal performance
|
|
||||||
|
|
||||||
### Common Troubleshooting
|
|
||||||
- **Build Issues**: Check Node version and run `npm install` if encountering module resolution errors
|
|
||||||
- **Test Failures**: Use `--skip-nx-cache` flag and ensure test isolation (no shared state between tests)
|
|
||||||
- **Nx Cache Issues**: If you see `existing outputs match the cache, left as is` during build or testing:
|
|
||||||
- **Option 1**: Run `npx nx reset` to clear the Nx cache completely
|
|
||||||
- **Option 2**: Use `--skip-nx-cache` flag to bypass Nx cache for a specific command (e.g., `npx nx test <project> --skip-nx-cache`)
|
|
||||||
- **When to use**: Always use `--skip-nx-cache` when you need guaranteed fresh builds or test results
|
|
||||||
- **SSL Certificates**: Development server uses SSL - accept certificate warnings in browser for localhost
|
|
||||||
- **Import Errors**: Verify path aliases in `tsconfig.base.json` and use absolute imports for cross-library dependencies
|
|
||||||
|
|
||||||
### Domain-Specific Conventions
|
|
||||||
- **Component Prefixes**: Use `oms-feature-*` for OMS, `remi-*` for remission, `ui-*` for shared components
|
|
||||||
- **Git Workflow**: Default branch is `develop` (not main), use conventional commits without co-author tags
|
|
||||||
- **Design System**: Use ISA-specific Tailwind utilities (`isa-accent-*`, `isa-text-*`) and custom breakpoints (`isa-desktop-*`)
|
|
||||||
- **Logging**: Use centralized logging service (`@isa/core/logging`) with contextual information for debugging
|
|
||||||
- **Navigation State**: Use `@isa/core/navigation` for passing temporary state between routes (return URLs, form context) instead of query parameters - keeps URLs clean and state reliable
|
|
||||||
|
|||||||
287
docs/ARCHITECTURE.md
Normal file
287
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
# ISA-Frontend Architecture Documentation
|
||||||
|
|
||||||
|
Complete architectural analysis of the ISA-Frontend monorepo with C4 models, dependency analysis, and implementation patterns.
|
||||||
|
|
||||||
|
## Documentation Files
|
||||||
|
|
||||||
|
### 1. **Architecture Analysis** (`architecture-analysis.md`) - 51 KB
|
||||||
|
Comprehensive architectural overview including:
|
||||||
|
- Complete project structure analysis
|
||||||
|
- All 63 libraries organized by domain
|
||||||
|
- Strict layered dependency model
|
||||||
|
- Technology stack (Angular 20.3.6, Nx 21.3.2, etc.)
|
||||||
|
- 6 primary domains (OMS, Remission, Checkout, Catalogue, Availability, CRM)
|
||||||
|
- Core infrastructure (5 libs), UI components (17 libs), shared components (7 libs)
|
||||||
|
- Modern architecture patterns (standalone components, NgRx Signals, responsive design)
|
||||||
|
- Complete C4 Model visualization (Levels 1-4)
|
||||||
|
- State management patterns with code examples
|
||||||
|
- Component architecture and dependency enforcement
|
||||||
|
|
||||||
|
### 2. **Dependency Hierarchy** (`dependency-hierarchy.md`) - 13 KB
|
||||||
|
Visual dependency organization:
|
||||||
|
- Layer-based dependency model (4 levels)
|
||||||
|
- Complete OMS domain dependency tree
|
||||||
|
- Remission domain dependency tree
|
||||||
|
- Checkout domain dependency tree
|
||||||
|
- Cross-domain dependency matrix
|
||||||
|
- Import path conventions and examples
|
||||||
|
- NO circular dependencies guarantee
|
||||||
|
- Bundle dependency impact analysis
|
||||||
|
- Development workflow for adding features
|
||||||
|
- Performance considerations (lazy loading, tree shaking)
|
||||||
|
- Quick reference lookup table
|
||||||
|
|
||||||
|
### 3. **Quick Reference** (`architecture-quick-reference.md`) - 15 KB
|
||||||
|
Developer quick reference guide:
|
||||||
|
- Project overview at a glance
|
||||||
|
- Domain summary with key libraries
|
||||||
|
- Architecture layers visualization
|
||||||
|
- State management pattern example
|
||||||
|
- Component structure template
|
||||||
|
- Common development patterns (search, dialogs, forms, responsive design)
|
||||||
|
- Essential command cheatsheet
|
||||||
|
- File organization by domain
|
||||||
|
- TypeScript path alias mapping
|
||||||
|
- Design system utilities (Tailwind ISA-specific)
|
||||||
|
- Testing approach (Vitest vs Jest)
|
||||||
|
- Troubleshooting guide
|
||||||
|
- Performance budgets
|
||||||
|
- Monorepo statistics
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Navigation
|
||||||
|
|
||||||
|
### For Architecture Understanding
|
||||||
|
Start with **architecture-analysis.md** → C4 Model section
|
||||||
|
- Understand the 6 primary domains
|
||||||
|
- Learn the 4-layer dependency model
|
||||||
|
- See how all 63 libraries fit together
|
||||||
|
|
||||||
|
### For Dependency Details
|
||||||
|
Read **dependency-hierarchy.md** for:
|
||||||
|
- How libraries depend on each other
|
||||||
|
- Where to import from (path aliases)
|
||||||
|
- Why circular dependencies are prevented
|
||||||
|
- How to add new features without breaking the graph
|
||||||
|
|
||||||
|
### For Hands-On Development
|
||||||
|
Use **architecture-quick-reference.md** for:
|
||||||
|
- Quick lookup of library purposes
|
||||||
|
- Code patterns and examples
|
||||||
|
- Common commands
|
||||||
|
- File locations and conventions
|
||||||
|
- Troubleshooting tips
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Structure Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
ISA-Frontend (Angular 20.3.6 Monorepo)
|
||||||
|
├── 63 Libraries organized by domain
|
||||||
|
│ ├── 6 Primary Domains (OMS, Remission, Checkout, Catalogue, Availability, CRM)
|
||||||
|
│ ├── 17 UI Component Libraries
|
||||||
|
│ ├── 7 Shared Component Libraries
|
||||||
|
│ ├── 5 Core Infrastructure Libraries
|
||||||
|
│ ├── 3 Common Utility Libraries
|
||||||
|
│ ├── 3 General Utility Libraries
|
||||||
|
│ ├── 1 Icon Library
|
||||||
|
│ └── 10 Auto-generated Swagger API Clients
|
||||||
|
├── 1 Main Application (isa-app)
|
||||||
|
└── Strict Layered Architecture (Feature → Shared → Data Access → Infrastructure)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Architecture Principles
|
||||||
|
|
||||||
|
### 1. Domain-Driven Design
|
||||||
|
- 6 distinct business domains (OMS, Remission, Checkout, etc.)
|
||||||
|
- Each domain has data-access, feature, and shared components
|
||||||
|
- Clear domain boundaries prevent unnecessary coupling
|
||||||
|
|
||||||
|
### 2. Strict Layering
|
||||||
|
- **Feature Layer**: Route components, user interaction
|
||||||
|
- **Shared Layer**: Reusable UI and domain-specific components
|
||||||
|
- **Data Access Layer**: NgRx Signals stores and API services
|
||||||
|
- **Infrastructure Layer**: Core, common, and generated APIs
|
||||||
|
|
||||||
|
### 3. No Circular Dependencies
|
||||||
|
- Enforced by TypeScript path aliases
|
||||||
|
- Verified by ESLint nx plugin
|
||||||
|
- Enables scalability and maintainability
|
||||||
|
|
||||||
|
### 4. Modern Angular Patterns
|
||||||
|
- **Standalone Components**: All new components (no NgModule)
|
||||||
|
- **Signal-based State**: NgRx Signals with functional composition
|
||||||
|
- **Type Safety**: TypeScript strict mode + Zod validation
|
||||||
|
- **Responsive Design**: Breakpoint service instead of CSS media queries
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Statistics
|
||||||
|
|
||||||
|
| Metric | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| Total Libraries | 63 |
|
||||||
|
| Primary Domains | 6 |
|
||||||
|
| UI Components | 17 |
|
||||||
|
| Feature Components | 20 |
|
||||||
|
| Data Access Stores | 6 |
|
||||||
|
| Core Infrastructure | 5 |
|
||||||
|
| Shared Components | 7 |
|
||||||
|
| Common Utilities | 3 |
|
||||||
|
| General Utilities | 3 |
|
||||||
|
| Generated APIs | 10 |
|
||||||
|
| Lines of Documentation | 2,165+ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technology Stack
|
||||||
|
|
||||||
|
- **Framework**: Angular 20.3.6
|
||||||
|
- **Build Tool**: Nx 21.3.2
|
||||||
|
- **Language**: TypeScript 5.8.3
|
||||||
|
- **State Management**: NgRx Signals 20.0.0
|
||||||
|
- **Styling**: Tailwind CSS 3.4.14 + 7 custom plugins
|
||||||
|
- **Testing**: Jest (legacy) + Vitest (modern)
|
||||||
|
- **HTTP Client**: HttpClient 20.3.6
|
||||||
|
- **Validation**: Zod 3.24.2
|
||||||
|
- **API Generation**: ng-swagger-gen 2.3.1
|
||||||
|
- **Authentication**: OAuth2/OIDC via angular-oauth2-oidc
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install and start
|
||||||
|
npm install
|
||||||
|
npm start # Runs on https://localhost:4200
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
npm test # All libraries
|
||||||
|
npx nx test [project] --skip-nx-cache # Specific library (fresh results)
|
||||||
|
|
||||||
|
# Building
|
||||||
|
npm run build # Development
|
||||||
|
npm run build-prod # Production
|
||||||
|
|
||||||
|
# Regenerate APIs
|
||||||
|
npm run generate:swagger # From OpenAPI specs
|
||||||
|
npm run fix:files:swagger # Unicode cleanup
|
||||||
|
|
||||||
|
# Analysis
|
||||||
|
npx nx graph # Visualize dependencies
|
||||||
|
npx nx show project [project] # Show project details
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Injecting and Using a Store
|
||||||
|
```typescript
|
||||||
|
export class MyComponent {
|
||||||
|
protected store = inject(omsStore);
|
||||||
|
|
||||||
|
onSearch(term: string) {
|
||||||
|
this.store.searchReceipts(term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a New Feature
|
||||||
|
1. Create standalone component in `[domain]/feature/[feature-name]`
|
||||||
|
2. Import from data-access, shared, and UI libraries via path aliases
|
||||||
|
3. Inject store directly (don't inject individual services)
|
||||||
|
4. Use reactive template syntax (@if, @for, @switch)
|
||||||
|
|
||||||
|
### Adding E2E Attributes
|
||||||
|
```html
|
||||||
|
<button
|
||||||
|
data-what="submit"
|
||||||
|
data-which="primary-action"
|
||||||
|
[attr.data-order-id]="orderId"
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Decisions
|
||||||
|
|
||||||
|
### Why NgRx Signals?
|
||||||
|
- Modern, functional composition
|
||||||
|
- Signals for reactive properties
|
||||||
|
- Entity management for normalized state
|
||||||
|
- Auto-persistence with withStorage()
|
||||||
|
- Request cancellation support
|
||||||
|
|
||||||
|
### Why Standalone Components?
|
||||||
|
- No NgModule boilerplate
|
||||||
|
- Explicit dependencies (in imports)
|
||||||
|
- Tree-shakeable code
|
||||||
|
- Easier testing
|
||||||
|
|
||||||
|
### Why Path Aliases?
|
||||||
|
- Prevent relative imports across domains
|
||||||
|
- Enforce architectural boundaries
|
||||||
|
- Clear import intent (@isa/domain/layer/feature)
|
||||||
|
- Enable refactoring safety
|
||||||
|
|
||||||
|
### Why Strict Layering?
|
||||||
|
- Prevent circular dependencies
|
||||||
|
- Enable parallel development
|
||||||
|
- Facilitate testing
|
||||||
|
- Support scalability
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
1. **Library Documentation**: Check `/libs/[domain]/[layer]/[feature]/README.md`
|
||||||
|
2. **Architecture Details**: See the appropriate documentation file above
|
||||||
|
3. **Code Examples**: Look for similar implementations in the codebase
|
||||||
|
4. **Nx Visualization**: Run `npx nx graph` to see dependency graph
|
||||||
|
5. **Project Configuration**: Review `nx.json` and `tsconfig.base.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- **Library Reference**: See `/docs/library-reference.md` for all 63 libraries
|
||||||
|
- **Testing Guidelines**: See `/docs/guidelines/testing.md` for testing patterns
|
||||||
|
- **Code Review Standards**: See `/.github/review-instructions.md` for review process
|
||||||
|
- **CLAUDE.md**: Project-specific conventions and best practices
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
These documentation files are maintained manually. When:
|
||||||
|
- Adding new libraries: Update library reference and domain counts
|
||||||
|
- Changing architecture patterns: Update quick reference and analysis
|
||||||
|
- Adding new domains: Document domain structure and dependencies
|
||||||
|
- Migrating frameworks: Update testing approach sections
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Document Generation
|
||||||
|
|
||||||
|
To regenerate library reference:
|
||||||
|
```bash
|
||||||
|
npm run docs:generate
|
||||||
|
```
|
||||||
|
|
||||||
|
This updates `/docs/library-reference.md` automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-10-29
|
||||||
|
**Angular Version**: 20.3.6
|
||||||
|
**Nx Version**: 21.3.2
|
||||||
|
**Documentation Format**: Markdown (3 comprehensive files)
|
||||||
|
|
||||||
1120
docs/architecture-analysis.md
Normal file
1120
docs/architecture-analysis.md
Normal file
File diff suppressed because it is too large
Load Diff
587
docs/architecture-quick-reference.md
Normal file
587
docs/architecture-quick-reference.md
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
# ISA-Frontend Architecture: Quick Reference Guide
|
||||||
|
|
||||||
|
## Project Overview at a Glance
|
||||||
|
|
||||||
|
| Aspect | Details |
|
||||||
|
|--------|---------|
|
||||||
|
| **Project Type** | Angular 20.3.6 Monorepo (Domain-Driven Design) |
|
||||||
|
| **Build Tool** | Nx 21.3.2 |
|
||||||
|
| **Total Libraries** | 63 (organized by domain + infrastructure) |
|
||||||
|
| **Main Application** | `isa-app` (only runnable app) |
|
||||||
|
| **Domains** | OMS, Remission, Checkout, Catalogue, Availability, CRM |
|
||||||
|
| **UI Components** | 17 specialized design system libraries |
|
||||||
|
| **Testing** | Jest (legacy) + Vitest (modern) - migration in progress |
|
||||||
|
| **State Management** | NgRx Signals with entity normalization |
|
||||||
|
| **API Clients** | 10 auto-generated from Swagger/OpenAPI specs |
|
||||||
|
| **Styling** | Tailwind CSS + 7 custom plugins |
|
||||||
|
| **Authentication** | OAuth2/OIDC via `angular-oauth2-oidc` |
|
||||||
|
| **Barcode Support** | Scandit Web Datacapture |
|
||||||
|
| **Analytics** | Matomo integration |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Domain Summary
|
||||||
|
|
||||||
|
### 1. Order Management System (OMS) - 9 Libraries
|
||||||
|
**Focus:** Return workflows and receipt management
|
||||||
|
|
||||||
|
| Library | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `oms-data-access` | State + API integration |
|
||||||
|
| `oms-feature-return-search` | Receipt search interface |
|
||||||
|
| `oms-feature-return-details` | Item selection & configuration |
|
||||||
|
| `oms-feature-return-process` | Dynamic return questions |
|
||||||
|
| `oms-feature-return-summary` | Confirmation & printing |
|
||||||
|
| `oms-feature-return-review` | Completion review |
|
||||||
|
| `oms-shared-product-info` | Product display |
|
||||||
|
| `oms-shared-task-list` | Task management UI |
|
||||||
|
| `oms-utils-translation` | Receipt type labels |
|
||||||
|
|
||||||
|
**Key APIs:** oms-api, isa-api, print-api
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Remission (Returns Management) - 8 Libraries
|
||||||
|
**Focus:** Warehouse return processing (mandatory + department)
|
||||||
|
|
||||||
|
| Library | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `remission-data-access` | State + API integration |
|
||||||
|
| `remission-feature-remission-list` | Main list view |
|
||||||
|
| `remission-feature-remission-return-receipt-list` | Receipt list |
|
||||||
|
| `remission-feature-remission-return-receipt-details` | Receipt details |
|
||||||
|
| `remission-shared-product` | Product components |
|
||||||
|
| `remission-shared-remission-start-dialog` | Start workflow |
|
||||||
|
| `remission-shared-return-receipt-actions` | Action buttons |
|
||||||
|
| `remission-shared-search-item-to-remit-dialog` | Item search |
|
||||||
|
|
||||||
|
**Key APIs:** Remission-specific via ISA backend
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Checkout & Rewards - 6 Libraries
|
||||||
|
**Focus:** Shopping cart, orders, loyalty rewards
|
||||||
|
|
||||||
|
| Library | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `checkout-data-access` | Cart state + API |
|
||||||
|
| `checkout-feature-reward-catalog` | Reward browsing |
|
||||||
|
| `checkout-feature-reward-shopping-cart` | Cart with rewards |
|
||||||
|
| `checkout-feature-reward-order-confirmation` | Order confirmation |
|
||||||
|
| `checkout-shared-product-info` | Product display |
|
||||||
|
| `checkout-shared-reward-selection-dialog` | Reward selection |
|
||||||
|
|
||||||
|
**Key APIs:** checkout-api, crm-api (bonus cards)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. Catalogue - 1 Library
|
||||||
|
**Focus:** Product search and discovery
|
||||||
|
|
||||||
|
| Library | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `catalogue-data-access` | Search + filtering |
|
||||||
|
|
||||||
|
**Key APIs:** cat-search-api, availability-api
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Availability - 1 Library
|
||||||
|
**Focus:** Product stock checking
|
||||||
|
|
||||||
|
| Library | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `availability-data-access` | Stock queries |
|
||||||
|
|
||||||
|
**Key APIs:** availability-api
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. CRM - 1 Library
|
||||||
|
**Focus:** Customer data and bonus cards
|
||||||
|
|
||||||
|
| Library | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `crm-data-access` | Customer + bonus card state |
|
||||||
|
|
||||||
|
**Key APIs:** crm-api
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Layers
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ FEATURE LAYER (User-Facing) │
|
||||||
|
│ - Components with routes │
|
||||||
|
│ - User interactions │
|
||||||
|
│ - Navigation handlers │
|
||||||
|
└──────────────┬──────────────────┘
|
||||||
|
│ imports
|
||||||
|
┌──────────────▼──────────────────┐
|
||||||
|
│ SHARED LAYER (Reusable) │
|
||||||
|
│ - UI components (17 libs) │
|
||||||
|
│ - Shared components (7 libs) │
|
||||||
|
│ - Domain shared │
|
||||||
|
└──────────────┬──────────────────┘
|
||||||
|
│ imports
|
||||||
|
┌──────────────▼──────────────────┐
|
||||||
|
│ DATA ACCESS LAYER (State) │
|
||||||
|
│ - NgRx Signal Stores │
|
||||||
|
│ - API Services │
|
||||||
|
│ - Entity management │
|
||||||
|
└──────────────┬──────────────────┘
|
||||||
|
│ imports
|
||||||
|
┌──────────────▼──────────────────┐
|
||||||
|
│ INFRASTRUCTURE (Foundation) │
|
||||||
|
│ - Core libraries (5) │
|
||||||
|
│ - Common utilities (3) │
|
||||||
|
│ - Generated APIs (10) │
|
||||||
|
│ - Utilities (3) │
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## State Management Pattern
|
||||||
|
|
||||||
|
### NgRx Signals Store Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export const orderStore = signalStore(
|
||||||
|
// 1. State definition
|
||||||
|
withState({
|
||||||
|
orders: [] as Order[],
|
||||||
|
selected: null as Order | null,
|
||||||
|
loading: false,
|
||||||
|
error: null as Error | null,
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 2. Entity management (auto-normalization)
|
||||||
|
withEntities({ entity: type<Order>() }),
|
||||||
|
|
||||||
|
// 3. Computed values
|
||||||
|
withComputed((store) => ({
|
||||||
|
orderCount: computed(() => store.orders().length),
|
||||||
|
hasSelected: computed(() => store.selected() !== null),
|
||||||
|
})),
|
||||||
|
|
||||||
|
// 4. Methods for state mutations
|
||||||
|
withMethods((store, api = inject(OmsApiService)) => ({
|
||||||
|
load: rxMethod<void>(
|
||||||
|
pipe(
|
||||||
|
tapResponse(
|
||||||
|
(orders) => patchState(store, setAllEntities(orders)),
|
||||||
|
(error) => handleError(error)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
select: (order: Order) => {
|
||||||
|
patchState(store, { selected: order });
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
|
||||||
|
// 5. Auto persistence
|
||||||
|
withStorage({ key: 'orders' }),
|
||||||
|
|
||||||
|
// 6. Cleanup hooks
|
||||||
|
withHooks({
|
||||||
|
onInit: ({ load }) => load(),
|
||||||
|
onDestroy: () => console.log('Store destroyed'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- Signals: Reactive properties
|
||||||
|
- Entity management: Auto-normalized state
|
||||||
|
- Methods: Encapsulated mutations
|
||||||
|
- Storage: Automatic persistence
|
||||||
|
- Hooks: Lifecycle management
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Component Structure
|
||||||
|
|
||||||
|
### Standalone Component Example
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
@Component({
|
||||||
|
selector: 'oms-return-search',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
// Shared components
|
||||||
|
UiSearchBar,
|
||||||
|
UiButton,
|
||||||
|
OmsProductInfo,
|
||||||
|
UiEmptyState,
|
||||||
|
],
|
||||||
|
template: `
|
||||||
|
<div class="container">
|
||||||
|
<ui-search-bar (search)="onSearch($event)" />
|
||||||
|
|
||||||
|
@if (store.receipts(); as receipts) {
|
||||||
|
@if (receipts.length > 0) {
|
||||||
|
<oms-product-info
|
||||||
|
*ngFor="let receipt of receipts"
|
||||||
|
[receipt]="receipt"
|
||||||
|
/>
|
||||||
|
} @else {
|
||||||
|
<ui-empty-state title="Keine Belege" />
|
||||||
|
}
|
||||||
|
} @loading {
|
||||||
|
<ui-skeleton-loader />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
styles: [`...`],
|
||||||
|
})
|
||||||
|
export class OmsReturnSearchComponent {
|
||||||
|
protected store = inject(omsStore);
|
||||||
|
private api = inject(OmsApiService);
|
||||||
|
|
||||||
|
onSearch(term: string) {
|
||||||
|
this.store.searchReceipts(term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Best Practices:**
|
||||||
|
- ✅ Standalone components only
|
||||||
|
- ✅ Explicit imports
|
||||||
|
- ✅ Inject store, not services
|
||||||
|
- ✅ Use store methods directly
|
||||||
|
- ✅ Let control flow (@if, @for)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### 1. Search with Debouncing
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export class SearchComponent {
|
||||||
|
private searchTerm$ = new Subject<string>();
|
||||||
|
|
||||||
|
results$ = this.searchTerm$.pipe(
|
||||||
|
debounceTime(300),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
switchMap((term) => this.api.search(term)),
|
||||||
|
takeUntilKeydown('Escape')
|
||||||
|
);
|
||||||
|
|
||||||
|
onSearch(term: string) {
|
||||||
|
this.searchTerm$.next(term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Modal/Dialog Handling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export class DialogComponent {
|
||||||
|
private dialog = inject(DialogService);
|
||||||
|
|
||||||
|
openRewardSelection() {
|
||||||
|
this.dialog.open(RewardSelectionDialog, {
|
||||||
|
data: { cart: this.cart },
|
||||||
|
}).afterClosed$.subscribe((reward) => {
|
||||||
|
if (reward) {
|
||||||
|
this.store.selectReward(reward);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Form Validation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export class ReturnProcessComponent {
|
||||||
|
form = new FormGroup({
|
||||||
|
reason: new FormControl('', [Validators.required]),
|
||||||
|
quantity: new FormControl(1, [Validators.min(1)]),
|
||||||
|
comments: new FormControl(''),
|
||||||
|
});
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
if (this.form.valid) {
|
||||||
|
this.store.submitReturn(this.form.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Responsive Design
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export class ResponsiveComponent {
|
||||||
|
// Use breakpoint service instead of CSS-only
|
||||||
|
isDesktop = breakpoint([
|
||||||
|
Breakpoint.Desktop,
|
||||||
|
Breakpoint.DesktopL,
|
||||||
|
Breakpoint.DesktopXL,
|
||||||
|
]);
|
||||||
|
|
||||||
|
template = `
|
||||||
|
@if (isDesktop()) {
|
||||||
|
<desktop-layout />
|
||||||
|
} @else {
|
||||||
|
<mobile-layout />
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
### Development
|
||||||
|
```bash
|
||||||
|
npm start # Start with SSL
|
||||||
|
npm test # Test all libraries
|
||||||
|
npm run build # Dev build
|
||||||
|
npm run build-prod # Production build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
```bash
|
||||||
|
npx nx test oms-data-access --skip-nx-cache
|
||||||
|
npx nx affected:test --skip-nx-cache
|
||||||
|
npm run ci # CI with coverage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
```bash
|
||||||
|
npm run lint # ESLint
|
||||||
|
npm run prettier # Format code
|
||||||
|
npm run docs:generate # Update library ref
|
||||||
|
```
|
||||||
|
|
||||||
|
### API & Swagger
|
||||||
|
```bash
|
||||||
|
npm run generate:swagger # Regenerate all APIs
|
||||||
|
npm run fix:files:swagger # Unicode cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependency Analysis
|
||||||
|
```bash
|
||||||
|
npx nx graph # Visual dependency graph
|
||||||
|
npx nx show project oms-data-access --web false
|
||||||
|
npx nx affected:lint --skip-nx-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Organization by Domain
|
||||||
|
|
||||||
|
### OMS Domain Structure
|
||||||
|
```
|
||||||
|
libs/oms/
|
||||||
|
├── data-access/
|
||||||
|
│ └── src/
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── stores/
|
||||||
|
│ │ ├── receipt.store.ts
|
||||||
|
│ │ └── return.store.ts
|
||||||
|
│ └── services/
|
||||||
|
│ ├── oms-api.service.ts
|
||||||
|
│ └── print.service.ts
|
||||||
|
├── feature/
|
||||||
|
│ ├── return-search/
|
||||||
|
│ ├── return-details/
|
||||||
|
│ ├── return-process/
|
||||||
|
│ ├── return-summary/
|
||||||
|
│ └── return-review/
|
||||||
|
├── shared/
|
||||||
|
│ ├── product-info/
|
||||||
|
│ └── task-list/
|
||||||
|
└── utils/
|
||||||
|
└── translation/
|
||||||
|
```
|
||||||
|
|
||||||
|
### UI Component Structure
|
||||||
|
```
|
||||||
|
libs/ui/buttons/
|
||||||
|
├── src/
|
||||||
|
│ ├── index.ts
|
||||||
|
│ ├── primary-button.component.ts
|
||||||
|
│ ├── secondary-button.component.ts
|
||||||
|
│ ├── ...
|
||||||
|
│ └── buttons.module.ts
|
||||||
|
├── README.md
|
||||||
|
├── project.json
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TypeScript Path Aliases
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"paths": {
|
||||||
|
// Domain data-access
|
||||||
|
"@isa/oms/data-access": ["libs/oms/data-access/src/index.ts"],
|
||||||
|
"@isa/remission/data-access": ["libs/remission/data-access/src/index.ts"],
|
||||||
|
|
||||||
|
// UI components
|
||||||
|
"@isa/ui/buttons": ["libs/ui/buttons/src/index.ts"],
|
||||||
|
"@isa/ui/dialog": ["libs/ui/dialog/src/index.ts"],
|
||||||
|
|
||||||
|
// Core infrastructure
|
||||||
|
"@isa/core/logging": ["libs/core/logging/src/index.ts"],
|
||||||
|
"@isa/core/storage": ["libs/core/storage/src/index.ts"],
|
||||||
|
|
||||||
|
// Generated APIs
|
||||||
|
"@generated/swagger/oms-api": ["generated/swagger/oms-api/src/index.ts"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Styling & Design System
|
||||||
|
|
||||||
|
### Tailwind Utilities (ISA-Specific)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- Brand Colors -->
|
||||||
|
<div class="text-isa-accent-primary">Primary text</div>
|
||||||
|
<button class="bg-isa-accent-primary">Primary button</button>
|
||||||
|
|
||||||
|
<!-- Typography -->
|
||||||
|
<h1 class="isa-text-heading-1-bold">Large heading</h1>
|
||||||
|
<p class="isa-text-body-2-regular">Body text</p>
|
||||||
|
|
||||||
|
<!-- Custom Breakpoints -->
|
||||||
|
<div class="hidden isa-desktop:block">Desktop only</div>
|
||||||
|
<div class="block isa-desktop:hidden">Mobile only</div>
|
||||||
|
|
||||||
|
<!-- Custom Plugins -->
|
||||||
|
<button class="isa-button-primary">ISA Button</button>
|
||||||
|
<div class="isa-input-group">...</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Tailwind Plugins
|
||||||
|
1. button - Button styling
|
||||||
|
2. typography - Text utilities
|
||||||
|
3. menu - Menu styling
|
||||||
|
4. label - Label & tag styling
|
||||||
|
5. input - Input styling
|
||||||
|
6. section - Section containers
|
||||||
|
7. select-bullet - Select styling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Approach
|
||||||
|
|
||||||
|
### New Libraries (Vitest + Angular Testing Utils)
|
||||||
|
```typescript
|
||||||
|
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||||
|
import { OmsReturnSearchComponent } from './oms-return-search.component';
|
||||||
|
|
||||||
|
describe('OmsReturnSearchComponent', () => {
|
||||||
|
let component: OmsReturnSearchComponent;
|
||||||
|
let fixture: ComponentFixture<OmsReturnSearchComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [OmsReturnSearchComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(OmsReturnSearchComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### E2E Attributes
|
||||||
|
All templates must include data attributes:
|
||||||
|
```html
|
||||||
|
<button
|
||||||
|
data-what="submit-return"
|
||||||
|
data-which="primary-action"
|
||||||
|
[attr.data-order-id]="orderId"
|
||||||
|
>
|
||||||
|
Submit Return
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Issue | Solution |
|
||||||
|
|-------|----------|
|
||||||
|
| **Build cache stale** | `npx nx reset` or `--skip-nx-cache` |
|
||||||
|
| **Test failures** | Always use `--skip-nx-cache` |
|
||||||
|
| **Import not found** | Check `tsconfig.base.json` path alias |
|
||||||
|
| **Circular dependency** | Run `npx nx lint` to identify |
|
||||||
|
| **SSL certificate error** | Accept localhost certificate in browser |
|
||||||
|
| **State not persisting** | Check `withStorage()` in store |
|
||||||
|
| **API 401 Unauthorized** | Verify OAuth2 token in auth service |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
- **Library Reference:** `/docs/library-reference.md`
|
||||||
|
- **Architecture Analysis:** `/docs/architecture-analysis.md`
|
||||||
|
- **Dependency Hierarchy:** `/docs/dependency-hierarchy.md`
|
||||||
|
- **Testing Guidelines:** `/docs/guidelines/testing.md`
|
||||||
|
- **Nx Documentation:** https://nx.dev/
|
||||||
|
- **Angular Documentation:** https://angular.io/
|
||||||
|
- **NgRx Signals:** https://ngrx.io/guide/signals
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
1. Check library README: `libs/[domain]/[layer]/[feature]/README.md`
|
||||||
|
2. Review existing examples in similar domains
|
||||||
|
3. Check `npx nx show project [project-name]`
|
||||||
|
4. Read CLAUDE.md for project-specific conventions
|
||||||
|
5. Review git history: `git log --oneline libs/[domain]`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Budgets
|
||||||
|
|
||||||
|
- **Main bundle:** 2MB warning, 5MB error (gzipped)
|
||||||
|
- **Initial load:** < 2s on 4G
|
||||||
|
- **Core (after auth):** < 5s
|
||||||
|
|
||||||
|
**Bundle Analysis:**
|
||||||
|
```bash
|
||||||
|
npx nx build isa-app --configuration=production --stats-json
|
||||||
|
webpack-bundle-analyzer dist/isa-app/browser/stats.json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monorepo Statistics
|
||||||
|
|
||||||
|
| Metric | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| Total Libraries | 63 |
|
||||||
|
| Feature Components | 20 |
|
||||||
|
| UI Components | 17 |
|
||||||
|
| Data Access | 6 |
|
||||||
|
| Core Infrastructure | 5 |
|
||||||
|
| Shared Components | 7 |
|
||||||
|
| Utilities | 3 |
|
||||||
|
| Generated APIs | 10 |
|
||||||
|
| Lines of Code | ~500K+ |
|
||||||
|
| TypeScript Files | ~1,500 |
|
||||||
|
| Test Files | ~400 |
|
||||||
|
| Generated Test Coverage | Vitest: 34%, Jest: 65% |
|
||||||
|
|
||||||
458
docs/dependency-hierarchy.md
Normal file
458
docs/dependency-hierarchy.md
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
# ISA-Frontend: Dependency Hierarchy Diagram
|
||||||
|
|
||||||
|
## 1. Layer-Based Dependency Model
|
||||||
|
|
||||||
|
```
|
||||||
|
Level 4: Feature Components (Entry Points)
|
||||||
|
├── oms-feature-return-search
|
||||||
|
├── oms-feature-return-details
|
||||||
|
├── oms-feature-return-process
|
||||||
|
├── oms-feature-return-summary
|
||||||
|
├── oms-feature-return-review
|
||||||
|
├── remission-feature-remission-list
|
||||||
|
├── remission-feature-remission-return-receipt-list
|
||||||
|
├── remission-feature-remission-return-receipt-details
|
||||||
|
├── checkout-feature-reward-catalog
|
||||||
|
├── checkout-feature-reward-shopping-cart
|
||||||
|
└── checkout-feature-reward-order-confirmation
|
||||||
|
|
||||||
|
Level 3: Shared & UI Components
|
||||||
|
├── OMS Shared
|
||||||
|
│ ├── oms-shared-product-info
|
||||||
|
│ └── oms-shared-task-list
|
||||||
|
├── Remission Shared
|
||||||
|
│ ├── remission-shared-product
|
||||||
|
│ ├── remission-shared-remission-start-dialog
|
||||||
|
│ ├── remission-shared-return-receipt-actions
|
||||||
|
│ └── remission-shared-search-item-to-remit-dialog
|
||||||
|
├── Checkout Shared
|
||||||
|
│ ├── checkout-shared-product-info
|
||||||
|
│ └── checkout-shared-reward-selection-dialog
|
||||||
|
└── UI Component Library (17)
|
||||||
|
├── ui-buttons
|
||||||
|
├── ui-input-controls
|
||||||
|
├── ui-dialog
|
||||||
|
├── ui-datepicker
|
||||||
|
├── ui-layout
|
||||||
|
├── ui-menu
|
||||||
|
├── ui-toolbar
|
||||||
|
├── ui-search-bar
|
||||||
|
├── ui-expandable
|
||||||
|
├── ui-empty-state
|
||||||
|
├── ui-skeleton-loader
|
||||||
|
├── ui-carousel
|
||||||
|
├── ui-item-rows
|
||||||
|
├── ui-progress-bar
|
||||||
|
├── ui-tooltip
|
||||||
|
├── ui-label
|
||||||
|
└── ui-bullet-list
|
||||||
|
|
||||||
|
Level 2: Data Access Layer
|
||||||
|
├── oms-data-access
|
||||||
|
├── remission-data-access
|
||||||
|
├── checkout-data-access
|
||||||
|
├── catalogue-data-access
|
||||||
|
├── availability-data-access
|
||||||
|
└── crm-data-access
|
||||||
|
|
||||||
|
Level 1: Infrastructure & Core
|
||||||
|
├── Core Libraries (5)
|
||||||
|
│ ├── core-config
|
||||||
|
│ ├── core-logging
|
||||||
|
│ ├── core-navigation
|
||||||
|
│ ├── core-storage
|
||||||
|
│ └── core-tabs
|
||||||
|
├── Common Utilities (3)
|
||||||
|
│ ├── common-data-access
|
||||||
|
│ ├── common-decorators
|
||||||
|
│ └── common-print
|
||||||
|
├── Shared Components (7)
|
||||||
|
│ ├── shared-address
|
||||||
|
│ ├── shared-filter
|
||||||
|
│ ├── shared-product-image
|
||||||
|
│ ├── shared-product-format
|
||||||
|
│ ├── shared-product-router-link
|
||||||
|
│ ├── shared-quantity-control
|
||||||
|
│ └── shared-scanner
|
||||||
|
├── Generated APIs (10)
|
||||||
|
│ ├── @generated/swagger/oms-api
|
||||||
|
│ ├── @generated/swagger/checkout-api
|
||||||
|
│ ├── @generated/swagger/crm-api
|
||||||
|
│ ├── @generated/swagger/cat-search-api
|
||||||
|
│ ├── @generated/swagger/availability-api
|
||||||
|
│ ├── @generated/swagger/isa-api
|
||||||
|
│ ├── @generated/swagger/eis-api
|
||||||
|
│ ├── @generated/swagger/inventory-api
|
||||||
|
│ ├── @generated/swagger/print-api
|
||||||
|
│ └── @generated/swagger/wws-api
|
||||||
|
└── Utilities (3)
|
||||||
|
├── utils-ean-validation
|
||||||
|
├── utils-scroll-position
|
||||||
|
└── utils-z-safe-parse
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. OMS Domain Dependency Tree
|
||||||
|
|
||||||
|
```
|
||||||
|
oms-feature-return-search
|
||||||
|
├── oms-data-access
|
||||||
|
│ ├── @generated/swagger/oms-api
|
||||||
|
│ ├── @generated/swagger/print-api
|
||||||
|
│ ├── @isa/core/logging
|
||||||
|
│ └── @isa/common/data-access
|
||||||
|
├── oms-shared-product-info
|
||||||
|
│ ├── shared-product-image
|
||||||
|
│ ├── shared-product-format
|
||||||
|
│ ├── ui-item-rows
|
||||||
|
│ └── ui-label
|
||||||
|
└── ui-* (search-bar, buttons, empty-state, etc.)
|
||||||
|
|
||||||
|
oms-feature-return-details
|
||||||
|
├── oms-data-access (store)
|
||||||
|
├── oms-shared-product-info
|
||||||
|
├── ui-input-controls (quantity selector)
|
||||||
|
├── ui-buttons
|
||||||
|
└── shared-quantity-control
|
||||||
|
|
||||||
|
oms-feature-return-process
|
||||||
|
├── oms-data-access (update store)
|
||||||
|
├── ui-input-controls (forms)
|
||||||
|
├── ui-buttons
|
||||||
|
└── common-data-access (validation)
|
||||||
|
|
||||||
|
oms-feature-return-summary
|
||||||
|
├── oms-data-access (confirmation)
|
||||||
|
├── oms-shared-product-info
|
||||||
|
├── oms-shared-task-list
|
||||||
|
├── common-print (printing)
|
||||||
|
└── ui-buttons
|
||||||
|
|
||||||
|
oms-feature-return-review
|
||||||
|
├── oms-data-access (state)
|
||||||
|
├── oms-shared-product-info
|
||||||
|
├── common-print (reprint)
|
||||||
|
└── ui-empty-state
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Remission Domain Dependency Tree
|
||||||
|
|
||||||
|
```
|
||||||
|
remission-feature-remission-list
|
||||||
|
├── remission-data-access
|
||||||
|
│ ├── @generated/swagger/remission-api
|
||||||
|
│ ├── @isa/core/logging
|
||||||
|
│ └── @isa/common/data-access
|
||||||
|
├── remission-shared-remission-start-dialog
|
||||||
|
├── ui-dialog
|
||||||
|
├── ui-buttons
|
||||||
|
└── shared-filter
|
||||||
|
|
||||||
|
remission-feature-remission-return-receipt-list
|
||||||
|
├── remission-data-access
|
||||||
|
├── remission-shared-search-item-to-remit-dialog
|
||||||
|
├── remission-shared-return-receipt-actions
|
||||||
|
├── ui-buttons
|
||||||
|
└── ui-empty-state
|
||||||
|
|
||||||
|
remission-feature-remission-return-receipt-details
|
||||||
|
├── remission-data-access
|
||||||
|
├── remission-shared-product
|
||||||
|
│ ├── shared-product-image
|
||||||
|
│ ├── shared-product-format
|
||||||
|
│ └── ui-item-rows
|
||||||
|
├── remission-shared-return-receipt-actions
|
||||||
|
├── ui-expandable
|
||||||
|
└── ui-buttons
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Checkout Domain Dependency Tree
|
||||||
|
|
||||||
|
```
|
||||||
|
checkout-feature-reward-shopping-cart
|
||||||
|
├── checkout-data-access
|
||||||
|
│ ├── @generated/swagger/checkout-api
|
||||||
|
│ ├── @generated/swagger/crm-api
|
||||||
|
│ ├── @isa/core/logging
|
||||||
|
│ └── @isa/common/data-access
|
||||||
|
├── checkout-shared-product-info
|
||||||
|
│ ├── shared-product-image
|
||||||
|
│ └── ui-item-rows
|
||||||
|
├── checkout-shared-reward-selection-dialog
|
||||||
|
├── shared-quantity-control
|
||||||
|
├── ui-buttons
|
||||||
|
└── ui-empty-state
|
||||||
|
|
||||||
|
checkout-feature-reward-catalog
|
||||||
|
├── checkout-data-access
|
||||||
|
├── checkout-shared-product-info
|
||||||
|
├── shared-product-image
|
||||||
|
├── ui-buttons
|
||||||
|
├── ui-carousel
|
||||||
|
└── ui-skeleton-loader
|
||||||
|
|
||||||
|
checkout-feature-reward-order-confirmation
|
||||||
|
├── checkout-data-access
|
||||||
|
├── checkout-shared-product-info
|
||||||
|
├── ui-buttons
|
||||||
|
└── shared-address
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Complete Cross-Domain Dependency Matrix
|
||||||
|
|
||||||
|
```
|
||||||
|
Domain → Depends On
|
||||||
|
────────────────────────────────
|
||||||
|
OMS Features → oms-data-access, oms-shared-*, ui-*, shared-*
|
||||||
|
OMS Data Access → @generated/swagger/*, core-*, common-*
|
||||||
|
Remission Features → remission-data-access, remission-shared-*, ui-*, shared-*
|
||||||
|
Remission D.A. → @generated/swagger/*, core-*, common-*
|
||||||
|
Checkout Features → checkout-data-access, checkout-shared-*, ui-*, shared-*
|
||||||
|
Checkout D.A. → @generated/swagger/*, core-*, common-*
|
||||||
|
Catalogue D.A. → @generated/swagger/*, core-*, common-*
|
||||||
|
Availability D.A. → @generated/swagger/*, core-*, common-*
|
||||||
|
CRM D.A. → @generated/swagger/crm-api, core-*, common-*
|
||||||
|
UI Components → core-config, common-*, no data-access deps
|
||||||
|
Shared Components → core-*, ui-*, no data-access deps
|
||||||
|
Core Libraries → No monorepo dependencies
|
||||||
|
Common Libraries → core-*, no domain deps
|
||||||
|
Generated APIs → External (backend)
|
||||||
|
Utilities → core-config, no domain deps
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Import Path Conventions
|
||||||
|
|
||||||
|
All imports follow strict path aliases:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Domain-specific data-access
|
||||||
|
import { OrderStore, orderStore } from '@isa/oms/data-access';
|
||||||
|
import { ReturnStore, returnStore } from '@isa/remission/data-access';
|
||||||
|
import { CartStore, cartStore } from '@isa/checkout/data-access';
|
||||||
|
|
||||||
|
// Domain-specific shared components
|
||||||
|
import { OmsProductInfo } from '@isa/oms/shared/product-info';
|
||||||
|
import { RemissionProduct } from '@isa/remission/shared/product';
|
||||||
|
import { CheckoutProductInfo } from '@isa/checkout/shared/product-info';
|
||||||
|
|
||||||
|
// UI component library
|
||||||
|
import { UiButton, UiPrimaryButton } from '@isa/ui/buttons';
|
||||||
|
import { UiDialog } from '@isa/ui/dialog';
|
||||||
|
import { UiEmptyState } from '@isa/ui/empty-state';
|
||||||
|
|
||||||
|
// Shared components
|
||||||
|
import { SharedAddress } from '@isa/shared/address';
|
||||||
|
import { SharedFilter } from '@isa/shared/filter';
|
||||||
|
import { SharedProductImage } from '@isa/shared/product-image';
|
||||||
|
|
||||||
|
// Core infrastructure
|
||||||
|
import { Config } from '@isa/core/config';
|
||||||
|
import { logger } from '@isa/core/logging';
|
||||||
|
import { navigationState } from '@isa/core/navigation';
|
||||||
|
import { storageProvider } from '@isa/core/storage';
|
||||||
|
import { tabManager } from '@isa/core/tabs';
|
||||||
|
|
||||||
|
// Common utilities
|
||||||
|
import { tapResponse } from '@isa/common/data-access';
|
||||||
|
import { Cached, Debounce } from '@isa/common/decorators';
|
||||||
|
import { PrintService } from '@isa/common/print';
|
||||||
|
|
||||||
|
// General utilities
|
||||||
|
import { validateEan } from '@isa/utils/ean-validation';
|
||||||
|
import { restoreScrollPosition } from '@isa/utils/scroll-position';
|
||||||
|
import { safeParse } from '@isa/utils/z-safe-parse';
|
||||||
|
|
||||||
|
// Generated Swagger APIs
|
||||||
|
import { OmsApiClient } from '@generated/swagger/oms-api';
|
||||||
|
import { CheckoutApiClient } from '@generated/swagger/checkout-api';
|
||||||
|
import { CrmApiClient } from '@generated/swagger/crm-api';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. NO Circular Dependencies
|
||||||
|
|
||||||
|
The architecture enforces strict acyclic dependencies:
|
||||||
|
|
||||||
|
```
|
||||||
|
Feature Layer (Level 4)
|
||||||
|
↓ (one-way only)
|
||||||
|
Shared/UI Layer (Level 3)
|
||||||
|
↓ (one-way only)
|
||||||
|
Data Access Layer (Level 2)
|
||||||
|
↓ (one-way only)
|
||||||
|
Infrastructure Layer (Level 1)
|
||||||
|
↓ (one-way only)
|
||||||
|
External APIs & Services (Backend)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verification Command:**
|
||||||
|
```bash
|
||||||
|
npx nx affected:lint --skip-nx-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Bundle Dependency Impact
|
||||||
|
|
||||||
|
### Smallest Dependencies (Infrastructure)
|
||||||
|
- `core-config` (~2KB)
|
||||||
|
- `core-logging` (~5KB)
|
||||||
|
- `utils-ean-validation` (~3KB)
|
||||||
|
|
||||||
|
### Medium Dependencies (Shared)
|
||||||
|
- `shared-product-image` (~8KB)
|
||||||
|
- `ui-buttons` (~12KB)
|
||||||
|
- `ui-input-controls` (~20KB)
|
||||||
|
|
||||||
|
### Larger Dependencies (Domain)
|
||||||
|
- `oms-data-access` (~25KB including API client)
|
||||||
|
- `checkout-data-access` (~30KB including API client)
|
||||||
|
- `remission-data-access` (~20KB including API client)
|
||||||
|
|
||||||
|
### Impact on Main Bundle
|
||||||
|
- All 63 libraries + isa-app = ~2MB (production gzipped)
|
||||||
|
- Tree-shaking removes unused code
|
||||||
|
- Lazy-loaded routes reduce initial load
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Development Workflow
|
||||||
|
|
||||||
|
### Adding a New Feature
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Create feature component
|
||||||
|
→ Depends on shared components
|
||||||
|
|
||||||
|
2. Create shared component (if needed)
|
||||||
|
→ Depends on UI & core libraries
|
||||||
|
|
||||||
|
3. Update data-access if needed
|
||||||
|
→ Depends on generated APIs & common
|
||||||
|
|
||||||
|
4. Import via path aliases
|
||||||
|
import { NewFeature } from '@isa/domain/feature/new-feature'
|
||||||
|
|
||||||
|
5. Verify no circular deps
|
||||||
|
npx nx affected:lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependency Investigation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Show all dependencies of a library
|
||||||
|
npx nx show project oms-feature-return-search --web false
|
||||||
|
|
||||||
|
# Visualize dependency graph
|
||||||
|
npx nx graph --filter=oms-data-access
|
||||||
|
|
||||||
|
# Check for circular dependencies
|
||||||
|
npx nx lint
|
||||||
|
|
||||||
|
# View detailed dependency tree
|
||||||
|
npx nx show project oms-data-access --web false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Performance Considerations
|
||||||
|
|
||||||
|
### Lazy Loading
|
||||||
|
- Each feature module can be lazy-loaded via routing
|
||||||
|
- Reduces initial bundle size
|
||||||
|
- Loads on demand
|
||||||
|
|
||||||
|
### Tree Shaking
|
||||||
|
- Unused exports automatically removed
|
||||||
|
- All libraries use ES6 modules
|
||||||
|
- Named exports encouraged
|
||||||
|
|
||||||
|
### Code Splitting
|
||||||
|
- Generated APIs included only when imported
|
||||||
|
- UI components tree-shakeable
|
||||||
|
- Shared components bundled separately
|
||||||
|
|
||||||
|
### Module Boundaries
|
||||||
|
```
|
||||||
|
isa-app (main bundle)
|
||||||
|
├── core/ (always loaded)
|
||||||
|
├── routing (root)
|
||||||
|
└── route bundles (lazy)
|
||||||
|
├── oms/ (on route navigation)
|
||||||
|
├── remission/ (on route navigation)
|
||||||
|
└── checkout/ (on route navigation)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Breaking Changes Prevention
|
||||||
|
|
||||||
|
Strict dependency enforcement prevents:
|
||||||
|
- ✅ Feature importing data-access from other features
|
||||||
|
- ✅ UI components importing domain logic
|
||||||
|
- ✅ Core libraries importing domain logic
|
||||||
|
- ✅ Circular dependencies
|
||||||
|
- ✅ Implicit dependencies
|
||||||
|
|
||||||
|
Violations caught by:
|
||||||
|
1. ESLint nx plugin (import-rules)
|
||||||
|
2. TypeScript compiler (path alias validation)
|
||||||
|
3. Bundle analysis tools
|
||||||
|
4. Code review process
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Updating Dependencies
|
||||||
|
|
||||||
|
### Safe Dependency Diagram Update
|
||||||
|
```
|
||||||
|
1. Update generated API
|
||||||
|
→ Automatically updates data-access
|
||||||
|
|
||||||
|
2. Update core library
|
||||||
|
→ Cascades to all dependent layers
|
||||||
|
|
||||||
|
3. Update UI component
|
||||||
|
→ Only affects features using it
|
||||||
|
|
||||||
|
4. Update data-access
|
||||||
|
→ Only affects features in domain
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Strategy
|
||||||
|
- Update → Run affected tests → Deploy
|
||||||
|
- `npx nx affected:test --skip-nx-cache`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference: Which Library to Import
|
||||||
|
|
||||||
|
**I need a component for...**
|
||||||
|
|
||||||
|
| Use Case | Import From |
|
||||||
|
|----------|------------|
|
||||||
|
| Button styling | `@isa/ui/buttons` |
|
||||||
|
| Form inputs | `@isa/ui/input-controls` |
|
||||||
|
| Modal dialog | `@isa/ui/dialog` |
|
||||||
|
| Data fetching | `@isa/[domain]/data-access` |
|
||||||
|
| Product display | `@isa/shared/product-*` |
|
||||||
|
| Address display | `@isa/shared/address` |
|
||||||
|
| Logging | `@isa/core/logging` |
|
||||||
|
| Configuration | `@isa/core/config` |
|
||||||
|
| State storage | `@isa/core/storage` |
|
||||||
|
| Tab navigation | `@isa/core/tabs` |
|
||||||
|
| Context preservation | `@isa/core/navigation` |
|
||||||
|
| Printer management | `@isa/common/print` |
|
||||||
|
| EAN validation | `@isa/utils/ean-validation` |
|
||||||
|
| API client | `@generated/swagger/[api-name]` |
|
||||||
|
|
||||||
@@ -173,6 +173,7 @@ export class ShoppingCartService {
|
|||||||
return res.result as ShoppingCart;
|
return res.result as ShoppingCart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Code Kommentieren + Beschreiben
|
||||||
async completeRewardSelection({
|
async completeRewardSelection({
|
||||||
tabId,
|
tabId,
|
||||||
rewardSelectionItems,
|
rewardSelectionItems,
|
||||||
@@ -222,6 +223,7 @@ export class ShoppingCartService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: If Logik in eigene Funktionen auslagern - Für Remove die Update Funktion mit Quantity 0 nutzen, Code Kommentieren
|
||||||
async #handleCart({
|
async #handleCart({
|
||||||
shoppingCartId,
|
shoppingCartId,
|
||||||
itemId,
|
itemId,
|
||||||
@@ -295,6 +297,7 @@ export class ShoppingCartService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: If Logik in eigene Funktionen auslagern - Für Remove die Update Funktion mit Quantity 0 nutzen, Code Kommentieren
|
||||||
async #handleRewardCart({
|
async #handleRewardCart({
|
||||||
rewardShoppingCartId,
|
rewardShoppingCartId,
|
||||||
itemId,
|
itemId,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
// Arrange
|
// Arrange
|
||||||
const bonusCards: BonusCardInfo[] = [
|
const bonusCards: BonusCardInfo[] = [
|
||||||
{
|
{
|
||||||
|
code: 'CARD-B',
|
||||||
firstName: 'John',
|
firstName: 'John',
|
||||||
lastName: 'Doe',
|
lastName: 'Doe',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -14,19 +15,13 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
totalPoints: 100,
|
totalPoints: 100,
|
||||||
} as BonusCardInfo,
|
} as BonusCardInfo,
|
||||||
{
|
{
|
||||||
|
code: 'CARD-A',
|
||||||
firstName: 'Jane',
|
firstName: 'Jane',
|
||||||
lastName: 'Smith',
|
lastName: 'Smith',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
totalPoints: 200,
|
totalPoints: 200,
|
||||||
} as BonusCardInfo,
|
} as BonusCardInfo,
|
||||||
{
|
|
||||||
firstName: 'Bob',
|
|
||||||
lastName: 'Johnson',
|
|
||||||
isActive: true,
|
|
||||||
isPrimary: false,
|
|
||||||
totalPoints: 50,
|
|
||||||
} as BonusCardInfo,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@@ -35,14 +30,14 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
// Assert
|
// Assert
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
expect(result?.isPrimary).toBe(true);
|
expect(result?.isPrimary).toBe(true);
|
||||||
expect(result?.firstName).toBe('Jane');
|
expect(result?.code).toBe('CARD-A');
|
||||||
expect(result?.lastName).toBe('Smith');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return undefined when no primary bonus card exists', () => {
|
it('should return first alphabetically when no primary card exists', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const bonusCards: BonusCardInfo[] = [
|
const bonusCards: BonusCardInfo[] = [
|
||||||
{
|
{
|
||||||
|
code: 'CARD-C',
|
||||||
firstName: 'John',
|
firstName: 'John',
|
||||||
lastName: 'Doe',
|
lastName: 'Doe',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -50,6 +45,7 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
totalPoints: 100,
|
totalPoints: 100,
|
||||||
} as BonusCardInfo,
|
} as BonusCardInfo,
|
||||||
{
|
{
|
||||||
|
code: 'CARD-A',
|
||||||
firstName: 'Jane',
|
firstName: 'Jane',
|
||||||
lastName: 'Smith',
|
lastName: 'Smith',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -62,7 +58,8 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
const result = getPrimaryBonusCard(bonusCards);
|
const result = getPrimaryBonusCard(bonusCards);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeDefined();
|
||||||
|
expect(result?.code).toBe('CARD-A');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return undefined when bonus cards array is empty', () => {
|
it('should return undefined when bonus cards array is empty', () => {
|
||||||
@@ -76,10 +73,11 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the first primary card when multiple primary cards exist', () => {
|
it('should return first alphabetically when multiple primary cards exist', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const bonusCards: BonusCardInfo[] = [
|
const bonusCards: BonusCardInfo[] = [
|
||||||
{
|
{
|
||||||
|
code: 'CARD-Z',
|
||||||
firstName: 'John',
|
firstName: 'John',
|
||||||
lastName: 'Doe',
|
lastName: 'Doe',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -87,6 +85,7 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
totalPoints: 100,
|
totalPoints: 100,
|
||||||
} as BonusCardInfo,
|
} as BonusCardInfo,
|
||||||
{
|
{
|
||||||
|
code: 'CARD-A',
|
||||||
firstName: 'Jane',
|
firstName: 'Jane',
|
||||||
lastName: 'Smith',
|
lastName: 'Smith',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -101,6 +100,6 @@ describe('getPrimaryBonusCard', () => {
|
|||||||
// Assert
|
// Assert
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
expect(result?.isPrimary).toBe(true);
|
expect(result?.isPrimary).toBe(true);
|
||||||
expect(result?.firstName).toBe('John');
|
expect(result?.code).toBe('CARD-A');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
import { BonusCardInfo } from '../models';
|
import { BonusCardInfo } from '../models';
|
||||||
|
|
||||||
export function getPrimaryBonusCard(bonusCards: BonusCardInfo[]) {
|
export function getPrimaryBonusCard(
|
||||||
return bonusCards.find((card) => card.isPrimary);
|
bonusCards: BonusCardInfo[],
|
||||||
|
): BonusCardInfo | undefined {
|
||||||
|
if (bonusCards.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter primary cards if any exist
|
||||||
|
const primaryCards = bonusCards.filter((card) => card.isPrimary);
|
||||||
|
|
||||||
|
// Use primary cards if available, otherwise use all cards
|
||||||
|
const cardsToSort = primaryCards.length > 0 ? primaryCards : bonusCards;
|
||||||
|
|
||||||
|
// Sort alphabetically by code and return the first one
|
||||||
|
return cardsToSort.sort((a, b) => {
|
||||||
|
const codeA = a.code?.toLowerCase() ?? '';
|
||||||
|
const codeB = b.code?.toLowerCase() ?? '';
|
||||||
|
return codeA.localeCompare(codeB);
|
||||||
|
})[0];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user