evnict-kit 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/bin/cli.js +38 -0
- package/package.json +48 -0
- package/src/commands/add.js +129 -0
- package/src/commands/init-check.js +19 -0
- package/src/commands/init-context.js +37 -0
- package/src/commands/init-rules.js +42 -0
- package/src/commands/init-workflow.js +36 -0
- package/src/commands/init.js +722 -0
- package/src/utils/config.js +167 -0
- package/src/utils/file.js +53 -0
- package/templates/GETTING-STARTED.md +196 -0
- package/templates/content/context/AGENTS.md.template +462 -0
- package/templates/content/rules/01-evnict-kit-general-rules.md +303 -0
- package/templates/content/rules/02-evnict-kit-security-rules.md +423 -0
- package/templates/content/rules/03-evnict-kit-backend-conventions.md +383 -0
- package/templates/content/rules/04-evnict-kit-frontend-conventions.md +402 -0
- package/templates/content/rules/05-evnict-kit-project-conventions.md +228 -0
- package/templates/content/skills/evnict-kit-brainstorm/SKILL.md +140 -0
- package/templates/content/skills/evnict-kit-bug-fix/SKILL.md +108 -0
- package/templates/content/skills/evnict-kit-checkpoint/SKILL.md +156 -0
- package/templates/content/skills/evnict-kit-code-review/SKILL.md +158 -0
- package/templates/content/skills/evnict-kit-coordinate/SKILL.md +274 -0
- package/templates/content/skills/evnict-kit-create-api/SKILL.md +281 -0
- package/templates/content/skills/evnict-kit-create-component/SKILL.md +263 -0
- package/templates/content/skills/evnict-kit-create-page/SKILL.md +247 -0
- package/templates/content/skills/evnict-kit-database-migration/SKILL.md +164 -0
- package/templates/content/skills/evnict-kit-doc-postmortem/SKILL.md +93 -0
- package/templates/content/skills/evnict-kit-finish-branch/SKILL.md +87 -0
- package/templates/content/skills/evnict-kit-fix-attt/SKILL.md +129 -0
- package/templates/content/skills/evnict-kit-fix-business-logic/SKILL.md +89 -0
- package/templates/content/skills/evnict-kit-git-worktrees/SKILL.md +104 -0
- package/templates/content/skills/evnict-kit-merge-checklist/SKILL.md +108 -0
- package/templates/content/skills/evnict-kit-onboard/SKILL.md +143 -0
- package/templates/content/skills/evnict-kit-prompt-standard/SKILL.md +103 -0
- package/templates/content/skills/evnict-kit-receiving-review/SKILL.md +89 -0
- package/templates/content/skills/evnict-kit-security-audit/SKILL.md +190 -0
- package/templates/content/skills/evnict-kit-spec/SKILL.md +237 -0
- package/templates/content/skills/evnict-kit-tdd/SKILL.md +413 -0
- package/templates/content/skills/evnict-kit-wiki/SKILL.md +412 -0
- package/templates/content/workflows/evnict-kit-archive-wiki.md +100 -0
- package/templates/content/workflows/evnict-kit-attt.md +100 -0
- package/templates/content/workflows/evnict-kit-bug-fix.md +107 -0
- package/templates/content/workflows/evnict-kit-feature-large.md +393 -0
- package/templates/content/workflows/evnict-kit-feature-small.md +86 -0
- package/templates/content/workflows/evnict-kit-handoff.md +243 -0
- package/templates/content/workflows/evnict-kit-implement.md +247 -0
- package/templates/content/workflows/evnict-kit-init-check.md +76 -0
- package/templates/content/workflows/evnict-kit-init-context.md +58 -0
- package/templates/content/workflows/evnict-kit-init-rules.md +114 -0
- package/templates/content/workflows/evnict-kit-init-wiki.md +80 -0
- package/templates/content/workflows/evnict-kit-plan.md +308 -0
- package/templates/content/workflows/evnict-kit-review.md +53 -0
- package/templates/content/workflows/evnict-kit-spec-archive.md +53 -0
- package/templates/content/workflows/evnict-kit-wiki-archive-feature.md +164 -0
- package/templates/content/workflows/evnict-kit-wiki-query.md +91 -0
- package/templates/content/workflows/evnict-kit-wiki-scan-project.md +272 -0
- package/templates/context/AGENT.md.template +9 -0
- package/templates/context/AGENTS.md.template +462 -0
- package/templates/context/CLAUDE.md.template +301 -0
- package/templates/context/copilot-instructions.md.template +60 -0
- package/templates/context/cursorrules.template +114 -0
- package/templates/instruct/Instruct-Agent-AI.be.md +96 -0
- package/templates/instruct/Instruct-Agent-AI.fe.md +79 -0
- package/templates/rules/antigravity/01-evnict-kit-general-rules.md +303 -0
- package/templates/rules/antigravity/02-evnict-kit-security-rules.md +423 -0
- package/templates/rules/antigravity/03-evnict-kit-backend-conventions.md +383 -0
- package/templates/rules/antigravity/04-evnict-kit-frontend-conventions.md +402 -0
- package/templates/rules/antigravity/05-evnict-kit-project-conventions.md +228 -0
- package/templates/rules/claude/README.md +8 -0
- package/templates/rules/cursor/01-evnict-kit-general-rules.mdc +46 -0
- package/templates/rules/cursor/02-evnict-kit-security-rules.mdc +46 -0
- package/templates/rules/cursor/03-evnict-kit-backend-conventions.mdc +50 -0
- package/templates/rules/cursor/04-evnict-kit-frontend-conventions.mdc +43 -0
- package/templates/rules/cursor/05-evnict-kit-project-conventions.mdc +63 -0
- package/templates/rules/cursor/README.md +7 -0
- package/templates/skills/evnict-kit-brainstorm/SKILL.md +140 -0
- package/templates/skills/evnict-kit-bug-fix/SKILL.md +108 -0
- package/templates/skills/evnict-kit-checkpoint/SKILL.md +156 -0
- package/templates/skills/evnict-kit-code-review/SKILL.md +158 -0
- package/templates/skills/evnict-kit-coordinate/SKILL.md +274 -0
- package/templates/skills/evnict-kit-create-api/SKILL.md +281 -0
- package/templates/skills/evnict-kit-create-component/SKILL.md +263 -0
- package/templates/skills/evnict-kit-create-page/SKILL.md +247 -0
- package/templates/skills/evnict-kit-database-migration/SKILL.md +164 -0
- package/templates/skills/evnict-kit-doc-postmortem/SKILL.md +93 -0
- package/templates/skills/evnict-kit-finish-branch/SKILL.md +87 -0
- package/templates/skills/evnict-kit-fix-attt/SKILL.md +129 -0
- package/templates/skills/evnict-kit-fix-business-logic/SKILL.md +89 -0
- package/templates/skills/evnict-kit-git-worktrees/SKILL.md +104 -0
- package/templates/skills/evnict-kit-merge-checklist/SKILL.md +108 -0
- package/templates/skills/evnict-kit-onboard/SKILL.md +143 -0
- package/templates/skills/evnict-kit-prompt-standard/SKILL.md +103 -0
- package/templates/skills/evnict-kit-receiving-review/SKILL.md +89 -0
- package/templates/skills/evnict-kit-security-audit/SKILL.md +190 -0
- package/templates/skills/evnict-kit-spec/SKILL.md +237 -0
- package/templates/skills/evnict-kit-tdd/SKILL.md +413 -0
- package/templates/skills/evnict-kit-wiki/SKILL.md +412 -0
- package/templates/wiki/README.md +35 -0
- package/templates/wiki/config.example.yaml +17 -0
- package/templates/wiki/package.json +17 -0
- package/templates/wiki/raw/notes/.gitkeep +1 -0
- package/templates/wiki/scripts/ingest.js +66 -0
- package/templates/workflows/antigravity/evnict-kit-archive-wiki.md +100 -0
- package/templates/workflows/antigravity/evnict-kit-attt.md +100 -0
- package/templates/workflows/antigravity/evnict-kit-bug-fix.md +107 -0
- package/templates/workflows/antigravity/evnict-kit-feature-large.md +393 -0
- package/templates/workflows/antigravity/evnict-kit-feature-small.md +86 -0
- package/templates/workflows/antigravity/evnict-kit-handoff.md +243 -0
- package/templates/workflows/antigravity/evnict-kit-implement.md +247 -0
- package/templates/workflows/antigravity/evnict-kit-init-check.md +76 -0
- package/templates/workflows/antigravity/evnict-kit-init-context.md +58 -0
- package/templates/workflows/antigravity/evnict-kit-init-rules.md +114 -0
- package/templates/workflows/antigravity/evnict-kit-init-wiki.md +80 -0
- package/templates/workflows/antigravity/evnict-kit-plan.md +308 -0
- package/templates/workflows/antigravity/evnict-kit-review.md +53 -0
- package/templates/workflows/antigravity/evnict-kit-spec-archive.md +53 -0
- package/templates/workflows/antigravity/evnict-kit-wiki-archive-feature.md +164 -0
- package/templates/workflows/antigravity/evnict-kit-wiki-query.md +91 -0
- package/templates/workflows/antigravity/evnict-kit-wiki-scan-project.md +272 -0
- package/templates/workflows/claude/README.md +6 -0
- package/templates/workflows/claude/evnict-kit-archive-wiki.md +98 -0
- package/templates/workflows/claude/evnict-kit-attt.md +98 -0
- package/templates/workflows/claude/evnict-kit-bug-fix.md +105 -0
- package/templates/workflows/claude/evnict-kit-feature-large.md +391 -0
- package/templates/workflows/claude/evnict-kit-feature-small.md +84 -0
- package/templates/workflows/claude/evnict-kit-handoff.md +240 -0
- package/templates/workflows/claude/evnict-kit-implement.md +245 -0
- package/templates/workflows/claude/evnict-kit-init-check.md +74 -0
- package/templates/workflows/claude/evnict-kit-init-context.md +56 -0
- package/templates/workflows/claude/evnict-kit-init-rules.md +112 -0
- package/templates/workflows/claude/evnict-kit-init-wiki.md +78 -0
- package/templates/workflows/claude/evnict-kit-plan.md +305 -0
- package/templates/workflows/claude/evnict-kit-review.md +51 -0
- package/templates/workflows/claude/evnict-kit-spec-archive.md +51 -0
- package/templates/workflows/claude/evnict-kit-wiki-archive-feature.md +162 -0
- package/templates/workflows/claude/evnict-kit-wiki-query.md +89 -0
- package/templates/workflows/claude/evnict-kit-wiki-scan-project.md +270 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
---
|
|
4
|
+
# Frontend Conventions — EVNICT Standard
|
|
5
|
+
**Activation Mode: Always On**
|
|
6
|
+
**Source: QĐ-TTPM Điều 8, Mục 8.6**
|
|
7
|
+
**Tech: Angular + PrimeNG**
|
|
8
|
+
|
|
9
|
+
> Áp dụng cho TẤT CẢ code frontend. Mọi code mới hoặc sửa đổi PHẢI tuân thủ.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. NO INLINE STYLES (RF01)
|
|
14
|
+
|
|
15
|
+
### Quy tắc
|
|
16
|
+
- KHÔNG sử dụng inline styles trực tiếp trong template
|
|
17
|
+
- Tất cả styles PHẢI đặt trong file `.scss` hoặc `.css` riêng
|
|
18
|
+
- Dùng CSS classes, KHÔNG dùng `[style]` binding
|
|
19
|
+
- Exception: dynamic styles từ business logic (VD: chart colors)
|
|
20
|
+
|
|
21
|
+
### Code examples
|
|
22
|
+
```html
|
|
23
|
+
<!-- ❌ SAI — Inline styles -->
|
|
24
|
+
<div style="color: red; font-size: 14px; margin-top: 10px">
|
|
25
|
+
{{ errorMessage }}
|
|
26
|
+
</div>
|
|
27
|
+
<div [style.color]="isError ? 'red' : 'green'">Status</div>
|
|
28
|
+
|
|
29
|
+
<!-- ✅ ĐÚNG — CSS class -->
|
|
30
|
+
<div class="error-message" [class.error]="isError" [class.success]="!isError">
|
|
31
|
+
{{ errorMessage }}
|
|
32
|
+
</div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```scss
|
|
36
|
+
// ✅ Trong component.scss
|
|
37
|
+
.error-message {
|
|
38
|
+
font-size: 14px;
|
|
39
|
+
margin-top: 10px;
|
|
40
|
+
|
|
41
|
+
&.error { color: var(--color-error); }
|
|
42
|
+
&.success { color: var(--color-success); }
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Scan commands
|
|
47
|
+
```bash
|
|
48
|
+
grep -rn "style=\"" --include="*.html" src/
|
|
49
|
+
grep -rn "\[style\." --include="*.html" src/
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 2. COMPONENT REUSE (RF02)
|
|
55
|
+
|
|
56
|
+
### Quy tắc
|
|
57
|
+
- TRƯỚC KHI tạo component mới → kiểm tra đã có component tương tự chưa
|
|
58
|
+
- Tìm trong: `shared/components/`, PrimeNG library, project components
|
|
59
|
+
- Nếu đã có → reuse hoặc extend
|
|
60
|
+
- Component mới PHẢI đặt trong `shared/` nếu dùng ≥ 2 nơi
|
|
61
|
+
|
|
62
|
+
### Component categories
|
|
63
|
+
```
|
|
64
|
+
src/app/
|
|
65
|
+
├── shared/
|
|
66
|
+
│ ├── components/ ← Reusable components (dùng ≥ 2 nơi)
|
|
67
|
+
│ │ ├── data-table/ ← Generic table wrapper
|
|
68
|
+
│ │ ├── form-field/ ← Form field với validation
|
|
69
|
+
│ │ ├── file-upload/ ← Upload component
|
|
70
|
+
│ │ └── confirm-dialog/
|
|
71
|
+
│ ├── pipes/ ← Shared pipes
|
|
72
|
+
│ ├── directives/ ← Shared directives
|
|
73
|
+
│ └── services/ ← Shared services
|
|
74
|
+
├── features/
|
|
75
|
+
│ └── customer/
|
|
76
|
+
│ ├── components/ ← Feature-specific components
|
|
77
|
+
│ ├── pages/ ← Routed pages
|
|
78
|
+
│ └── services/ ← Feature services
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### PrimeNG usage
|
|
82
|
+
```typescript
|
|
83
|
+
// ✅ ĐÚNG — Dùng PrimeNG components trước khi tự viết
|
|
84
|
+
// Table → p-table
|
|
85
|
+
// Dialog → p-dialog
|
|
86
|
+
// Form elements → p-inputText, p-dropdown, p-calendar
|
|
87
|
+
// Toast → p-toast (qua MessageService)
|
|
88
|
+
// Confirm → p-confirmDialog (qua ConfirmationService)
|
|
89
|
+
|
|
90
|
+
// ❌ SAI — Tự viết component khi PrimeNG đã có
|
|
91
|
+
// Custom table → Dùng p-table
|
|
92
|
+
// Custom dropdown → Dùng p-dropdown
|
|
93
|
+
// Custom date picker → Dùng p-calendar
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 3. NO HARDCODED TEXT / I18N (RF03)
|
|
99
|
+
|
|
100
|
+
### Quy tắc
|
|
101
|
+
- KHÔNG hardcode text hiển thị trong template hoặc component
|
|
102
|
+
- Tất cả text PHẢI qua i18n (ngx-translate hoặc Angular i18n)
|
|
103
|
+
- Labels, messages, tooltips, placeholders → đều qua translate
|
|
104
|
+
|
|
105
|
+
### Code examples
|
|
106
|
+
```html
|
|
107
|
+
<!-- ❌ SAI — Hardcoded text -->
|
|
108
|
+
<button>Tạo mới</button>
|
|
109
|
+
<label>Tên khách hàng:</label>
|
|
110
|
+
<p-message severity="error" text="Không tìm thấy dữ liệu"></p-message>
|
|
111
|
+
|
|
112
|
+
<!-- ✅ ĐÚNG — i18n -->
|
|
113
|
+
<button>{{ 'button.create' | translate }}</button>
|
|
114
|
+
<label>{{ 'customer.name' | translate }}:</label>
|
|
115
|
+
<p-message severity="error" [text]="'message.notFound' | translate"></p-message>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
// vi.json
|
|
120
|
+
{
|
|
121
|
+
"button": {
|
|
122
|
+
"create": "Tạo mới",
|
|
123
|
+
"save": "Lưu",
|
|
124
|
+
"cancel": "Hủy",
|
|
125
|
+
"delete": "Xóa",
|
|
126
|
+
"search": "Tìm kiếm"
|
|
127
|
+
},
|
|
128
|
+
"customer": {
|
|
129
|
+
"name": "Tên khách hàng",
|
|
130
|
+
"phone": "Số điện thoại"
|
|
131
|
+
},
|
|
132
|
+
"message": {
|
|
133
|
+
"notFound": "Không tìm thấy dữ liệu",
|
|
134
|
+
"saveSuccess": "Lưu thành công",
|
|
135
|
+
"confirmDelete": "Bạn có chắc chắn muốn xóa?"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Ngoại lệ
|
|
141
|
+
- Technical strings (CSS class names, HTML attributes)
|
|
142
|
+
- Enum labels → nên qua i18n nhưng có thể hardcode trong các dict objects
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 4. ACCESSIBILITY / A11Y (RF04)
|
|
147
|
+
|
|
148
|
+
### Quy tắc
|
|
149
|
+
- Mọi `<img>` PHẢI có `alt` attribute
|
|
150
|
+
- Mọi form field PHẢI có `<label>` hoặc `aria-label`
|
|
151
|
+
- Mọi interactive element PHẢI có `tabindex` hợp lý
|
|
152
|
+
- Color contrast ratio ≥ 4.5:1 cho text
|
|
153
|
+
|
|
154
|
+
### Code examples
|
|
155
|
+
```html
|
|
156
|
+
<!-- ❌ SAI — Thiếu a11y -->
|
|
157
|
+
<img src="logo.png">
|
|
158
|
+
<input type="text" placeholder="Search">
|
|
159
|
+
<div (click)="doSomething()">Click me</div>
|
|
160
|
+
|
|
161
|
+
<!-- ✅ ĐÚNG — a11y đầy đủ -->
|
|
162
|
+
<img src="logo.png" alt="Logo EVNICT">
|
|
163
|
+
<label for="search">{{ 'label.search' | translate }}</label>
|
|
164
|
+
<input type="text" id="search" [placeholder]="'placeholder.search' | translate" aria-label="Search">
|
|
165
|
+
<button (click)="doSomething()" tabindex="0">
|
|
166
|
+
{{ 'button.action' | translate }}
|
|
167
|
+
</button>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Scan commands
|
|
171
|
+
```bash
|
|
172
|
+
grep -rn "<img " --include="*.html" src/ | grep -v "alt="
|
|
173
|
+
grep -rn "<input " --include="*.html" src/ | grep -v "aria-label\|id="
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 5. NO DIRECT DOM MANIPULATION (RF05)
|
|
179
|
+
|
|
180
|
+
### Quy tắc
|
|
181
|
+
- KHÔNG dùng `document.getElementById()`, `document.querySelector()`
|
|
182
|
+
- KHÔNG dùng `jQuery` hoặc truy cập DOM trực tiếp
|
|
183
|
+
- Dùng Angular bindings, `@ViewChild`, hoặc `Renderer2`
|
|
184
|
+
- Exception: third-party library integration (VD: chart.js) → dùng `@ViewChild`
|
|
185
|
+
|
|
186
|
+
### Code examples
|
|
187
|
+
```typescript
|
|
188
|
+
// ❌ SAI — Direct DOM manipulation
|
|
189
|
+
ngAfterViewInit() {
|
|
190
|
+
document.getElementById('myInput').focus();
|
|
191
|
+
document.querySelector('.container').classList.add('active');
|
|
192
|
+
const el = document.getElementsByClassName('item');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ✅ ĐÚNG — Angular way
|
|
196
|
+
@ViewChild('myInput') myInput: ElementRef;
|
|
197
|
+
|
|
198
|
+
ngAfterViewInit() {
|
|
199
|
+
this.myInput.nativeElement.focus();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ✅ ĐÚNG — Renderer2
|
|
203
|
+
constructor(private renderer: Renderer2) {}
|
|
204
|
+
|
|
205
|
+
setActive(el: ElementRef) {
|
|
206
|
+
this.renderer.addClass(el.nativeElement, 'active');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ✅ ĐÚNG — Template bindings
|
|
210
|
+
// <div [class.active]="isActive"></div>
|
|
211
|
+
// <input #myInput (keyup)="onKeyUp()">
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Scan commands
|
|
215
|
+
```bash
|
|
216
|
+
grep -rn "document\.getElementById\|document\.querySelector\|document\.getElement" --include="*.ts" src/
|
|
217
|
+
grep -rn "jQuery\|\\$(" --include="*.ts" src/
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 6. RESPONSIVE DESIGN (RF06)
|
|
223
|
+
|
|
224
|
+
### Quy tắc
|
|
225
|
+
- Tất cả pages PHẢI responsive cho: Desktop (≥1200px), Tablet (768-1199px), Mobile (≤767px)
|
|
226
|
+
- Dùng PrimeNG Grid system (p-grid, p-col) hoặc CSS Grid/Flexbox
|
|
227
|
+
- Test responsive trước khi commit
|
|
228
|
+
- Text KHÔNG bị cắt, table PHẢI scrollable trên mobile
|
|
229
|
+
|
|
230
|
+
### Code examples
|
|
231
|
+
```html
|
|
232
|
+
<!-- ✅ ĐÚNG — PrimeNG responsive grid -->
|
|
233
|
+
<div class="grid">
|
|
234
|
+
<div class="col-12 md:col-6 lg:col-4">
|
|
235
|
+
<!-- Card 1 -->
|
|
236
|
+
</div>
|
|
237
|
+
<div class="col-12 md:col-6 lg:col-4">
|
|
238
|
+
<!-- Card 2 -->
|
|
239
|
+
</div>
|
|
240
|
+
<div class="col-12 md:col-12 lg:col-4">
|
|
241
|
+
<!-- Card 3 -->
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<!-- ✅ Table responsive -->
|
|
246
|
+
<div class="table-responsive">
|
|
247
|
+
<p-table [value]="data" [scrollable]="true" scrollHeight="400px"
|
|
248
|
+
[responsive]="true" responsiveLayout="scroll">
|
|
249
|
+
<!-- columns -->
|
|
250
|
+
</p-table>
|
|
251
|
+
</div>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```scss
|
|
255
|
+
// ✅ SCSS responsive
|
|
256
|
+
.page-container {
|
|
257
|
+
padding: 1rem;
|
|
258
|
+
|
|
259
|
+
@media (max-width: 768px) {
|
|
260
|
+
padding: 0.5rem;
|
|
261
|
+
|
|
262
|
+
.action-buttons {
|
|
263
|
+
flex-direction: column;
|
|
264
|
+
gap: 0.5rem;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 7. ANGULAR CONVENTIONS
|
|
273
|
+
|
|
274
|
+
### File naming
|
|
275
|
+
| Loại | Pattern | Ví dụ |
|
|
276
|
+
|------|---------|-------|
|
|
277
|
+
| Component | `{name}.component.ts` | `customer-list.component.ts` |
|
|
278
|
+
| Service | `{name}.service.ts` | `customer.service.ts` |
|
|
279
|
+
| Module | `{name}.module.ts` | `customer.module.ts` |
|
|
280
|
+
| Pipe | `{name}.pipe.ts` | `date-format.pipe.ts` |
|
|
281
|
+
| Directive | `{name}.directive.ts` | `auto-focus.directive.ts` |
|
|
282
|
+
| Guard | `{name}.guard.ts` | `auth.guard.ts` |
|
|
283
|
+
| Interceptor | `{name}.interceptor.ts` | `auth.interceptor.ts` |
|
|
284
|
+
| Model/Interface | `{name}.model.ts` | `customer.model.ts` |
|
|
285
|
+
|
|
286
|
+
### Component structure
|
|
287
|
+
```typescript
|
|
288
|
+
// ✅ ĐÚNG — Component tiêu chuẩn
|
|
289
|
+
@Component({
|
|
290
|
+
selector: 'app-customer-list',
|
|
291
|
+
templateUrl: './customer-list.component.html',
|
|
292
|
+
styleUrls: ['./customer-list.component.scss']
|
|
293
|
+
})
|
|
294
|
+
export class CustomerListComponent implements OnInit, OnDestroy {
|
|
295
|
+
// 1. Decorators
|
|
296
|
+
@ViewChild('dt') table: Table;
|
|
297
|
+
|
|
298
|
+
// 2. Public properties (used in template)
|
|
299
|
+
customers: CustomerDTO[] = [];
|
|
300
|
+
loading = false;
|
|
301
|
+
totalRecords = 0;
|
|
302
|
+
|
|
303
|
+
// 3. Private properties
|
|
304
|
+
private destroy$ = new Subject<void>();
|
|
305
|
+
|
|
306
|
+
// 4. Constructor (DI)
|
|
307
|
+
constructor(
|
|
308
|
+
private customerService: CustomerService,
|
|
309
|
+
private messageService: MessageService
|
|
310
|
+
) {}
|
|
311
|
+
|
|
312
|
+
// 5. Lifecycle hooks
|
|
313
|
+
ngOnInit(): void {
|
|
314
|
+
this.loadData();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
ngOnDestroy(): void {
|
|
318
|
+
this.destroy$.next();
|
|
319
|
+
this.destroy$.complete();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// 6. Public methods (used in template)
|
|
323
|
+
loadData(): void { ... }
|
|
324
|
+
onCreate(): void { ... }
|
|
325
|
+
|
|
326
|
+
// 7. Private methods
|
|
327
|
+
private handleError(err: any): void { ... }
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Service pattern
|
|
332
|
+
```typescript
|
|
333
|
+
// ✅ ĐÚNG — Service tiêu chuẩn
|
|
334
|
+
@Injectable({ providedIn: 'root' })
|
|
335
|
+
export class CustomerService {
|
|
336
|
+
private baseUrl = `${environment.apiUrl}/api/customers`;
|
|
337
|
+
|
|
338
|
+
constructor(private http: HttpClient) {}
|
|
339
|
+
|
|
340
|
+
search(keyword: string, page: number, size: number): Observable<ResponseData> {
|
|
341
|
+
const params = new HttpParams()
|
|
342
|
+
.set('keyword', keyword)
|
|
343
|
+
.set('page', page.toString())
|
|
344
|
+
.set('size', size.toString());
|
|
345
|
+
return this.http.get<ResponseData>(this.baseUrl, { params });
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
getById(id: number): Observable<ResponseData> {
|
|
349
|
+
return this.http.get<ResponseData>(`${this.baseUrl}/${id}`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
create(dto: CustomerDTO): Observable<ResponseData> {
|
|
353
|
+
return this.http.post<ResponseData>(this.baseUrl, dto);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
update(id: number, dto: CustomerDTO): Observable<ResponseData> {
|
|
357
|
+
return this.http.put<ResponseData>(`${this.baseUrl}/${id}`, dto);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
delete(id: number): Observable<ResponseData> {
|
|
361
|
+
return this.http.delete<ResponseData>(`${this.baseUrl}/${id}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### RxJS — Memory leak prevention
|
|
367
|
+
```typescript
|
|
368
|
+
// ❌ SAI — Không unsubscribe → memory leak
|
|
369
|
+
ngOnInit() {
|
|
370
|
+
this.service.getData().subscribe(data => this.data = data);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// ✅ ĐÚNG — takeUntil pattern
|
|
374
|
+
private destroy$ = new Subject<void>();
|
|
375
|
+
|
|
376
|
+
ngOnInit() {
|
|
377
|
+
this.service.getData()
|
|
378
|
+
.pipe(takeUntil(this.destroy$))
|
|
379
|
+
.subscribe(data => this.data = data);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
ngOnDestroy() {
|
|
383
|
+
this.destroy$.next();
|
|
384
|
+
this.destroy$.complete();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ✅ ĐÚNG — async pipe (tự unsubscribe)
|
|
388
|
+
// component.ts
|
|
389
|
+
data$ = this.service.getData();
|
|
390
|
+
// template
|
|
391
|
+
<div *ngIf="data$ | async as data">{{ data.name }}</div>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Scan commands
|
|
395
|
+
```bash
|
|
396
|
+
# Tìm subscribe không unsubscribe
|
|
397
|
+
grep -rn "\.subscribe(" --include="*.ts" src/ | grep -v "takeUntil\|async\|take(1)\|first()"
|
|
398
|
+
# Tìm inline styles
|
|
399
|
+
grep -rn "style=\"" --include="*.html" src/
|
|
400
|
+
# Tìm document access
|
|
401
|
+
grep -rn "document\." --include="*.ts" src/
|
|
402
|
+
```
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
---
|
|
2
|
+
trigger: always_on
|
|
3
|
+
---
|
|
4
|
+
# Project Conventions — EVNICT Standard
|
|
5
|
+
**Activation Mode: Always On**
|
|
6
|
+
**Source: QĐ-TTPM Phụ lục IV — Hướng dẫn thiết lập ngữ cảnh**
|
|
7
|
+
|
|
8
|
+
> **⚠️ FILE NÀY CẦN ĐƯỢC KHỞI TẠO BỞI AI AGENT**
|
|
9
|
+
> Chạy `/evnict-kit:init-rules` → Agent đọc codebase → tự động điền nội dung.
|
|
10
|
+
> Các section bên dưới chứa placeholder — Agent sẽ thay thế bằng conventions thực tế của dự án.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## RP01 — NAMING CONVENTION
|
|
15
|
+
|
|
16
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định naming conventions.
|
|
17
|
+
|
|
18
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
19
|
+
- Package/namespace naming pattern
|
|
20
|
+
- Class naming pattern (Controller, Service, Repository, DTO, Entity)
|
|
21
|
+
- Method naming pattern (CRUD, search, business operations)
|
|
22
|
+
- Variable naming pattern (fields, locals, constants)
|
|
23
|
+
- File naming pattern
|
|
24
|
+
- Database table/column naming pattern
|
|
25
|
+
- API path naming pattern
|
|
26
|
+
|
|
27
|
+
### Format mẫu (Agent sẽ điền theo dự án thực tế):
|
|
28
|
+
```
|
|
29
|
+
Package: com.evn.{project}.{module}
|
|
30
|
+
Class: {Module}{Type}.java (VD: CustomerService.java)
|
|
31
|
+
Method: camelCase, prefix: find/get/create/update/delete
|
|
32
|
+
Variable: camelCase, descriptive
|
|
33
|
+
Constant: UPPER_SNAKE_CASE
|
|
34
|
+
Table: UPPER_SNAKE_CASE (VD: CUSTOMER, DON_VI)
|
|
35
|
+
Column: UPPER_SNAKE_CASE (VD: CREATED_DATE, DON_VI_ID)
|
|
36
|
+
API: /api/{module}/{action} (VD: /api/customers/search)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## RP02 — ARCHITECTURE PATTERN
|
|
42
|
+
|
|
43
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định kiến trúc.
|
|
44
|
+
|
|
45
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
46
|
+
- Overall architecture (MVC, Clean Architecture, Hexagonal...)
|
|
47
|
+
- Layer structure (Controller → Service → Repository)
|
|
48
|
+
- Module organization (by feature, by layer, hybrid)
|
|
49
|
+
- Dependency direction rules
|
|
50
|
+
- Cross-cutting concerns (logging, auth, exception handling)
|
|
51
|
+
|
|
52
|
+
### Format mẫu:
|
|
53
|
+
```
|
|
54
|
+
Architecture: Layered MVC
|
|
55
|
+
Layers:
|
|
56
|
+
1. Controller — HTTP handling, input validation
|
|
57
|
+
2. Service — Business logic, transaction management
|
|
58
|
+
3. Repository — Data access (JOOQ/JPA)
|
|
59
|
+
4. DTO/Entity — Data transfer / persistence
|
|
60
|
+
|
|
61
|
+
Module Structure:
|
|
62
|
+
src/main/java/com/evn/{project}/
|
|
63
|
+
├── config/ ← Application configuration
|
|
64
|
+
├── common/ ← Shared utilities, base classes
|
|
65
|
+
├── security/ ← Auth, JWT, filters
|
|
66
|
+
└── {module}/ ← Feature modules
|
|
67
|
+
├── controller/
|
|
68
|
+
├── service/
|
|
69
|
+
├── repository/
|
|
70
|
+
└── dto/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## RP03 — CODING CONVENTION
|
|
76
|
+
|
|
77
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định coding style.
|
|
78
|
+
|
|
79
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
80
|
+
- Indentation (tabs vs spaces, size)
|
|
81
|
+
- Import ordering
|
|
82
|
+
- Method ordering within class
|
|
83
|
+
- Comment style
|
|
84
|
+
- Exception handling pattern
|
|
85
|
+
- Logging convention
|
|
86
|
+
- Null handling (Optional, null checks, annotations)
|
|
87
|
+
|
|
88
|
+
### Format mẫu:
|
|
89
|
+
```
|
|
90
|
+
Indentation: 4 spaces (Java), 2 spaces (TypeScript/HTML/SCSS)
|
|
91
|
+
Max line length: 120 characters
|
|
92
|
+
Import order: java.*, javax.*, org.*, com.*, static
|
|
93
|
+
Method order: public → protected → private
|
|
94
|
+
Logging: SLF4J with Lombok @Slf4j
|
|
95
|
+
Null: @Nullable/@NonNull annotations, Optional for return types
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## RP04 — API CONVENTION
|
|
101
|
+
|
|
102
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định API patterns.
|
|
103
|
+
|
|
104
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
105
|
+
- Base URL pattern
|
|
106
|
+
- HTTP method usage (GET/POST/PUT/DELETE)
|
|
107
|
+
- Request/Response format (ResponseData wrapper)
|
|
108
|
+
- Pagination pattern
|
|
109
|
+
- Error response format
|
|
110
|
+
- Authentication header format
|
|
111
|
+
- API versioning (if any)
|
|
112
|
+
|
|
113
|
+
### Format mẫu:
|
|
114
|
+
```
|
|
115
|
+
Base URL: /api/{module}
|
|
116
|
+
Response: ResponseData { status, message, data }
|
|
117
|
+
Pagination: ?page=0&size=20&sort=name
|
|
118
|
+
Auth Header: Authorization: Bearer {token}
|
|
119
|
+
Error: ResponseData { status: 1, message: "...", data: null }
|
|
120
|
+
|
|
121
|
+
Endpoints:
|
|
122
|
+
GET /api/{module} → List (paginated)
|
|
123
|
+
GET /api/{module}/{id} → Get by ID
|
|
124
|
+
POST /api/{module} → Create
|
|
125
|
+
PUT /api/{module}/{id} → Update
|
|
126
|
+
DELETE /api/{module}/{id} → Delete
|
|
127
|
+
POST /api/{module}/search → Complex search
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## RP05 — DATABASE CONVENTION
|
|
133
|
+
|
|
134
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định DB patterns.
|
|
135
|
+
|
|
136
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
137
|
+
- Database type & version
|
|
138
|
+
- Schema structure (single/multi schema)
|
|
139
|
+
- Table naming convention
|
|
140
|
+
- Column naming convention
|
|
141
|
+
- Primary key pattern (sequence, UUID, identity)
|
|
142
|
+
- Foreign key naming
|
|
143
|
+
- Index naming
|
|
144
|
+
- Audit columns (created_by, created_date, etc.)
|
|
145
|
+
- Soft delete pattern (if used)
|
|
146
|
+
|
|
147
|
+
### Format mẫu:
|
|
148
|
+
```
|
|
149
|
+
Database: Oracle 19c
|
|
150
|
+
Schemas: EVNTMS (system), {PROJECT} (business)
|
|
151
|
+
Table: UPPER_SNAKE (VD: CUSTOMER, HD_DIEN)
|
|
152
|
+
Column: UPPER_SNAKE (VD: TEN_KH, MA_DON_VI)
|
|
153
|
+
PK: ID (NUMBER, sequence {TABLE}_SEQ)
|
|
154
|
+
FK: {TABLE}_{REF_TABLE}_FK
|
|
155
|
+
Index: IX_{TABLE}_{COLUMNS}
|
|
156
|
+
Audit: CREATED_BY, CREATED_DATE, UPDATED_BY, UPDATED_DATE
|
|
157
|
+
Soft delete: IS_DELETED (NUMBER(1)) hoặc STATUS = 'DELETED'
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## RP06 — COMPONENT CONVENTION (Frontend)
|
|
163
|
+
|
|
164
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định component patterns.
|
|
165
|
+
|
|
166
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
167
|
+
- Component file structure
|
|
168
|
+
- Shared vs feature-specific components
|
|
169
|
+
- Naming convention (selector prefix, file names)
|
|
170
|
+
- State management pattern
|
|
171
|
+
- UI library usage (PrimeNG components)
|
|
172
|
+
- Form handling pattern (Reactive Forms vs Template-driven)
|
|
173
|
+
- Routing pattern
|
|
174
|
+
|
|
175
|
+
### Format mẫu:
|
|
176
|
+
```
|
|
177
|
+
Selector prefix: app-
|
|
178
|
+
File structure: {name}.component.ts/html/scss
|
|
179
|
+
Shared path: src/app/shared/components/
|
|
180
|
+
Feature path: src/app/features/{module}/components/
|
|
181
|
+
State: Service + BehaviorSubject (no NgRx)
|
|
182
|
+
UI Library: PrimeNG 16+
|
|
183
|
+
Forms: Reactive Forms (FormBuilder)
|
|
184
|
+
Routing: Lazy-loaded feature modules
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## RP07 — INTEGRATION MAP
|
|
190
|
+
|
|
191
|
+
> ⚠️ **CHƯA ĐƯỢC KHỞI TẠO** — Agent cần scan codebase để xác định integrations.
|
|
192
|
+
|
|
193
|
+
### Khi khởi tạo, Agent sẽ điền:
|
|
194
|
+
- External services integrated (SSO, MinIO, CMIS, etc.)
|
|
195
|
+
- Internal service dependencies
|
|
196
|
+
- Message queues / event systems
|
|
197
|
+
- Caching strategy
|
|
198
|
+
- File storage
|
|
199
|
+
- Email/notification services
|
|
200
|
+
|
|
201
|
+
### Format mẫu:
|
|
202
|
+
```
|
|
203
|
+
Authentication: EVN SSO → JWT (RS256)
|
|
204
|
+
File Storage: MinIO (S3-compatible)
|
|
205
|
+
Document: CMIS (Content Management)
|
|
206
|
+
Cache: Redis (session) / Caffeine (local)
|
|
207
|
+
Email: SMTP server
|
|
208
|
+
Notification: WebSocket (SockJS + STOMP)
|
|
209
|
+
CI/CD: Azure DevOps Pipelines
|
|
210
|
+
Container: Docker + Kubernetes
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## HƯỚNG DẪN KHỞI TẠO
|
|
216
|
+
|
|
217
|
+
Khi Agent nhận `/evnict-kit:init-rules`:
|
|
218
|
+
|
|
219
|
+
1. **Scan codebase** — `tree -L 3`, đọc các file cốt lõi (pom.xml, package.json, config files)
|
|
220
|
+
2. **Phân tích patterns** — Tìm patterns từ code hiện có
|
|
221
|
+
3. **Điền từng section** — Thay thế "⚠️ CHƯA ĐƯỢC KHỞI TẠO" bằng nội dung thực tế
|
|
222
|
+
4. **Thêm code examples** — Lấy từ code thực tế của dự án (KHÔNG code mẫu generic)
|
|
223
|
+
5. **Validate** — Đảm bảo conventions phù hợp với code hiện có
|
|
224
|
+
|
|
225
|
+
**SAU KHI khởi tạo:**
|
|
226
|
+
- Xóa tất cả placeholder "⚠️ CHƯA ĐƯỢC KHỞI TẠO"
|
|
227
|
+
- Đổi mỗi section header thành `✅ ĐÃ KHỞI TẠO — {date}`
|
|
228
|
+
- Commit: `chore: initialize project conventions RP01-RP07`
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Claude Code Templates
|
|
2
|
+
|
|
3
|
+
> TODO: Adapt rules for Claude Code (`.claude/` structure)
|
|
4
|
+
> Planned for evnict-kit v0.2.0
|
|
5
|
+
>
|
|
6
|
+
> Claude Code uses a single `CLAUDE.md` context file at project root.
|
|
7
|
+
> Rules are embedded directly in CLAUDE.md (no separate rules folder).
|
|
8
|
+
> Skills use `.claude/commands/` as slash commands.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: EVNICT General Rules — No Secrets, No Auto Push, Test Before Commit, Minimal Diff
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# General Rules — EVNICT Standard
|
|
8
|
+
> QĐ-TTPM Điều 8 — LUÔN kiểm tra. Vi phạm → DỪNG ngay.
|
|
9
|
+
|
|
10
|
+
## R01: No Hardcoded Secrets — CRITICAL
|
|
11
|
+
- KHÔNG hardcode passwords, API keys, tokens, JWT secrets, connection strings
|
|
12
|
+
- Dùng env vars: `@Value("${spring.datasource.password}")`, `environment.apiUrl`
|
|
13
|
+
- Scan: `grep -rn "password\s*=\s*\"" --include="*.java" --include="*.ts" src/`
|
|
14
|
+
|
|
15
|
+
## R02: No Auto Git Push
|
|
16
|
+
- KHÔNG `git push` / `git push --force` — PHẢI HỎI USER
|
|
17
|
+
- Được phép: `git add`, `git commit`, `git status`, `git log`, `git diff`, `git stash`
|
|
18
|
+
|
|
19
|
+
## R03: No Destructive Operations
|
|
20
|
+
- KHÔNG `rm -rf` trên src/, database/, docs/
|
|
21
|
+
- KHÔNG `DROP TABLE`, `TRUNCATE TABLE` production
|
|
22
|
+
- Trước khi xóa → kiểm tra git status, hỏi user confirm
|
|
23
|
+
|
|
24
|
+
## R04: No PII In Logs
|
|
25
|
+
- KHÔNG log: password, token, JWT, CMND, phone, email, card number
|
|
26
|
+
- OK: log userId, customerId, action, count, status
|
|
27
|
+
|
|
28
|
+
## R05: Test Before Commit
|
|
29
|
+
- BẮT BUỘC: `./mvnw test` (BE) hoặc `ng test --watch=false` (FE)
|
|
30
|
+
- Test FAIL → fix trước, không commit
|
|
31
|
+
|
|
32
|
+
## R06: Minimal Diff
|
|
33
|
+
- CHỈ sửa code liên quan yêu cầu
|
|
34
|
+
- KHÔNG refactor/rename ngoài scope
|
|
35
|
+
- Sửa >3 lần cùng đoạn → DỪNG (vibe coding)
|
|
36
|
+
|
|
37
|
+
## R07: No Placeholder Code
|
|
38
|
+
- KHÔNG `// TODO: implement later`, KHÔNG method rỗng
|
|
39
|
+
- Mỗi function PHẢI có logic thực tế
|
|
40
|
+
|
|
41
|
+
## R08: Respect Gitignore
|
|
42
|
+
- KHÔNG tạo/commit: node_modules/, .env, *.key, *.pem, target/, dist/
|
|
43
|
+
|
|
44
|
+
## Checkpoint
|
|
45
|
+
- Trước phiên AI: `git checkout -b feature/ai-task-xxx`
|
|
46
|
+
- Revert được trong ≤ 1 thao tác git
|