opencastle 0.32.5 → 0.32.6
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 +13 -3
- package/bin/cli.mjs +2 -0
- package/package.json +1 -1
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/orchestrator/agents/api-designer.agent.md +25 -34
- package/src/orchestrator/agents/architect.agent.md +40 -84
- package/src/orchestrator/agents/content-engineer.agent.md +29 -31
- package/src/orchestrator/agents/copywriter.agent.md +35 -60
- package/src/orchestrator/agents/data-expert.agent.md +24 -30
- package/src/orchestrator/agents/database-engineer.agent.md +26 -31
- package/src/orchestrator/agents/developer.agent.md +32 -34
- package/src/orchestrator/agents/devops-expert.agent.md +31 -26
- package/src/orchestrator/agents/documentation-writer.agent.md +29 -29
- package/src/orchestrator/agents/performance-expert.agent.md +36 -33
- package/src/orchestrator/agents/release-manager.agent.md +25 -34
- package/src/orchestrator/agents/researcher.agent.md +41 -95
- package/src/orchestrator/agents/reviewer.agent.md +24 -34
- package/src/orchestrator/agents/security-expert.agent.md +35 -39
- package/src/orchestrator/agents/seo-specialist.agent.md +25 -32
- package/src/orchestrator/agents/session-guard.agent.md +20 -79
- package/src/orchestrator/agents/team-lead.agent.md +50 -254
- package/src/orchestrator/agents/testing-expert.agent.md +37 -49
- package/src/orchestrator/agents/ui-ux-expert.agent.md +33 -39
- package/src/orchestrator/customizations/KNOWN-ISSUES.md +0 -1
- package/src/orchestrator/customizations/agents/skill-matrix.json +12 -0
- package/src/orchestrator/instructions/general.instructions.md +24 -84
- package/src/orchestrator/plugins/astro/SKILL.md +23 -179
- package/src/orchestrator/plugins/convex/SKILL.md +38 -12
- package/src/orchestrator/plugins/netlify/SKILL.md +17 -13
- package/src/orchestrator/plugins/nextjs/SKILL.md +55 -261
- package/src/orchestrator/plugins/nx/SKILL.md +20 -72
- package/src/orchestrator/plugins/playwright/SKILL.md +5 -17
- package/src/orchestrator/plugins/slack/SKILL.md +28 -190
- package/src/orchestrator/plugins/teams/SKILL.md +10 -140
- package/src/orchestrator/plugins/vitest/SKILL.md +2 -2
- package/src/orchestrator/prompts/bug-fix.prompt.md +25 -63
- package/src/orchestrator/prompts/implement-feature.prompt.md +29 -66
- package/src/orchestrator/prompts/quick-refinement.prompt.md +31 -66
- package/src/orchestrator/skills/accessibility-standards/SKILL.md +50 -105
- package/src/orchestrator/skills/agent-hooks/SKILL.md +60 -110
- package/src/orchestrator/skills/agent-memory/SKILL.md +44 -93
- package/src/orchestrator/skills/api-patterns/SKILL.md +20 -68
- package/src/orchestrator/skills/code-commenting/SKILL.md +49 -101
- package/src/orchestrator/skills/context-map/SKILL.md +47 -88
- package/src/orchestrator/skills/data-engineering/SKILL.md +27 -74
- package/src/orchestrator/skills/decomposition/SKILL.md +50 -98
- package/src/orchestrator/skills/deployment-infrastructure/SKILL.md +44 -107
- package/src/orchestrator/skills/documentation-standards/SKILL.md +28 -89
- package/src/orchestrator/skills/fast-review/SKILL.md +51 -276
- package/src/orchestrator/skills/frontend-design/SKILL.md +53 -163
- package/src/orchestrator/skills/git-workflow/SKILL.md +18 -54
- package/src/orchestrator/skills/memory-merger/SKILL.md +51 -88
- package/src/orchestrator/skills/observability-logging/SKILL.md +29 -75
- package/src/orchestrator/skills/orchestration-protocols/SKILL.md +58 -117
- package/src/orchestrator/skills/panel-majority-vote/SKILL.md +65 -140
- package/src/orchestrator/skills/performance-optimization/SKILL.md +21 -85
- package/src/orchestrator/skills/project-consistency/SKILL.md +62 -281
- package/src/orchestrator/skills/react-development/SKILL.md +38 -86
- package/src/orchestrator/skills/security-hardening/SKILL.md +40 -84
- package/src/orchestrator/skills/self-improvement/SKILL.md +26 -60
- package/src/orchestrator/skills/seo-patterns/SKILL.md +40 -105
- package/src/orchestrator/skills/session-checkpoints/SKILL.md +26 -68
- package/src/orchestrator/skills/team-lead-reference/SKILL.md +66 -206
- package/src/orchestrator/skills/testing-workflow/SKILL.md +42 -112
- package/src/orchestrator/skills/validation-gates/SKILL.md +39 -170
- package/src/orchestrator/snippets/base-output-contract.md +14 -0
- package/src/orchestrator/snippets/discovered-issues-policy.md +15 -0
- package/src/orchestrator/snippets/logging-mandatory.md +11 -0
- package/src/orchestrator/snippets/never-expose-secrets.md +22 -0
|
@@ -3,19 +3,17 @@ name: api-patterns
|
|
|
3
3
|
description: "API design patterns for route handlers, Server Actions, Zod validation, and external API integration. Use when creating API routes, Server Actions, or integrating external services."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
|
|
7
|
-
|
|
8
6
|
# API Patterns
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
Project-specific config: [api-config.md](../../.opencastle/stack/api-config.md).
|
|
11
9
|
|
|
12
10
|
## Architecture
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
| Layer | Use for |
|
|
13
|
+
|-------|---------|
|
|
14
|
+
| **Server Actions** (preferred) | mutations, form submissions, data writes, auth |
|
|
15
|
+
| **Route Handlers** (`route.ts`) | analytics, autocomplete, external integrations |
|
|
16
|
+
| **Proxy layer** | IP rate limiting, fingerprinting, bot detection |
|
|
19
17
|
|
|
20
18
|
## Code Patterns
|
|
21
19
|
|
|
@@ -25,16 +23,11 @@ This project uses **App Router** API patterns (resolve the specific framework vi
|
|
|
25
23
|
// app/api/example/route.ts
|
|
26
24
|
import { NextRequest, NextResponse } from 'next/server';
|
|
27
25
|
import { z } from 'zod';
|
|
28
|
-
|
|
29
26
|
const schema = z.object({ query: z.string().min(1).max(200) });
|
|
30
27
|
|
|
31
28
|
export async function GET(request: NextRequest) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
if (!result.success) {
|
|
35
|
-
return NextResponse.json({ error: 'Invalid input' }, { status: 400 });
|
|
36
|
-
}
|
|
37
|
-
// ... process
|
|
29
|
+
const result = schema.safeParse(Object.fromEntries(request.nextUrl.searchParams));
|
|
30
|
+
if (!result.success) return NextResponse.json({ error: 'Invalid input' }, { status: 400 });
|
|
38
31
|
return NextResponse.json(data);
|
|
39
32
|
}
|
|
40
33
|
```
|
|
@@ -47,62 +40,21 @@ import { createServerClient } from '@libs/auth';
|
|
|
47
40
|
import { revalidatePath } from 'next/cache';
|
|
48
41
|
|
|
49
42
|
export async function submitAction(formData: FormData) {
|
|
50
|
-
const
|
|
51
|
-
const { data: { user } } = await client.auth.getUser();
|
|
43
|
+
const { data: { user } } = await (await createServerClient()).auth.getUser();
|
|
52
44
|
if (!user) return { error: 'Unauthorized' };
|
|
53
|
-
// ... validate and process
|
|
54
45
|
revalidatePath('/places');
|
|
55
46
|
return { success: true };
|
|
56
47
|
}
|
|
57
48
|
```
|
|
58
49
|
|
|
59
|
-
## Design
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
## API Design Principles
|
|
71
|
-
|
|
72
|
-
### Route Architecture
|
|
73
|
-
- RESTful resource naming: `/api/v1/places`, `/api/v1/places/:slug`
|
|
74
|
-
- Use HTTP methods correctly: `GET` (read), `POST` (create), `PATCH` (partial update), `DELETE` (remove)
|
|
75
|
-
- Group related endpoints under a common prefix
|
|
76
|
-
- Keep URLs noun-based, not verb-based (`/api/places` not `/api/getPlaces`)
|
|
77
|
-
|
|
78
|
-
### Request/Response Schemas
|
|
79
|
-
- Define Zod schemas for all request bodies, query params, and responses
|
|
80
|
-
- Use consistent envelope format for responses:
|
|
81
|
-
```json
|
|
82
|
-
{ "data": ..., "meta": { "total": 42, "page": 1 } }
|
|
83
|
-
```
|
|
84
|
-
- Error responses follow a standard shape:
|
|
85
|
-
```json
|
|
86
|
-
{ "error": { "code": "VALIDATION_ERROR", "message": "...", "details": [...] } }
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Error Handling
|
|
90
|
-
- Use appropriate HTTP status codes (400, 401, 403, 404, 422, 429, 500)
|
|
91
|
-
- Return machine-readable error codes alongside human-readable messages
|
|
92
|
-
- Never leak internal errors — sanitize stack traces in production
|
|
93
|
-
- Provide actionable error messages when possible
|
|
94
|
-
|
|
95
|
-
### Pagination & Filtering
|
|
96
|
-
- Cursor-based pagination for large datasets (offset-based as fallback)
|
|
97
|
-
- Consistent query parameter names: `limit`, `cursor`, `sort`, `order`
|
|
98
|
-
- Filter parameters match field names: `?type=brewery&city=prague`
|
|
99
|
-
|
|
100
|
-
### Versioning
|
|
101
|
-
- URL-based versioning: `/api/v1/...`
|
|
102
|
-
- Never break existing contracts — add fields, never remove or rename
|
|
103
|
-
- Deprecation notices in response headers before removal
|
|
104
|
-
|
|
105
|
-
### Rate Limiting & Caching
|
|
106
|
-
- Define rate limits per endpoint sensitivity
|
|
107
|
-
- Set `Cache-Control` headers appropriate to content freshness
|
|
108
|
-
- Use `ETag` / `If-None-Match` for conditional requests where applicable
|
|
50
|
+
## Design Rules
|
|
51
|
+
|
|
52
|
+
- Server Actions for mutations; Route Handlers for external/public endpoints
|
|
53
|
+
- Validate all input with Zod on the server
|
|
54
|
+
- RESTful nouns: `/api/v1/places/:slug`; HTTP methods: `GET` read, `POST` create, `PATCH` update, `DELETE` remove
|
|
55
|
+
- Response envelope: `{ "data": ..., "meta": { "total": 42, "page": 1 } }`
|
|
56
|
+
- Error shape: `{ "error": { "code": "VALIDATION_ERROR", "message": "...", "details": [...] } }`
|
|
57
|
+
- Status codes: 400, 401, 403, 404, 422, 429, 500 — never leak stack traces
|
|
58
|
+
- Pagination: cursor-based preferred; params: `limit`, `cursor`, `sort`, `order`
|
|
59
|
+
- Versioning: `/api/v1/...`; add fields only, never remove/rename; deprecation headers before removal
|
|
60
|
+
- Rate-limit public endpoints; set `Cache-Control` and `ETag`/`If-None-Match` headers
|
|
@@ -3,133 +3,81 @@ name: code-commenting
|
|
|
3
3
|
description: "Guidelines for writing self-explanatory code with minimal comments. Covers when to comment (WHY not WHAT), anti-patterns to avoid, annotation tags, and public API documentation. Use when writing or reviewing code comments."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
# Code Commenting
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**Comment WHY, not WHAT.** Prefer renaming over commenting.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## When to Comment
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
| Situation | Action |
|
|
13
|
+
|-----------|--------|
|
|
14
|
+
| Self-explanatory code | No comment |
|
|
15
|
+
| Bad name is the real problem | Rename instead |
|
|
16
|
+
| Complex business logic / non-obvious algorithm | Comment WHY |
|
|
17
|
+
| Regex, API constraints, gotchas | Comment WHY |
|
|
18
|
+
| Public API function/method | JSDoc |
|
|
19
|
+
| Magic number / config constant | Inline rationale |
|
|
14
20
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
Before writing a comment, ask:
|
|
18
|
-
|
|
19
|
-
1. **Is the code self-explanatory?** → No comment needed
|
|
20
|
-
2. **Would a better variable/function name eliminate the need?** → Refactor instead
|
|
21
|
-
3. **Does this explain WHY, not WHAT?** → Good comment
|
|
22
|
-
4. **Will this help future maintainers?** → Good comment
|
|
23
|
-
|
|
24
|
-
## Comments to AVOID
|
|
25
|
-
|
|
26
|
-
**Obvious Comments**
|
|
21
|
+
## Examples
|
|
27
22
|
|
|
28
23
|
```javascript
|
|
24
|
+
// ✗ Obvious
|
|
29
25
|
let counter = 0; // Initialize counter to zero
|
|
30
|
-
counter++; // Increment counter by one
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Redundant Comments**
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
36
|
-
function getUserName() {
|
|
37
|
-
return user.name; // Return the user's name
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
26
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```javascript
|
|
44
|
-
// Calculate tax at 5% rate
|
|
45
|
-
const tax = price * 0.08; // Actually 8%
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Comments to WRITE
|
|
49
|
-
|
|
50
|
-
**Complex Business Logic**
|
|
51
|
-
|
|
52
|
-
```javascript
|
|
27
|
+
// ✓ WHY
|
|
53
28
|
// Apply progressive tax brackets: 10% up to 10k, 20% above
|
|
54
29
|
const tax = calculateProgressiveTax(income, [0.1, 0.2], [10000]);
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Non-obvious Algorithms**
|
|
58
30
|
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
// because we need distances between all nodes
|
|
31
|
+
// ✓ Algorithm rationale
|
|
32
|
+
// Floyd-Warshall: need all-pairs distances, not just single-source
|
|
62
33
|
for (let k = 0; k < vertices; k++) { /* ... */ }
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Regex Patterns**
|
|
66
34
|
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**API Constraints or Gotchas**
|
|
73
|
-
|
|
74
|
-
```javascript
|
|
75
|
-
// GitHub API rate limit: 5000 requests/hour for authenticated users
|
|
35
|
+
// ✓ API constraint
|
|
36
|
+
// GitHub API: 5000 req/hr for authenticated users
|
|
76
37
|
await rateLimiter.wait();
|
|
38
|
+
|
|
39
|
+
// ✓ Config rationale
|
|
40
|
+
const MAX_RETRIES = 3; // network reliability baseline
|
|
41
|
+
const API_TIMEOUT = 5000; // Lambda max is 15 s — leave headroom
|
|
77
42
|
```
|
|
78
43
|
|
|
79
|
-
## Public APIs
|
|
44
|
+
## Public APIs — JSDoc
|
|
80
45
|
|
|
81
46
|
```javascript
|
|
82
47
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
87
|
-
* @
|
|
88
|
-
* @param {number} compoundFrequency - How many times per year interest compounds (default: 1)
|
|
89
|
-
* @returns {number} Final amount after compound interest
|
|
48
|
+
* @param principal - Initial amount
|
|
49
|
+
* @param rate - Annual rate as decimal (0.05 = 5%)
|
|
50
|
+
* @param time - Years
|
|
51
|
+
* @param n - Compounds per year (default 1)
|
|
52
|
+
* @returns Final amount
|
|
90
53
|
*/
|
|
91
|
-
function calculateCompoundInterest(principal, rate, time,
|
|
92
|
-
// ... implementation
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Configuration and Constants
|
|
97
|
-
|
|
98
|
-
```javascript
|
|
99
|
-
const MAX_RETRIES = 3; // Based on network reliability studies
|
|
100
|
-
const API_TIMEOUT = 5000; // AWS Lambda timeout is 15s, leaving buffer
|
|
54
|
+
function calculateCompoundInterest(principal, rate, time, n = 1) { ... }
|
|
101
55
|
```
|
|
102
56
|
|
|
103
57
|
## Annotation Tags
|
|
104
58
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// DEPRECATED: Use newApiFunction() instead - this will be removed in v3.0
|
|
116
|
-
```
|
|
59
|
+
| Tag | Use |
|
|
60
|
+
|-----|-----|
|
|
61
|
+
| `TODO` | Planned work |
|
|
62
|
+
| `FIXME` | Known bug needing fix |
|
|
63
|
+
| `HACK` | Workaround — note why and when to remove |
|
|
64
|
+
| `NOTE` | Important non-obvious constraint |
|
|
65
|
+
| `WARNING` | Side effect / mutation risk |
|
|
66
|
+
| `PERF` | Hot path — optimization opportunity |
|
|
67
|
+
| `SECURITY` | Security-sensitive code |
|
|
68
|
+
| `DEPRECATED` | Note replacement and removal version |
|
|
117
69
|
|
|
118
70
|
## Anti-Patterns
|
|
119
71
|
|
|
120
|
-
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Before committing, ensure your comments:
|
|
72
|
+
| Anti-pattern | Rule |
|
|
73
|
+
|--------------|------|
|
|
74
|
+
| Commented-out code | Delete it — git has history |
|
|
75
|
+
| Changelog in comments | Use git log |
|
|
76
|
+
| Decorative dividers | Use proper file/section structure |
|
|
127
77
|
|
|
128
|
-
|
|
129
|
-
- [ ] Are grammatically correct and clear
|
|
130
|
-
- [ ] Will remain accurate as code evolves
|
|
131
|
-
- [ ] Add genuine value to code understanding
|
|
132
|
-
- [ ] Are placed appropriately (above the code they describe)
|
|
133
|
-
- [ ] Use proper spelling and professional language
|
|
78
|
+
## Checklist
|
|
134
79
|
|
|
135
|
-
|
|
80
|
+
- [ ] Explains WHY, not WHAT
|
|
81
|
+
- [ ] Still accurate after the change
|
|
82
|
+
- [ ] Adds genuine value
|
|
83
|
+
- [ ] Placed above the code it describes
|
|
@@ -3,53 +3,30 @@ name: context-map
|
|
|
3
3
|
description: "Generate a structured file impact map before making changes. Identifies all files that will be affected, their relationships, and cascade effects — improving file partitioning for parallel work and reducing unexpected side effects."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
|
|
7
|
-
|
|
8
6
|
# Skill: Context Map
|
|
9
7
|
|
|
10
|
-
Generate a
|
|
8
|
+
Generate a **file impact map** before code changes to identify affected files, relationships, and cascades — improving agent file partitions for parallel work.
|
|
11
9
|
|
|
12
10
|
## When to Use
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## How to Generate a Context Map
|
|
21
|
-
|
|
22
|
-
### Step 1: Identify the Entry Points
|
|
23
|
-
|
|
24
|
-
Start from the task description and identify the primary files that MUST change:
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
Entry Points:
|
|
28
|
-
- [file path] — [why it must change]
|
|
29
|
-
- [file path] — [why it must change]
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Step 2: Trace Dependencies (Outward)
|
|
33
|
-
|
|
34
|
-
For each entry point, trace what depends on it:
|
|
12
|
+
| Use | Skip |
|
|
13
|
+
|-----|------|
|
|
14
|
+
| Feature implementation (Phase 1) | Isolated bug fixes ≤2 files |
|
|
15
|
+
| Refactoring (Phase 1 Scope) | |
|
|
16
|
+
| Schema changes cascading through queries/components | |
|
|
17
|
+
| Any task touching `libs/` | |
|
|
35
18
|
|
|
36
|
-
|
|
37
|
-
2. **Type consumers** — what files use types/interfaces defined here?
|
|
38
|
-
3. **Route references** — what pages render this component?
|
|
39
|
-
4. **Query consumers** — what components or pages call this query?
|
|
40
|
-
5. **Test files** — what test files cover this code?
|
|
19
|
+
## Steps
|
|
41
20
|
|
|
42
|
-
###
|
|
21
|
+
### 1 — Entry Points
|
|
22
|
+
Identify files that MUST change from the task description.
|
|
43
23
|
|
|
44
|
-
|
|
24
|
+
### 2 — Trace Outward (dependents)
|
|
25
|
+
Use `grep_search` / `list_code_usages`: imports, type consumers, route references, query consumers, test files.
|
|
45
26
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
### Step 4: Build the Map
|
|
51
|
-
|
|
52
|
-
Produce a structured map in this format:
|
|
27
|
+
### 3 — Trace Inward (sources)
|
|
28
|
+
CMS schemas, `libs/` utilities, config files.
|
|
29
|
+
### 4 — Build the Map
|
|
53
30
|
|
|
54
31
|
```markdown
|
|
55
32
|
## Context Map: [Task Name]
|
|
@@ -57,81 +34,63 @@ Produce a structured map in this format:
|
|
|
57
34
|
### Entry Points (MUST change)
|
|
58
35
|
| File | Reason | Owner |
|
|
59
36
|
|------|--------|-------|
|
|
60
|
-
| `libs/queries/src/lib/places.ts` | Add
|
|
61
|
-
| `libs/ui-kit
|
|
37
|
+
| `libs/queries/src/lib/places.ts` | Add query field | Content Engineer |
|
|
38
|
+
| `libs/ui-kit/.../PlaceCard/` | Display new field | UI/UX Expert |
|
|
62
39
|
|
|
63
40
|
### Cascade Effects (WILL change)
|
|
64
41
|
| File | Triggered By | Reason | Owner |
|
|
65
42
|
|------|-------------|--------|-------|
|
|
66
|
-
| `apps/web-app/places/page.tsx` | PlaceCard
|
|
67
|
-
| `
|
|
68
|
-
| `libs/queries/src/lib/__tests__/places.test.ts` | Query change | Update test | Testing Expert |
|
|
43
|
+
| `apps/web-app/places/page.tsx` | PlaceCard | Update props | Frontend Dev |
|
|
44
|
+
| `libs/queries/src/lib/__tests__/places.test.ts` | Query | Update test | Testing Expert |
|
|
69
45
|
|
|
70
|
-
### Shared Boundaries (WATCH
|
|
46
|
+
### Shared Boundaries (WATCH)
|
|
71
47
|
| File | Risk | Mitigation |
|
|
72
48
|
|------|------|------------|
|
|
73
|
-
| `libs/ui-kit/src/lib/index.ts` | Barrel export
|
|
49
|
+
| `libs/ui-kit/src/lib/index.ts` | Barrel export conflict | Merge sequentially |
|
|
74
50
|
|
|
75
|
-
### Unaffected
|
|
51
|
+
### Unaffected
|
|
76
52
|
| Area | Why |
|
|
77
53
|
|------|-----|
|
|
78
54
|
| `db/migrations/` | No DB changes |
|
|
79
55
|
| `libs/auth/` | No auth changes |
|
|
80
|
-
| `apps/cms-studio/` | No schema changes |
|
|
81
56
|
```
|
|
82
57
|
|
|
83
|
-
###
|
|
58
|
+
### 5 — Derive File Partitions
|
|
84
59
|
|
|
85
|
-
|
|
60
|
+
Assign ownership — no file in two partitions; shared boundaries to one agent (merged first); test files to Testing Expert unless tightly coupled.
|
|
86
61
|
|
|
87
62
|
```
|
|
88
|
-
Agent A
|
|
89
|
-
Agent B
|
|
90
|
-
Agent C
|
|
91
|
-
Agent D
|
|
63
|
+
Agent A: libs/queries/src/lib/places.ts
|
|
64
|
+
Agent B: libs/ui-kit/.../PlaceCard/
|
|
65
|
+
Agent C: apps/web-app/places/, apps/admin-panel/places/
|
|
66
|
+
Agent D: **/*test*, **/*spec*
|
|
92
67
|
```
|
|
93
68
|
|
|
94
|
-
|
|
95
|
-
- No file appears in two partitions
|
|
96
|
-
- Shared boundaries are assigned to ONE agent and merged first
|
|
97
|
-
- Test files belong to the Testing Expert unless tightly coupled to a specific change
|
|
98
|
-
|
|
99
|
-
## Context Map Depth Levels
|
|
100
|
-
|
|
101
|
-
Scale the depth to the task complexity:
|
|
69
|
+
## Depth Levels
|
|
102
70
|
|
|
103
|
-
|
|
|
104
|
-
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
71
|
+
| Complexity | Files | Depth |
|
|
72
|
+
|------------|-------|-------|
|
|
73
|
+
| Small | 1–3 | Entry points + direct imports |
|
|
74
|
+
| Medium | 4–8 | Entry + 1-hop cascade |
|
|
75
|
+
| Large | 9+ | Full dependency graph |
|
|
108
76
|
|
|
109
|
-
##
|
|
77
|
+
## Team Lead Integration
|
|
110
78
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
3. **Verification (QA Gate)** — compare actual changed files against the map to detect scope creep
|
|
116
|
-
|
|
117
|
-
### Including in Delegation Prompts
|
|
79
|
+
Produced in **Phase 1**; consumed by:
|
|
80
|
+
- **Decomposition** — informs file partitions
|
|
81
|
+
- **Delegation prompts** — agents receive their map section
|
|
82
|
+
- **QA Gate** — compare actual changes against map to detect scope creep
|
|
118
83
|
|
|
84
|
+
Delegation prompt snippet:
|
|
119
85
|
```markdown
|
|
120
|
-
## Your File Partition
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- `libs/queries/src/lib/places.ts`
|
|
124
|
-
- `libs/queries/src/lib/__tests__/places.test.ts`
|
|
125
|
-
|
|
126
|
-
Do NOT modify:
|
|
127
|
-
- `libs/ui-kit/` (owned by UI/UX Expert)
|
|
128
|
-
- `apps/` (owned by Developer)
|
|
86
|
+
## Your File Partition
|
|
87
|
+
Modify only: `libs/queries/src/lib/places.ts`, `libs/queries/src/lib/__tests__/places.test.ts`
|
|
88
|
+
Do NOT modify: `libs/ui-kit/` (UI/UX Expert), `apps/` (Developer)
|
|
129
89
|
```
|
|
130
90
|
|
|
131
91
|
## Anti-Patterns
|
|
132
92
|
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
- **Mapping files you won't change** — the "Unaffected" section is for explicitly noting what's safe, not for cataloging the entire codebase
|
|
93
|
+
- Skipping for "obvious" tasks — shared libs cascade unexpectedly
|
|
94
|
+
- Guessing dependencies instead of using `grep_search` / `list_code_usages`
|
|
95
|
+
- Over-mapping a 2-file fix
|
|
96
|
+
- Using a stale map after plan changes
|
|
@@ -3,27 +3,17 @@ name: data-engineering
|
|
|
3
3
|
description: "Data pipeline ETL workflows, web scraping, NDJSON processing, and CMS data import. Use when building scrapers, processing data, running CLI tools, or importing to a CMS."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- ⚠️ This file is managed by OpenCastle. Edits will be overwritten on update. Customize in the .opencastle/ directory instead. -->
|
|
7
|
-
|
|
8
6
|
# Data Engineering
|
|
9
7
|
|
|
10
|
-
Generic
|
|
8
|
+
Generic pipeline patterns. For project-specific sources, CLI commands, and data status see [data-pipeline-config.md](../../.opencastle/stack/data-pipeline-config.md).
|
|
11
9
|
|
|
12
10
|
## Scraper Architecture
|
|
13
11
|
|
|
14
|
-
### Base Scraper Pattern
|
|
15
|
-
|
|
16
12
|
```typescript
|
|
17
13
|
interface ScraperConfig {
|
|
18
|
-
source: string;
|
|
19
|
-
|
|
20
|
-
maxPages: number;
|
|
21
|
-
concurrency: number;
|
|
22
|
-
delay: { min: number; max: number };
|
|
23
|
-
outputPath: string;
|
|
24
|
-
headless: boolean;
|
|
14
|
+
source: string; query: string; maxPages: number; concurrency: number;
|
|
15
|
+
delay: { min: number; max: number }; outputPath: string; headless: boolean;
|
|
25
16
|
}
|
|
26
|
-
|
|
27
17
|
abstract class BaseScraper {
|
|
28
18
|
abstract scrape(config: ScraperConfig): Promise<void>;
|
|
29
19
|
abstract extractVenue(page: Page): Promise<RawVenue>;
|
|
@@ -31,74 +21,37 @@ abstract class BaseScraper {
|
|
|
31
21
|
}
|
|
32
22
|
```
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Use a headless browser cluster for concurrent scraping (e.g., Puppeteer Cluster, Playwright):
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
// Example using Puppeteer Cluster — adapt to your project's scraping library
|
|
40
|
-
const cluster = await Cluster.launch({
|
|
41
|
-
concurrency: Cluster.CONCURRENCY_CONTEXT,
|
|
42
|
-
maxConcurrency: config.concurrency,
|
|
43
|
-
puppeteerOptions: {
|
|
44
|
-
headless: config.headless,
|
|
45
|
-
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
46
|
-
},
|
|
47
|
-
retryLimit: 3,
|
|
48
|
-
retryDelay: 5000,
|
|
49
|
-
timeout: 30000,
|
|
50
|
-
});
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Anti-Detection Measures
|
|
54
|
-
|
|
55
|
-
- Rotate user agents from a curated list
|
|
56
|
-
- Random delays between requests (2-5 seconds default)
|
|
57
|
-
- Randomize viewport sizes
|
|
58
|
-
- Block unnecessary resources (images, fonts, CSS) for speed
|
|
59
|
-
- Use stealth plugin for the scraping library
|
|
60
|
-
- Request interception for resource optimization
|
|
24
|
+
Launch a headless browser cluster (Puppeteer Cluster / Playwright) with `retryLimit: 3`, `retryDelay: 5000`, `timeout: 30000`, `args: ['--no-sandbox', '--disable-setuid-sandbox']`.
|
|
61
25
|
|
|
62
|
-
|
|
26
|
+
**Anti-detection:** rotate user-agents; random 2–5 s delays; randomize viewport; block images/fonts/CSS; use stealth plugin.
|
|
63
27
|
|
|
64
|
-
|
|
65
|
-
- Log failed URLs for manual review
|
|
66
|
-
- Save partial results on crash/interruption
|
|
67
|
-
- Checkpoint/resume for long-running scrapes
|
|
28
|
+
**Error recovery:** exponential backoff (3 retries); log failed URLs; save partial results; checkpoint/resume for long runs.
|
|
68
29
|
|
|
69
|
-
## NDJSON Output
|
|
30
|
+
## NDJSON Output
|
|
70
31
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```json
|
|
74
|
-
{"name":"Example Venue","lat":50.0755,"lng":14.4378,"source":"google-maps","sourceId":"ChIJ...","category":"bar","address":"Street 30, City","rating":4.5,"reviewCount":120}
|
|
75
|
-
```
|
|
32
|
+
One record per line: `{"name":"…","lat":50.0755,"lng":14.4378,"source":"google-maps","sourceId":"ChIJ…","category":"bar","address":"…","rating":4.5,"reviewCount":120}`
|
|
76
33
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
| Field | Priority | Notes |
|
|
80
|
-
|-------|----------|-------|
|
|
34
|
+
| Field | Type | Notes |
|
|
35
|
+
|-------|------|-------|
|
|
81
36
|
| `name` | Required | Preserve original encoding |
|
|
82
37
|
| `lat`/`lng` | Required | GPS coordinates |
|
|
83
|
-
| `address` | Required | Full text
|
|
84
|
-
| `source` | Required |
|
|
85
|
-
| `sourceId` | Required | Source-
|
|
86
|
-
| `category` | Required | Domain
|
|
87
|
-
|
|
88
|
-
### Optional Fields
|
|
89
|
-
|
|
90
|
-
`rating`, `reviewCount`, `phone`, `website`, `openingHours`, `photos`, `priceLevel`
|
|
38
|
+
| `address` | Required | Full text |
|
|
39
|
+
| `source` | Required | e.g. `google-maps` |
|
|
40
|
+
| `sourceId` | Required | Source-unique ID |
|
|
41
|
+
| `category` | Required | Domain category |
|
|
42
|
+
| `rating`, `reviewCount`, `phone`, `website`, `openingHours`, `photos`, `priceLevel` | Optional | — |
|
|
91
43
|
|
|
92
44
|
## Design Principles
|
|
93
45
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
46
|
+
| Principle | Detail |
|
|
47
|
+
|-----------|--------|
|
|
48
|
+
| Composable stages | Single-responsibility pipeline steps |
|
|
49
|
+
| Streams | Use for large files to minimize memory |
|
|
50
|
+
| Idempotent imports | `createOrReplace` + deterministic `_id` |
|
|
51
|
+
| Dry-run mode | Required for all destructive operations |
|
|
52
|
+
| Normalized names | Strip diacritics for search |
|
|
53
|
+
| Structured addresses | `{ street, city, postalCode, country, countryCode }` |
|
|
54
|
+
| Data lineage | Record source and transformation history |
|
|
55
|
+
| Error handling | Skip bad records; don't halt pipeline |
|
|
56
|
+
| Backup | Before all bulk operations |
|
|
57
|
+
| Rate limiting | Respect `robots.txt`; attribute sources |
|