@mind-fold/open-flow 0.1.17 → 0.2.2

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 (40) hide show
  1. package/dist/configurators/templates.d.ts.map +1 -1
  2. package/dist/configurators/templates.js +17 -6
  3. package/dist/configurators/templates.js.map +1 -1
  4. package/dist/configurators/workflow.d.ts.map +1 -1
  5. package/dist/configurators/workflow.js +82 -6
  6. package/dist/configurators/workflow.js.map +1 -1
  7. package/dist/templates/commands/break-loop.txt +107 -0
  8. package/dist/templates/commands/check-cross-layer.txt +153 -0
  9. package/dist/templates/commands/finish-work.txt +129 -0
  10. package/dist/templates/commands/index.d.ts +9 -5
  11. package/dist/templates/commands/index.d.ts.map +1 -1
  12. package/dist/templates/commands/index.js +16 -5
  13. package/dist/templates/commands/index.js.map +1 -1
  14. package/dist/templates/commands/init-agent.txt +100 -9
  15. package/dist/templates/commands/sync-from-runtime.txt +140 -0
  16. package/dist/templates/markdown/flow.md.txt +96 -84
  17. package/dist/templates/markdown/index.d.ts +21 -4
  18. package/dist/templates/markdown/index.d.ts.map +1 -1
  19. package/dist/templates/markdown/index.js +27 -4
  20. package/dist/templates/markdown/index.js.map +1 -1
  21. package/dist/templates/markdown/structure/backend/database-guidelines.md.txt +247 -0
  22. package/dist/templates/markdown/structure/backend/directory-structure.md.txt +153 -0
  23. package/dist/templates/markdown/structure/backend/error-handling.md.txt +257 -0
  24. package/dist/templates/markdown/structure/backend/index.md.txt +88 -0
  25. package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +212 -0
  26. package/dist/templates/markdown/structure/backend/quality-guidelines.md.txt +219 -0
  27. package/dist/templates/markdown/structure/backend/type-safety.md.txt +192 -0
  28. package/dist/templates/markdown/structure/flows/code-reuse-thinking-guide.md.txt +343 -0
  29. package/dist/templates/markdown/structure/flows/cross-layer-thinking-guide.md.txt +283 -0
  30. package/dist/templates/markdown/structure/flows/index.md.txt +133 -0
  31. package/dist/templates/markdown/structure/flows/pre-implementation-checklist.md.txt +182 -0
  32. package/dist/templates/markdown/structure/flows/spec-flow-template.md.txt +145 -0
  33. package/dist/templates/markdown/structure/frontend/component-guidelines.md.txt +335 -0
  34. package/dist/templates/markdown/structure/frontend/directory-structure.md.txt +172 -0
  35. package/dist/templates/markdown/structure/frontend/hook-guidelines.md.txt +287 -0
  36. package/dist/templates/markdown/structure/frontend/index.md.txt +91 -0
  37. package/dist/templates/markdown/structure/frontend/quality-guidelines.md.txt +274 -0
  38. package/dist/templates/markdown/structure/frontend/state-management.md.txt +293 -0
  39. package/dist/templates/markdown/structure/frontend/type-safety.md.txt +275 -0
  40. package/package.json +2 -2
@@ -0,0 +1,247 @@
1
+ # Database Guidelines
2
+
3
+ > ORM patterns, batch operations, and query optimization
4
+
5
+ ---
6
+
7
+ ## Core Rules
8
+
9
+ 1. **No await in loops** - Use batch operations
10
+ 2. **Use transactions** - For multi-table operations
11
+ 3. **Define relations** - Enable relational queries
12
+ 4. **Handle timestamps** - Consistent format across layers
13
+
14
+ ---
15
+
16
+ ## No Await in Loops (N+1 Problem)
17
+
18
+ The N+1 query problem is one of the most common performance issues.
19
+
20
+ ### Problem
21
+
22
+ ```typescript
23
+ // ❌ BAD: N+1 queries (1 + N database calls)
24
+ const users = await db.select().from(users).all();
25
+ for (const user of users) {
26
+ const posts = await db.select().from(posts).where(eq(posts.userId, user.id)).all();
27
+ user.posts = posts;
28
+ }
29
+ ```
30
+
31
+ ### Solution 1: Relational Queries
32
+
33
+ ```typescript
34
+ // ✅ GOOD: Single query with JOIN
35
+ const usersWithPosts = await db.query.users.findMany({
36
+ with: {
37
+ posts: true,
38
+ },
39
+ });
40
+ ```
41
+
42
+ ### Solution 2: Batch Lookup with inArray
43
+
44
+ ```typescript
45
+ // ✅ GOOD: Two queries total (1 for users, 1 for all posts)
46
+ import { inArray } from 'drizzle-orm';
47
+
48
+ const users = await db.select().from(users).all();
49
+ const userIds = users.map(u => u.id);
50
+
51
+ const allPosts = await db
52
+ .select()
53
+ .from(posts)
54
+ .where(inArray(posts.userId, userIds))
55
+ .all();
56
+
57
+ // Group in memory
58
+ const postsByUser = groupBy(allPosts, 'userId');
59
+ ```
60
+
61
+ ### Solution 3: Promise.all (Use Carefully)
62
+
63
+ ```typescript
64
+ // ⚠️ OK for small N, but watch connection limits
65
+ const results = await Promise.all(
66
+ ids.slice(0, 10).map(id =>
67
+ db.query.users.findFirst({ where: eq(users.id, id) })
68
+ )
69
+ );
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Batch Operations
75
+
76
+ ### Bulk Insert
77
+
78
+ ```typescript
79
+ // Insert multiple rows in one statement
80
+ await db.insert(users).values([
81
+ { id: '1', email: 'a@example.com', name: 'Alice' },
82
+ { id: '2', email: 'b@example.com', name: 'Bob' },
83
+ ]).run();
84
+ ```
85
+
86
+ ### Upsert (Insert or Update)
87
+
88
+ ```typescript
89
+ await db.insert(users)
90
+ .values(userData)
91
+ .onConflictDoUpdate({
92
+ target: users.id,
93
+ set: {
94
+ name: userData.name,
95
+ updatedAt: new Date(),
96
+ },
97
+ })
98
+ .run();
99
+ ```
100
+
101
+ ### Bulk Update with inArray
102
+
103
+ ```typescript
104
+ // Update multiple rows matching condition
105
+ await db.update(users)
106
+ .set({ status: 'archived' })
107
+ .where(inArray(users.id, idsToArchive))
108
+ .run();
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Transactions
114
+
115
+ Use transactions for operations that must be atomic.
116
+
117
+ ```typescript
118
+ // All-or-nothing: either all succeed or all rollback
119
+ const result = db.transaction((tx) => {
120
+ // Create user
121
+ const user = tx.insert(users).values({
122
+ id: userId,
123
+ email: input.email,
124
+ }).returning().get();
125
+
126
+ // Create default settings
127
+ tx.insert(userSettings).values({
128
+ userId: user.id,
129
+ theme: 'light',
130
+ }).run();
131
+
132
+ // Create audit log
133
+ tx.insert(auditLogs).values({
134
+ action: 'user_created',
135
+ entityId: user.id,
136
+ }).run();
137
+
138
+ return user;
139
+ });
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Timestamp Handling
145
+
146
+ ### Use Milliseconds
147
+
148
+ JavaScript `Date.now()` returns milliseconds. Store timestamps consistently.
149
+
150
+ ```typescript
151
+ // Schema definition
152
+ export const users = sqliteTable('users', {
153
+ // ...
154
+ createdAt: integer('created_at', { mode: 'timestamp_ms' })
155
+ .notNull()
156
+ .default(sql`(unixepoch() * 1000)`),
157
+ updatedAt: integer('updated_at', { mode: 'timestamp_ms' })
158
+ .notNull()
159
+ .default(sql`(unixepoch() * 1000)`)
160
+ .$onUpdate(() => new Date()),
161
+ });
162
+ ```
163
+
164
+ ### Common Pitfall
165
+
166
+ ```typescript
167
+ // ❌ BAD: Mixing seconds and milliseconds
168
+ const timestamp = Math.floor(Date.now() / 1000); // Seconds
169
+ new Date(timestamp); // Wrong! Expects milliseconds
170
+
171
+ // ✅ GOOD: Consistent milliseconds
172
+ const timestamp = Date.now(); // Milliseconds
173
+ new Date(timestamp); // Correct
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Query Patterns
179
+
180
+ ### Pagination
181
+
182
+ ```typescript
183
+ async function listUsers(page: number, pageSize: number) {
184
+ const offset = (page - 1) * pageSize;
185
+
186
+ const [users, countResult] = await Promise.all([
187
+ db.select()
188
+ .from(users)
189
+ .limit(pageSize)
190
+ .offset(offset)
191
+ .all(),
192
+ db.select({ count: count() })
193
+ .from(users)
194
+ .get(),
195
+ ]);
196
+
197
+ return {
198
+ data: users,
199
+ total: countResult?.count ?? 0,
200
+ page,
201
+ pageSize,
202
+ };
203
+ }
204
+ ```
205
+
206
+ ### Soft Delete
207
+
208
+ ```typescript
209
+ // Schema with soft delete
210
+ export const users = sqliteTable('users', {
211
+ // ...
212
+ isDeleted: integer('is_deleted', { mode: 'boolean' }).notNull().default(false),
213
+ deletedAt: integer('deleted_at', { mode: 'timestamp_ms' }),
214
+ });
215
+
216
+ // Query excludes deleted by default
217
+ const activeUsers = await db
218
+ .select()
219
+ .from(users)
220
+ .where(eq(users.isDeleted, false))
221
+ .all();
222
+
223
+ // Soft delete
224
+ await db.update(users)
225
+ .set({
226
+ isDeleted: true,
227
+ deletedAt: new Date()
228
+ })
229
+ .where(eq(users.id, userId))
230
+ .run();
231
+ ```
232
+
233
+ ---
234
+
235
+ ## Summary
236
+
237
+ | Rule | Description |
238
+ |------|-------------|
239
+ | No await in loops | Use `with:`, `inArray`, or batch queries |
240
+ | Use transactions | For atomic multi-table operations |
241
+ | Millisecond timestamps | Match JavaScript Date behavior |
242
+ | Soft delete | Use `isDeleted` flag, not hard delete |
243
+ | Pagination | Always limit results for list endpoints |
244
+
245
+ ---
246
+
247
+ **Language**: All documentation must be written in **English**.
@@ -0,0 +1,153 @@
1
+ # Directory Structure
2
+
3
+ > Module organization and file layout for backend development
4
+
5
+ ---
6
+
7
+ ## Standard Layout
8
+
9
+ ```
10
+ server/
11
+ ├── db/ # Database layer
12
+ │ ├── client.ts # Database client initialization
13
+ │ ├── schema.ts # Table definitions
14
+ │ └── migrations/ # Migration files
15
+
16
+ ├── lib/ # Shared utilities
17
+ │ ├── logger.ts # Logger setup
18
+ │ ├── errors.ts # Custom error classes
19
+ │ └── utils.ts # Helper functions
20
+
21
+ ├── middleware/ # Middleware
22
+ │ ├── auth.ts # Authentication
23
+ │ ├── error-handler.ts # Error handling
24
+ │ └── request-context.ts # Request context
25
+
26
+ ├── routes/ # API routes (domain-driven)
27
+ │ └── {domain}/
28
+ │ ├── types.ts # Zod schemas + TypeScript types
29
+ │ ├── router.ts # Route definitions
30
+ │ ├── procedures/ # One file per endpoint
31
+ │ │ ├── list.ts
32
+ │ │ ├── get.ts
33
+ │ │ ├── create.ts
34
+ │ │ ├── update.ts
35
+ │ │ └── delete.ts
36
+ │ └── lib/ # Domain-specific logic
37
+
38
+ └── types.ts # Shared types (AppContext, etc.)
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Module Structure
44
+
45
+ Each domain module follows this pattern:
46
+
47
+ ### types.ts - Schema Definitions
48
+
49
+ ```typescript
50
+ import { z } from 'zod';
51
+
52
+ // Input schemas
53
+ export const createUserInput = z.object({
54
+ email: z.string().email(),
55
+ name: z.string().min(1),
56
+ });
57
+
58
+ export const updateUserInput = z.object({
59
+ name: z.string().min(1).optional(),
60
+ });
61
+
62
+ // Output schemas
63
+ export const userOutput = z.object({
64
+ id: z.string(),
65
+ email: z.string(),
66
+ name: z.string(),
67
+ createdAt: z.date(),
68
+ });
69
+
70
+ // Infer types from schemas
71
+ export type CreateUserInput = z.infer<typeof createUserInput>;
72
+ export type UpdateUserInput = z.infer<typeof updateUserInput>;
73
+ export type UserOutput = z.infer<typeof userOutput>;
74
+ ```
75
+
76
+ ### router.ts - Route Definitions
77
+
78
+ ```typescript
79
+ import { Hono } from 'hono';
80
+ import { zValidator } from '@hono/zod-validator';
81
+ import { createUserInput, updateUserInput } from './types';
82
+ import { createUser } from './procedures/create';
83
+ import { getUser } from './procedures/get';
84
+ import { listUsers } from './procedures/list';
85
+
86
+ const app = new Hono();
87
+
88
+ app.get('/', listUsers);
89
+ app.get('/:id', getUser);
90
+ app.post('/', zValidator('json', createUserInput), createUser);
91
+ app.patch('/:id', zValidator('json', updateUserInput), updateUser);
92
+
93
+ export default app;
94
+ ```
95
+
96
+ ### procedures/*.ts - Business Logic
97
+
98
+ ```typescript
99
+ // procedures/create.ts
100
+ import type { Context } from 'hono';
101
+ import { db } from '@/db/client';
102
+ import { users } from '@/db/schema';
103
+ import type { CreateUserInput } from '../types';
104
+
105
+ export async function createUser(c: Context) {
106
+ const input = c.req.valid('json') as CreateUserInput;
107
+ const logger = c.get('logger');
108
+
109
+ logger.info('creating_user', { email: input.email });
110
+
111
+ const user = await db.insert(users).values({
112
+ id: generateId(),
113
+ email: input.email,
114
+ name: input.name,
115
+ }).returning().get();
116
+
117
+ return c.json(user);
118
+ }
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Naming Conventions
124
+
125
+ | Type | Convention | Example |
126
+ |------|------------|---------|
127
+ | Files | kebab-case | `user-service.ts` |
128
+ | Directories | kebab-case | `user-management/` |
129
+ | Types | PascalCase | `UserOutput` |
130
+ | Functions | camelCase | `createUser` |
131
+ | Constants | SCREAMING_SNAKE | `MAX_RETRY_COUNT` |
132
+
133
+ ---
134
+
135
+ ## Best Practices
136
+
137
+ ### DO
138
+
139
+ - Keep procedures focused on single responsibility
140
+ - Put shared logic in `lib/` directory
141
+ - Use descriptive file names (`create-with-team.ts` not `create2.ts`)
142
+ - Group related functionality in domain modules
143
+
144
+ ### DON'T
145
+
146
+ - Mix multiple domains in one module
147
+ - Put business logic in router files
148
+ - Create deeply nested directory structures
149
+ - Use generic names like `utils.ts` in domain modules
150
+
151
+ ---
152
+
153
+ **Language**: All documentation must be written in **English**.
@@ -0,0 +1,257 @@
1
+ # Error Handling
2
+
3
+ > Error types, handling strategies, and user-facing messages
4
+
5
+ ---
6
+
7
+ ## Error Types
8
+
9
+ ### Application Errors
10
+
11
+ Define custom error classes for different error categories:
12
+
13
+ ```typescript
14
+ // lib/errors.ts
15
+ export class AppError extends Error {
16
+ constructor(
17
+ message: string,
18
+ public code: string,
19
+ public statusCode: number = 500,
20
+ public details?: Record<string, unknown>
21
+ ) {
22
+ super(message);
23
+ this.name = 'AppError';
24
+ }
25
+ }
26
+
27
+ export class NotFoundError extends AppError {
28
+ constructor(message: string, details?: Record<string, unknown>) {
29
+ super(message, 'NOT_FOUND', 404, details);
30
+ this.name = 'NotFoundError';
31
+ }
32
+ }
33
+
34
+ export class ValidationError extends AppError {
35
+ constructor(message: string, details?: Record<string, unknown>) {
36
+ super(message, 'VALIDATION_ERROR', 400, details);
37
+ this.name = 'ValidationError';
38
+ }
39
+ }
40
+
41
+ export class UnauthorizedError extends AppError {
42
+ constructor(message: string = 'Unauthorized') {
43
+ super(message, 'UNAUTHORIZED', 401);
44
+ this.name = 'UnauthorizedError';
45
+ }
46
+ }
47
+
48
+ export class ForbiddenError extends AppError {
49
+ constructor(message: string = 'Forbidden') {
50
+ super(message, 'FORBIDDEN', 403);
51
+ this.name = 'ForbiddenError';
52
+ }
53
+ }
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Error Handling Middleware
59
+
60
+ ```typescript
61
+ // middleware/error-handler.ts
62
+ import type { Context, Next } from 'hono';
63
+ import { AppError } from '@/lib/errors';
64
+
65
+ export async function errorHandler(c: Context, next: Next) {
66
+ try {
67
+ await next();
68
+ } catch (error) {
69
+ const logger = c.get('logger');
70
+
71
+ if (error instanceof AppError) {
72
+ logger.warn('app_error', {
73
+ code: error.code,
74
+ message: error.message,
75
+ details: error.details,
76
+ });
77
+
78
+ return c.json({
79
+ error: {
80
+ code: error.code,
81
+ message: error.message,
82
+ details: error.details,
83
+ },
84
+ }, error.statusCode);
85
+ }
86
+
87
+ // Unexpected errors
88
+ logger.error('unhandled_error', error);
89
+
90
+ return c.json({
91
+ error: {
92
+ code: 'INTERNAL_ERROR',
93
+ message: 'An unexpected error occurred',
94
+ },
95
+ }, 500);
96
+ }
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Error Handling Patterns
103
+
104
+ ### Route Handlers
105
+
106
+ ```typescript
107
+ app.get('/users/:id', async (c) => {
108
+ const userId = c.req.param('id');
109
+
110
+ const user = await db.query.users.findFirst({
111
+ where: eq(users.id, userId),
112
+ });
113
+
114
+ if (!user) {
115
+ throw new NotFoundError(`User ${userId} not found`);
116
+ }
117
+
118
+ return c.json(user);
119
+ });
120
+ ```
121
+
122
+ ### Service Layer
123
+
124
+ ```typescript
125
+ async function transferFunds(fromId: string, toId: string, amount: number) {
126
+ const fromAccount = await getAccount(fromId);
127
+ if (!fromAccount) {
128
+ throw new NotFoundError('Source account not found');
129
+ }
130
+
131
+ if (fromAccount.balance < amount) {
132
+ throw new ValidationError('Insufficient funds', {
133
+ available: fromAccount.balance,
134
+ requested: amount,
135
+ });
136
+ }
137
+
138
+ // Proceed with transfer...
139
+ }
140
+ ```
141
+
142
+ ### External API Calls
143
+
144
+ ```typescript
145
+ async function fetchExternalData(id: string) {
146
+ try {
147
+ const response = await fetch(`https://api.example.com/data/${id}`);
148
+
149
+ if (!response.ok) {
150
+ if (response.status === 404) {
151
+ throw new NotFoundError('External resource not found');
152
+ }
153
+ throw new AppError(
154
+ 'External API error',
155
+ 'EXTERNAL_API_ERROR',
156
+ 502,
157
+ { status: response.status }
158
+ );
159
+ }
160
+
161
+ return await response.json();
162
+ } catch (error) {
163
+ if (error instanceof AppError) {
164
+ throw error;
165
+ }
166
+ throw new AppError(
167
+ 'Failed to fetch external data',
168
+ 'EXTERNAL_API_ERROR',
169
+ 502,
170
+ { originalError: String(error) }
171
+ );
172
+ }
173
+ }
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Validation Errors
179
+
180
+ ### Zod Integration
181
+
182
+ ```typescript
183
+ import { z, ZodError } from 'zod';
184
+
185
+ app.post('/users', async (c) => {
186
+ try {
187
+ const input = createUserSchema.parse(await c.req.json());
188
+ // Process valid input...
189
+ } catch (error) {
190
+ if (error instanceof ZodError) {
191
+ throw new ValidationError('Invalid input', {
192
+ errors: error.errors.map(e => ({
193
+ path: e.path.join('.'),
194
+ message: e.message,
195
+ })),
196
+ });
197
+ }
198
+ throw error;
199
+ }
200
+ });
201
+ ```
202
+
203
+ ### Response Format
204
+
205
+ ```json
206
+ {
207
+ "error": {
208
+ "code": "VALIDATION_ERROR",
209
+ "message": "Invalid input",
210
+ "details": {
211
+ "errors": [
212
+ { "path": "email", "message": "Invalid email format" },
213
+ { "path": "age", "message": "Must be a positive number" }
214
+ ]
215
+ }
216
+ }
217
+ }
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Error Codes
223
+
224
+ Maintain a consistent set of error codes:
225
+
226
+ | Code | HTTP Status | Description |
227
+ |------|-------------|-------------|
228
+ | `NOT_FOUND` | 404 | Resource not found |
229
+ | `VALIDATION_ERROR` | 400 | Invalid input |
230
+ | `UNAUTHORIZED` | 401 | Authentication required |
231
+ | `FORBIDDEN` | 403 | Permission denied |
232
+ | `CONFLICT` | 409 | Resource conflict (duplicate) |
233
+ | `RATE_LIMITED` | 429 | Too many requests |
234
+ | `INTERNAL_ERROR` | 500 | Unexpected server error |
235
+ | `EXTERNAL_API_ERROR` | 502 | External service failure |
236
+
237
+ ---
238
+
239
+ ## Best Practices
240
+
241
+ ### DO
242
+
243
+ - Use specific error types for different scenarios
244
+ - Include helpful details for debugging
245
+ - Log errors with context
246
+ - Return consistent error response format
247
+
248
+ ### DON'T
249
+
250
+ - Expose internal error details to clients
251
+ - Use generic error messages
252
+ - Swallow errors silently
253
+ - Return stack traces in production
254
+
255
+ ---
256
+
257
+ **Language**: All documentation must be written in **English**.