@regardio/dev 1.24.0 → 2.0.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.
Files changed (128) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/ship/hotfix.bin.mjs +140 -0
  3. package/dist/bin/ship/production.bin.mjs +120 -0
  4. package/dist/bin/ship/staging.bin.mjs +70 -0
  5. package/dist/bin/ship/utils-BQ-JZ2D5.mjs +45 -0
  6. package/dist/playwright/index.d.mts +24 -0
  7. package/dist/playwright/index.mjs +61 -0
  8. package/dist/vitest/node.d.mts +22 -0
  9. package/dist/vitest/node.mjs +28 -0
  10. package/dist/vitest/react.d.mts +22 -0
  11. package/dist/vitest/react.mjs +28 -0
  12. package/docs/en/README.md +95 -0
  13. package/docs/en/agents.md +57 -0
  14. package/docs/en/standards/api.md +324 -0
  15. package/docs/en/standards/coding.md +144 -0
  16. package/docs/en/standards/commits.md +111 -0
  17. package/docs/en/standards/documentation.md +173 -0
  18. package/docs/en/standards/naming.md +180 -0
  19. package/docs/en/standards/principles.md +84 -0
  20. package/docs/en/standards/react.md +246 -0
  21. package/docs/en/standards/sql.md +258 -0
  22. package/docs/en/standards/testing.md +139 -0
  23. package/docs/en/standards/writing.md +119 -0
  24. package/docs/en/tools/biome.md +89 -0
  25. package/docs/en/tools/commitlint.md +92 -0
  26. package/docs/en/tools/dependencies.md +116 -0
  27. package/docs/en/tools/husky.md +90 -0
  28. package/docs/en/tools/markdownlint.md +84 -0
  29. package/docs/en/tools/playwright.md +117 -0
  30. package/docs/en/tools/releases.md +242 -0
  31. package/docs/en/tools/typescript.md +89 -0
  32. package/docs/en/tools/vitest.md +146 -0
  33. package/package.json +58 -70
  34. package/src/biome/preset.json +3 -0
  35. package/templates/changeset/README.md +14 -0
  36. package/templates/changeset/config.json +11 -0
  37. package/templates/github/release.yml +77 -0
  38. package/dist/bin/exec/clean.d.ts +0 -3
  39. package/dist/bin/exec/clean.d.ts.map +0 -1
  40. package/dist/bin/exec/clean.js +0 -25
  41. package/dist/bin/exec/clean.test.d.ts +0 -2
  42. package/dist/bin/exec/clean.test.d.ts.map +0 -1
  43. package/dist/bin/exec/clean.test.js +0 -45
  44. package/dist/bin/exec/husky.d.ts +0 -3
  45. package/dist/bin/exec/husky.d.ts.map +0 -1
  46. package/dist/bin/exec/husky.js +0 -9
  47. package/dist/bin/exec/p.d.ts +0 -3
  48. package/dist/bin/exec/p.d.ts.map +0 -1
  49. package/dist/bin/exec/p.js +0 -8
  50. package/dist/bin/exec/s.d.ts +0 -3
  51. package/dist/bin/exec/s.d.ts.map +0 -1
  52. package/dist/bin/exec/s.js +0 -8
  53. package/dist/bin/exec/tsc.d.ts +0 -3
  54. package/dist/bin/exec/tsc.d.ts.map +0 -1
  55. package/dist/bin/exec/tsc.js +0 -8
  56. package/dist/bin/lint/biome.d.ts +0 -3
  57. package/dist/bin/lint/biome.d.ts.map +0 -1
  58. package/dist/bin/lint/biome.js +0 -8
  59. package/dist/bin/lint/commit.d.ts +0 -3
  60. package/dist/bin/lint/commit.d.ts.map +0 -1
  61. package/dist/bin/lint/commit.js +0 -8
  62. package/dist/bin/lint/md.d.ts +0 -3
  63. package/dist/bin/lint/md.d.ts.map +0 -1
  64. package/dist/bin/lint/md.js +0 -16
  65. package/dist/bin/lint/package.d.ts +0 -4
  66. package/dist/bin/lint/package.d.ts.map +0 -1
  67. package/dist/bin/lint/package.js +0 -81
  68. package/dist/bin/lint/package.test.d.ts +0 -2
  69. package/dist/bin/lint/package.test.d.ts.map +0 -1
  70. package/dist/bin/lint/package.test.js +0 -65
  71. package/dist/bin/ship/hotfix.d.ts +0 -3
  72. package/dist/bin/ship/hotfix.d.ts.map +0 -1
  73. package/dist/bin/ship/hotfix.js +0 -141
  74. package/dist/bin/ship/production.d.ts +0 -3
  75. package/dist/bin/ship/production.d.ts.map +0 -1
  76. package/dist/bin/ship/production.js +0 -124
  77. package/dist/bin/ship/staging.d.ts +0 -3
  78. package/dist/bin/ship/staging.d.ts.map +0 -1
  79. package/dist/bin/ship/staging.js +0 -51
  80. package/dist/bin/ship/utils.d.ts +0 -9
  81. package/dist/bin/ship/utils.d.ts.map +0 -1
  82. package/dist/bin/ship/utils.js +0 -63
  83. package/dist/bin/ship/utils.test.d.ts +0 -2
  84. package/dist/bin/ship/utils.test.d.ts.map +0 -1
  85. package/dist/bin/ship/utils.test.js +0 -127
  86. package/dist/config.test.d.ts +0 -2
  87. package/dist/config.test.d.ts.map +0 -1
  88. package/dist/config.test.js +0 -101
  89. package/dist/playwright/index.d.ts +0 -10
  90. package/dist/playwright/index.d.ts.map +0 -1
  91. package/dist/playwright/index.js +0 -42
  92. package/dist/playwright/index.test.d.ts +0 -2
  93. package/dist/playwright/index.test.d.ts.map +0 -1
  94. package/dist/playwright/index.test.js +0 -55
  95. package/dist/testing/setup-react.d.ts +0 -2
  96. package/dist/testing/setup-react.d.ts.map +0 -1
  97. package/dist/testing/setup-react.js +0 -1
  98. package/dist/vitest/node.d.ts +0 -22
  99. package/dist/vitest/node.d.ts.map +0 -1
  100. package/dist/vitest/node.js +0 -16
  101. package/dist/vitest/react.d.ts +0 -17
  102. package/dist/vitest/react.d.ts.map +0 -1
  103. package/dist/vitest/react.js +0 -12
  104. package/src/bin/exec/clean.test.ts +0 -63
  105. package/src/bin/exec/clean.ts +0 -36
  106. package/src/bin/exec/husky.ts +0 -14
  107. package/src/bin/exec/p.ts +0 -13
  108. package/src/bin/exec/s.ts +0 -13
  109. package/src/bin/exec/tsc.ts +0 -13
  110. package/src/bin/lint/biome.ts +0 -13
  111. package/src/bin/lint/commit.ts +0 -13
  112. package/src/bin/lint/md.ts +0 -28
  113. package/src/bin/lint/package.test.ts +0 -83
  114. package/src/bin/lint/package.ts +0 -108
  115. package/src/bin/ship/hotfix.ts +0 -241
  116. package/src/bin/ship/production.ts +0 -240
  117. package/src/bin/ship/staging.ts +0 -108
  118. package/src/bin/ship/utils.test.ts +0 -178
  119. package/src/bin/ship/utils.ts +0 -109
  120. package/src/config.test.ts +0 -129
  121. package/src/markdownlint/markdownlint-cli2.jsonc +0 -9
  122. package/src/playwright/index.test.ts +0 -73
  123. package/src/playwright/index.ts +0 -63
  124. package/src/templates/release.yml +0 -128
  125. package/src/testing/setup-react.ts +0 -8
  126. package/src/vitest/node.ts +0 -25
  127. package/src/vitest/react.ts +0 -19
  128. /package/{src → templates}/sqlfluff/setup.cfg +0 -0
@@ -0,0 +1,57 @@
1
+ ---
2
+
3
+ title: AI Agent Guidelines
4
+ type: guide
5
+ status: published
6
+ summary: Instructions for AI coding assistants working with Regardio projects
7
+ related: [coding-standards, react-standards, development-principles]
8
+ locale: en-US
9
+ ---
10
+
11
+ # AI Agent Guidelines
12
+
13
+ Baseline expectations for AI coding assistants working in Regardio projects. Follow the linked standards — they apply equally to agent and human contributions.
14
+
15
+ ## How Agents Should Work
16
+
17
+ - **Scope changes tightly** - Only change what the task requires. Do not refactor adjacent code, add features, or reorganize files unless asked.
18
+ - **Read before writing** - Understand existing patterns in the file and its neighbors before editing. Match the style you find.
19
+ - **Avoid unnecessary complexity** - Only implement what is explicitly required. Do not introduce abstractions, helpers, or utilities speculatively.
20
+ - **No emojis** - Unless explicitly requested.
21
+ - **Preserve comments and documentation** - Do not add or remove comments unless the task calls for it.
22
+ - **Explain uncertainty** - If something is ambiguous, say so rather than guessing.
23
+
24
+ ## Implementation Workflow
25
+
26
+ When working on any non-trivial task, follow this sequence:
27
+
28
+ 1. **Understand the business logic** — Gather context before writing code. Read relevant domain documents. Know what is actually needed; do not implement what was not asked for.
29
+ 2. **Evaluate existing solutions** — Check for well-maintained libraries or utilities before writing custom code. Do not reinvent; do not introduce a dependency without verifying it exists and is actively maintained.
30
+ 3. **Define tests first** — Identify what tests describe the expected behavior before implementing. Tests are a contract. Do not modify tests to make them pass.
31
+ 4. **Implement with reusability in mind** — Prefer simple, readable code. Duplicate until a clear pattern emerges, then extract. Avoid speculative abstractions.
32
+ 5. **Stop if it gets complicated** — Growing complexity despite good preparation is a signal. Surface the difficulty, reconsider the approach, and back out rather than pushing through.
33
+ 6. **Document intent, stay lean** — Comments explain *why*, not *what*. Check existing documentation and business logic context before starting work.
34
+
35
+ ## Standards
36
+
37
+ - [Coding Standards](./standards/coding.md) — TypeScript, React, and general coding patterns
38
+ - [React and TypeScript Standards](./standards/react.md) — Component, hook, and state patterns
39
+ - [SQL Schema Standards](./standards/sql.md) — PostgreSQL naming, structure, and access control
40
+ - [Development Principles](./standards/principles.md) — Code quality, architecture, security
41
+ - [API Standards](./standards/api.md) — API design and implementation
42
+ - [Naming Conventions](./standards/naming.md) — Naming across TypeScript, SQL, CSS, Git
43
+ - [Testing Approach](./standards/testing.md) — Testing philosophy and patterns
44
+ - [Commit Conventions](./standards/commits.md) — Conventional commits and changelog generation
45
+ - [Documentation Standard](./standards/documentation.md) — Document structure and conventions
46
+ - [Writing](./standards/writing.md) — Voice, tone, and language
47
+
48
+ ## Commands
49
+
50
+ ```bash
51
+ pnpm fix # Fix and lint everything
52
+ pnpm lint # Lint only
53
+ pnpm test # Run tests
54
+ pnpm typecheck # Type check
55
+ ```
56
+
57
+ Run `typecheck` and `lint` before marking a task complete.
@@ -0,0 +1,324 @@
1
+ ---
2
+
3
+ title: "API"
4
+ description: "REST endpoint shape, error handling, security, and performance patterns for Regardio APIs."
5
+ publishedAt: 2026-04-17
6
+ order: 8
7
+ language: "en"
8
+ status: "published"
9
+ kind: "reference"
10
+ area: "dev"
11
+ ---
12
+
13
+ Regardio APIs are resource-oriented, predictable, and consistent about errors. This page catalogues the shape of endpoints, the response envelope, and the patterns for authentication, validation, caching, and testing. The contract a client sees — URL, verb, status, envelope — stays stable; the implementation behind it is free to change.
14
+
15
+ ## Design
16
+
17
+ ### RESTful URLs
18
+
19
+ - One resource per URL
20
+ - Standard HTTP verbs carry the operation
21
+ - Status codes carry the outcome
22
+
23
+ ```text
24
+ GET /api/users List users
25
+ GET /api/users/:id Get a specific user
26
+ POST /api/users Create a user
27
+ PATCH /api/users/:id Update a user
28
+ DELETE /api/users/:id Delete a user
29
+ ```
30
+
31
+ ### Response envelope
32
+
33
+ Every response wraps its payload in a discriminated union so that a client never has to guess whether it received success or failure:
34
+
35
+ ```typescript
36
+ interface SuccessResponse<T> {
37
+ success: true;
38
+ data: T;
39
+ meta?: { page?: number; limit?: number; total?: number };
40
+ }
41
+
42
+ interface ErrorResponse {
43
+ success: false;
44
+ error: { code: string; message: string; details?: unknown };
45
+ }
46
+
47
+ type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
48
+ ```
49
+
50
+ Breaking changes go through versioning; consistency across versions keeps clients portable.
51
+
52
+ ## Errors
53
+
54
+ ### Categories
55
+
56
+ ```typescript
57
+ enum ApiErrorType {
58
+ VALIDATION = 'validation',
59
+ AUTHENTICATION = 'authentication',
60
+ PERMISSION = 'permission',
61
+ NOT_FOUND = 'not_found',
62
+ CONFLICT = 'conflict',
63
+ RATE_LIMIT = 'rate_limit',
64
+ SERVER = 'server',
65
+ }
66
+
67
+ class ApiError extends Error {
68
+ constructor(
69
+ message: string,
70
+ public type: ApiErrorType,
71
+ public code: string,
72
+ public statusCode: number,
73
+ public details?: unknown,
74
+ ) {
75
+ super(message);
76
+ this.name = 'ApiError';
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### Status codes
82
+
83
+ | Code | Use |
84
+ |------|-----|
85
+ | 200 | Successful GET, PATCH, DELETE |
86
+ | 201 | Successful POST |
87
+ | 400 | Invalid request |
88
+ | 401 | Missing or invalid authentication |
89
+ | 403 | Insufficient permissions |
90
+ | 404 | Resource not found |
91
+ | 409 | Resource conflict |
92
+ | 422 | Validation failure |
93
+ | 429 | Rate limit exceeded |
94
+ | 500 | Server error |
95
+
96
+ ### Error payload
97
+
98
+ ```json
99
+ {
100
+ "success": false,
101
+ "error": {
102
+ "code": "VALIDATION_ERROR",
103
+ "message": "Invalid input data",
104
+ "details": { "fields": { "email": "Invalid email format" } }
105
+ }
106
+ }
107
+ ```
108
+
109
+ ### Client handling
110
+
111
+ ```typescript
112
+ async function fetchUser(id: string): Promise<User> {
113
+ const response = await fetch(`/api/users/${id}`);
114
+ const result: ApiResponse<User> = await response.json();
115
+
116
+ if (!result.success) {
117
+ throw new ApiError(
118
+ result.error.message,
119
+ mapErrorCode(result.error.code),
120
+ result.error.code,
121
+ response.status,
122
+ );
123
+ }
124
+
125
+ return result.data;
126
+ }
127
+ ```
128
+
129
+ ## Security
130
+
131
+ ### Authentication
132
+
133
+ - Token-based (JWT or equivalent)
134
+ - HTTPS in every environment that sees real traffic
135
+ - Tokens expire; refresh is explicit
136
+
137
+ ```typescript
138
+ interface AuthTokens {
139
+ accessToken: string;
140
+ refreshToken: string;
141
+ expiresAt: number;
142
+ }
143
+ ```
144
+
145
+ ### Authorisation
146
+
147
+ - Minimum necessary permissions
148
+ - Role-based access for cross-resource actions
149
+ - Ownership verified on every resource-scoped action
150
+ - Server-side validation is the line; the client is untrusted
151
+
152
+ ```typescript
153
+ async function updateUser(id: string, data: Partial<User>): Promise<User> {
154
+ const currentUser = await getCurrentUser();
155
+
156
+ if (currentUser.id !== id && !currentUser.roles.includes('admin')) {
157
+ throw new ApiError('Permission denied', ApiErrorType.PERMISSION, 'PERMISSION_DENIED', 403);
158
+ }
159
+
160
+ const validatedData = validateUserUpdate(data);
161
+ return userRepository.update(id, validatedData);
162
+ }
163
+ ```
164
+
165
+ ### Input validation
166
+
167
+ Types, ranges, and formats are validated on the server. A schema library carries the shape so the contract stays single-sourced:
168
+
169
+ ```typescript
170
+ import { z } from 'zod';
171
+
172
+ const UserUpdateSchema = z.object({
173
+ email: z.string().email().optional(),
174
+ displayName: z.string().min(2).max(50).optional(),
175
+ age: z.number().int().min(18).max(120).optional(),
176
+ });
177
+
178
+ function validateUserUpdate(data: unknown): Partial<User> {
179
+ try {
180
+ return UserUpdateSchema.parse(data);
181
+ } catch (error) {
182
+ if (error instanceof z.ZodError) {
183
+ throw new ApiError(
184
+ 'Validation failed',
185
+ ApiErrorType.VALIDATION,
186
+ 'VALIDATION_ERROR',
187
+ 422,
188
+ { fields: error.flatten().fieldErrors },
189
+ );
190
+ }
191
+ throw error;
192
+ }
193
+ }
194
+ ```
195
+
196
+ ## Performance
197
+
198
+ ### Pagination
199
+
200
+ List endpoints paginate; limits are capped so a client cannot ask for the world:
201
+
202
+ ```typescript
203
+ interface ListParams {
204
+ page?: number;
205
+ limit?: number;
206
+ sortBy?: string;
207
+ sortOrder?: 'asc' | 'desc';
208
+ }
209
+
210
+ async function listUsers(params: ListParams): Promise<ApiResponse<User[]>> {
211
+ const page = params.page ?? 1;
212
+ const limit = Math.min(params.limit ?? 20, 100);
213
+ const offset = (page - 1) * limit;
214
+
215
+ const [users, total] = await Promise.all([
216
+ userRepository.findMany({ offset, limit, sortBy: params.sortBy, sortOrder: params.sortOrder }),
217
+ userRepository.count(),
218
+ ]);
219
+
220
+ return {
221
+ success: true,
222
+ data: users,
223
+ meta: { page, limit, total, totalPages: Math.ceil(total / limit) },
224
+ };
225
+ }
226
+ ```
227
+
228
+ ### Caching and rate limiting
229
+
230
+ - `Cache-Control` and ETags where the resource tolerates it
231
+ - Rate limits protect against runaway clients and scraped keys
232
+
233
+ ```typescript
234
+ app.get('/api/users/:id', async (req, res) => {
235
+ const user = await userRepository.findById(req.params.id);
236
+ if (!user) {
237
+ return res.status(404).json({
238
+ success: false,
239
+ error: { code: 'NOT_FOUND', message: 'User not found' },
240
+ });
241
+ }
242
+ res.set('Cache-Control', 'private, max-age=300');
243
+ res.json({ success: true, data: user });
244
+ });
245
+
246
+ const apiLimiter = rateLimit({
247
+ windowMs: 15 * 60 * 1000,
248
+ max: 100,
249
+ message: { success: false, error: { code: 'RATE_LIMIT_EXCEEDED', message: 'Too many requests' } },
250
+ });
251
+ app.use('/api/', apiLimiter);
252
+ ```
253
+
254
+ ## Documentation
255
+
256
+ Each endpoint carries:
257
+
258
+ - Purpose and authentication requirement
259
+ - Parameters and response shape
260
+ - Error codes that can arise
261
+ - A request/response example
262
+
263
+ ```typescript
264
+ /**
265
+ * Update a user profile.
266
+ * @route PATCH /api/users/:id
267
+ * @auth Required
268
+ * @param id User ID
269
+ * @returns Updated user
270
+ * @throws 401 UNAUTHORIZED
271
+ * @throws 403 PERMISSION_DENIED
272
+ * @throws 422 VALIDATION_ERROR
273
+ */
274
+ ```
275
+
276
+ For large APIs, OpenAPI/Swagger carries the same contract in a form tooling can consume.
277
+
278
+ ## Testing
279
+
280
+ - **Unit tests** — individual handlers and helpers
281
+ - **Integration tests** — endpoints against a real database
282
+ - **Contract tests** — request/response shape held to the documented contract
283
+
284
+ ```typescript
285
+ describe('User API', () => {
286
+ it('updates user profile successfully', async () => {
287
+ const user = await createTestUser();
288
+ const token = await generateAuthToken(user);
289
+
290
+ const response = await request(app)
291
+ .patch(`/api/users/${user.id}`)
292
+ .set('Authorization', `Bearer ${token}`)
293
+ .send({ displayName: 'Updated Name' });
294
+
295
+ expect(response.status).toBe(200);
296
+ expect(response.body.data.displayName).toBe('Updated Name');
297
+ });
298
+
299
+ it('returns 403 when updating another user', async () => {
300
+ const user1 = await createTestUser();
301
+ const user2 = await createTestUser();
302
+ const token = await generateAuthToken(user1);
303
+
304
+ const response = await request(app)
305
+ .patch(`/api/users/${user2.id}`)
306
+ .set('Authorization', `Bearer ${token}`)
307
+ .send({ displayName: 'Hacked' });
308
+
309
+ expect(response.status).toBe(403);
310
+ expect(response.body.error.code).toBe('PERMISSION_DENIED');
311
+ });
312
+ });
313
+ ```
314
+
315
+ ## Related
316
+
317
+ - [React](./react.md) — Patterns for the clients that consume the API
318
+ - [SQL](./sql.md) — Naming, structure, and access on the database side
319
+ - [Testing](./testing.md) — Testing philosophy and layers
320
+ - [Principles](./principles.md) — Shared principles
321
+
322
+ ---
323
+
324
+ **License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio
@@ -0,0 +1,144 @@
1
+ ---
2
+
3
+ title: "Coding"
4
+ description: "TypeScript and general coding patterns Regardio projects hold to across packages and apps."
5
+ publishedAt: 2026-04-17
6
+ order: 5
7
+ language: "en"
8
+ status: "published"
9
+ kind: "reference"
10
+ area: "dev"
11
+ ---
12
+
13
+ Regardio code is TypeScript across the board. What keeps the packages readable to each other is a small set of patterns held consistently: strict types, small modules, small functions, deliberate error handling. This page catalogues those patterns.
14
+
15
+ ## TypeScript
16
+
17
+ ### Type safety
18
+
19
+ - Strict TypeScript is on
20
+ - Data shapes are defined as `interface`; unions and aliases use `type`
21
+ - `any` stays rare and gets a comment explaining why
22
+ - Return types are explicit when inference leaves the reader guessing
23
+
24
+ ### Modules and exports
25
+
26
+ - One responsibility per module
27
+ - No barrel files; `package.json` `exports` names the public surface
28
+ - Internal helpers stay internal, even when they look generally useful
29
+
30
+ ### Function design
31
+
32
+ - Small, focused functions
33
+ - Parameters and non-obvious return types are typed explicitly
34
+
35
+ ```typescript
36
+ interface UserProfile {
37
+ id: string;
38
+ displayName: string;
39
+ createdAt: Date;
40
+ }
41
+
42
+ async function fetchUserProfile(userId: string): Promise<UserProfile> {
43
+ const response = await api.get(`/users/${userId}`);
44
+ return response.data;
45
+ }
46
+ ```
47
+
48
+ ## React
49
+
50
+ ### Components
51
+
52
+ - Functional components with hooks
53
+ - One responsibility per component
54
+ - Explicit props interfaces
55
+ - Composition over inheritance
56
+
57
+ ### Hooks
58
+
59
+ - Dependencies declared in full for `useEffect`, `useMemo`, `useCallback`
60
+ - Reusable logic extracts into custom hooks (`use` prefix)
61
+ - Subscriptions, timers, and listeners are torn down in cleanup
62
+ - `useEffect` reads as a code smell; most cases have a better form elsewhere
63
+
64
+ ### State
65
+
66
+ - Local state stays close to where it is used
67
+ - Related state collapses into one object or a `useReducer`
68
+ - Server state lives in a query layer, not in `useState`
69
+
70
+ ```typescript
71
+ interface ButtonProps {
72
+ variant: 'primary' | 'secondary';
73
+ isDisabled?: boolean;
74
+ onClick: () => void;
75
+ children: React.ReactNode;
76
+ }
77
+
78
+ function Button({ variant, isDisabled, onClick, children }: ButtonProps) {
79
+ return (
80
+ <button className={`btn btn--${variant}`} disabled={isDisabled} onClick={onClick}>
81
+ {children}
82
+ </button>
83
+ );
84
+ }
85
+ ```
86
+
87
+ See [React](./react.md) for the longer form.
88
+
89
+ ## General
90
+
91
+ ### Comments carry the *why*
92
+
93
+ A comment that restates the next line gets deleted. A comment that names the reason behind a non-obvious choice stays.
94
+
95
+ ```typescript
96
+ // Reset to 1-based index for display
97
+ counter += 1;
98
+ ```
99
+
100
+ ### Errors are designed, not caught and dropped
101
+
102
+ The paths that fail are known when the function is written. Result types are preferred at API boundaries; thrown errors inside a module where the flow is clearer. No `catch` block silently swallows.
103
+
104
+ ```typescript
105
+ try {
106
+ const result = await riskyOperation();
107
+ return { success: true, data: result };
108
+ } catch (error) {
109
+ logger.error('Operation failed', { error });
110
+ return { success: false, error: 'Operation failed' };
111
+ }
112
+ ```
113
+
114
+ ### Inference where it reads, explicit where it doesn't
115
+
116
+ ```typescript
117
+ const names = ['Alice', 'Bob']; // inferred as string[]
118
+ const config: AppConfig = loadConfig(); // explicit where the type isn't obvious
119
+ ```
120
+
121
+ ### Exceptions leave a reason
122
+
123
+ Lint suppressions and type escapes carry a comment:
124
+
125
+ ```typescript
126
+ // biome-ignore lint/complexity/noForEach: forEach is clearer for side effects here
127
+ items.forEach(sendNotification);
128
+
129
+ // @ts-expect-error: library types are incorrect for this overload
130
+ const result = legacyLib.process(data);
131
+ ```
132
+
133
+ An unjustified suppression is a regression.
134
+
135
+ ## Related
136
+
137
+ - [Principles](./principles.md) — Shared principles the patterns build on
138
+ - [React](./react.md) — Component, hook, and state patterns
139
+ - [Naming](./naming.md) — Names across languages
140
+ - [Testing](./testing.md) — Testing philosophy
141
+
142
+ ---
143
+
144
+ **License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio
@@ -0,0 +1,111 @@
1
+ ---
2
+
3
+ title: "Commits"
4
+ description: "Conventional Commits format Regardio projects hold to, so history reads and changelogs generate."
5
+ publishedAt: 2026-04-17
6
+ order: 10
7
+ language: "en"
8
+ status: "published"
9
+ kind: "reference"
10
+ area: "dev"
11
+ ---
12
+
13
+ Commit subjects feed the changelog the outside world reads, and the git history is what a future contributor reaches for when a line of code raises a question. Short, imperative subjects with a type and an optional scope keep both useful.
14
+
15
+ ## Format
16
+
17
+ ```text
18
+ <type>(<scope>): <subject>
19
+ [optional body]
20
+ [optional footer]
21
+ ```
22
+
23
+ - **type** — category of change (required)
24
+ - **scope** — area affected (optional)
25
+ - **subject** — imperative mood, up to 100 characters (required)
26
+
27
+ ## Types
28
+
29
+ | Type | Description | Changelog |
30
+ |------|-------------|-----------|
31
+ | `feat` | New feature | Features |
32
+ | `fix` | Bug fix | Bug Fixes |
33
+ | `docs` | Documentation only | — |
34
+ | `style` | Formatting | — |
35
+ | `refactor` | Code change with no fix or feature | — |
36
+ | `perf` | Performance improvement | Performance |
37
+ | `test` | Tests | — |
38
+ | `build` | Build or dependency change | — |
39
+ | `ci` | CI configuration | — |
40
+ | `chore` | Other changes | — |
41
+ | `BREAKING CHANGE` | Breaking API change | Breaking Changes |
42
+
43
+ ## Examples
44
+
45
+ ```bash
46
+ # Simple
47
+ feat: add user authentication
48
+ fix: resolve login redirect loop
49
+
50
+ # With scope
51
+ feat(auth): implement OAuth2 flow
52
+ fix(api): handle null response gracefully
53
+
54
+ # With body
55
+ fix: prevent race condition in data sync
56
+
57
+ The previous implementation could cause data corruption.
58
+ A mutex now guards the sequential path.
59
+
60
+ Closes #123
61
+
62
+ # Breaking change
63
+ feat!: redesign authentication API
64
+
65
+ BREAKING CHANGE: auth.login() now returns a Promise.
66
+ Update call sites to use async/await.
67
+ ```
68
+
69
+ ## Practices
70
+
71
+ ### Imperative mood
72
+
73
+ ```bash
74
+ # Good
75
+ feat: add validation for email field
76
+
77
+ # Not good
78
+ feat: added validation for email field
79
+ ```
80
+
81
+ ### Atomic commits
82
+
83
+ Each commit carries one logical change. When a branch has done several things, the history reflects them as separate commits.
84
+
85
+ ### References to issues
86
+
87
+ ```bash
88
+ fix: correct calculation of total price
89
+
90
+ Closes #456
91
+ Refs #123, #789
92
+ ```
93
+
94
+ ## Enforcement
95
+
96
+ Commit messages are validated by [Commitlint](../tools/commitlint.md) through git hooks.
97
+
98
+ ## Changelog generation
99
+
100
+ Changelogs are generated from [Changesets](../tools/releases.md) — one-line descriptions authors write with `pnpm changeset` alongside their change. `ship-production` consumes pending changesets at ship time and writes them into each package's `CHANGELOG.md`. The changeset description is what users read, so write it for that reader from the start.
101
+
102
+ ## Related
103
+
104
+ - [Commitlint](../tools/commitlint.md) — Commit message validation
105
+ - [Releases](../tools/releases.md) — Release workflow that consumes the commits
106
+ - [Naming](./naming.md) — Branch and package naming
107
+ - [Conventional Commits](https://www.conventionalcommits.org/) — The spec this follows
108
+
109
+ ---
110
+
111
+ **License**: [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) © Regardio