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
|
@@ -25,133 +25,73 @@ applyTo: '**'
|
|
|
25
25
|
|
|
26
26
|
## General Coding Principles
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
- **Self-documenting Code**: Comment WHY, not WHAT — for detailed patterns, load the **code-commenting** skill
|
|
30
|
-
- **TypeScript First**: All code in TypeScript with proper types — never `as any`
|
|
31
|
-
- **DRY**: Extract reusable logic into functions, custom hooks, or components
|
|
32
|
-
- **Feature Grouping**: Co-locate code that changes together; avoid barrel files
|
|
33
|
-
- **Shared Code**: Place reusable UI components and data queries in shared libraries
|
|
28
|
+
Clean code, readability, maintainability. TypeScript with proper types (never `as any`). DRY. Co-locate code that changes together; avoid barrel files. Shared code in shared libraries. Comment WHY, not WHAT (load **code-commenting** skill for patterns).
|
|
34
29
|
|
|
35
30
|
## Technology Standards
|
|
36
31
|
|
|
37
|
-
Load the corresponding skill
|
|
32
|
+
Load the corresponding skill before writing code in that domain. See `.opencastle/agents/skill-matrix.json` for domain-to-skill mapping. Key domains: UI Components (**ui-library**), App Framework (**framework**), Accessibility (**accessibility-standards**), Performance (**performance-optimization**), Frontend Design (**frontend-design**).
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|--------|-------|
|
|
41
|
-
| UI Components | **ui-library** (via skill matrix) |
|
|
42
|
-
| App Framework | **framework** (via skill matrix) |
|
|
43
|
-
| Accessibility | **accessibility-standards** |
|
|
44
|
-
| Performance | **performance-optimization** |
|
|
45
|
-
| Frontend Design | **frontend-design** |
|
|
34
|
+
## Task Decomposition
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Before starting multi-step work, decompose it into individually verifiable tasks:
|
|
50
|
-
|
|
51
|
-
1. **Decompose first** — split the work into the smallest meaningful units before writing any code
|
|
52
|
-
2. **Verify each step** — after completing each unit, verify it (run tests, check types, lint, or visually inspect) before moving to the next
|
|
53
|
-
3. **Choose the right verification** — match the check to the change type:
|
|
54
|
-
- Logic change → run unit tests
|
|
55
|
-
- Type/interface change → run the project's type-check / lint command (see the **codebase-tool** skill)
|
|
56
|
-
- UI change → start dev server and visually inspect in the browser
|
|
57
|
-
- Build config change → run a full build
|
|
58
|
-
4. **Batch edits, then build** — group related edits across files, then run one build — not build-per-edit
|
|
59
|
-
5. **Stop and re-plan** — if execution diverges from the plan (unexpected errors, wrong assumptions, scope growth), stop immediately, reassess, and revise the plan before continuing
|
|
60
|
-
6. **When unsure how to verify** — ask the user rather than skipping verification
|
|
36
|
+
Decompose → verify each step → batch edits → build once. Re-plan when execution diverges. Match verification to change type. Load **decomposition** skill for templates.
|
|
61
37
|
|
|
62
38
|
## Testing
|
|
63
39
|
|
|
64
|
-
|
|
65
|
-
- **Test plan before implementation**: initial state, user interactions, state transitions, edge cases, integration
|
|
66
|
-
- **Browser testing mandatory** for any UI change — verified at responsive breakpoints defined in `testing-config.md`
|
|
67
|
-
- Load the **testing-workflow** skill for test patterns and the **browser-testing** skill for E2E automation
|
|
40
|
+
95% minimum unit test coverage. Test plan before implementation. Browser testing mandatory for UI changes. Load **testing-workflow** and **browser-testing** skills.
|
|
68
41
|
|
|
69
42
|
## Build & Task Commands
|
|
70
43
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Resolve exact commands by loading the **codebase-tool** skill from the skill matrix. Common tasks:
|
|
74
|
-
|
|
75
|
-
- **Test** — run project tests (with optional coverage)
|
|
76
|
-
- **Lint** — run linter with auto-fix
|
|
77
|
-
- **Build** — production build
|
|
78
|
-
- **Serve** — start dev server
|
|
79
|
-
- **Affected** — run a target for all projects affected by current changes
|
|
80
|
-
|
|
81
|
-
**Exception:** Tools without task runner targets may be invoked directly (e.g., CMS CLI commands, database CLI commands). Check the project's task runner config first; only bypass it when no target exists.
|
|
44
|
+
Always use the project's configured task runner. Load **codebase-tool** skill for exact commands. Direct CLI only for tools without task runner targets.
|
|
82
45
|
|
|
83
46
|
## Documentation
|
|
84
47
|
|
|
85
|
-
Follow markdown formatting
|
|
48
|
+
Follow markdown formatting standards. Load **documentation-standards** skill for templates.
|
|
86
49
|
|
|
87
50
|
## AI Optimization
|
|
88
51
|
|
|
89
|
-
See [ai-optimization.instructions.md](ai-optimization.instructions.md)
|
|
52
|
+
See [ai-optimization.instructions.md](ai-optimization.instructions.md).
|
|
90
53
|
|
|
91
54
|
## Project Context
|
|
92
55
|
|
|
93
|
-
|
|
56
|
+
See [project.instructions.md](../.opencastle/project.instructions.md).
|
|
94
57
|
|
|
95
58
|
## Git Workflow
|
|
96
59
|
|
|
97
|
-
**NEVER
|
|
60
|
+
**NEVER push to `main`.** All changes via feature/fix branch → PR. Load **git-workflow** skill for branch naming and PR rules.
|
|
98
61
|
|
|
99
62
|
## Discovered Issues Policy
|
|
100
63
|
|
|
101
|
-
>
|
|
64
|
+
> Inherits: [discovered-issues-policy](../snippets/discovered-issues-policy.md)
|
|
102
65
|
|
|
103
|
-
|
|
66
|
+
See **git-workflow** skill for full tracking procedure.
|
|
104
67
|
|
|
105
68
|
## Observability Logging
|
|
106
69
|
|
|
107
|
-
>
|
|
108
|
-
> Do NOT respond to the user until you have appended the required log records.
|
|
109
|
-
> A session without log records is a failed session — regardless of code quality.
|
|
70
|
+
> Inherits: [logging-mandatory](../snippets/logging-mandatory.md)
|
|
110
71
|
|
|
111
|
-
|
|
72
|
+
Load **observability-logging** skill for CLI commands and schemas.
|
|
112
73
|
|
|
113
74
|
## Self-Improvement Protocol
|
|
114
75
|
|
|
115
|
-
> **⛔ HARD GATE —
|
|
116
|
-
|
|
117
|
-
1. **Before starting work:** Read `.opencastle/LESSONS-LEARNED.md` — apply relevant lessons proactively. This is NOT optional.
|
|
118
|
-
2. **During execution:** If you retry with a different approach and it works, use the **self-improvement** skill to add a lesson immediately.
|
|
119
|
-
3. **Update source files:** If the lesson reveals a gap in instruction/skill files, update those files too.
|
|
76
|
+
> **⛔ HARD GATE** — Read `.opencastle/LESSONS-LEARNED.md` before starting work. Add lessons via **self-improvement** skill when retries succeed.
|
|
120
77
|
|
|
121
78
|
## Universal Agent Rules
|
|
122
79
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
3. **Read and update lessons** — See Self-Improvement Protocol above.
|
|
128
|
-
4. **Log every session** — See Observability Logging above. This is Constitution rule #6 — a blocking gate, not optional.
|
|
80
|
+
1. Never delegate (specialists complete their own work)
|
|
81
|
+
2. Follow Discovered Issues Policy
|
|
82
|
+
3. Read and update lessons
|
|
83
|
+
4. Log every session (Constitution rule #6)
|
|
129
84
|
|
|
130
85
|
## Pre-Response Quality Gate
|
|
131
86
|
|
|
132
|
-
> **⛔ STOP before responding
|
|
133
|
-
|
|
134
|
-
- [ ] **Lessons read** — `LESSONS-LEARNED.md` was read at session start
|
|
135
|
-
- [ ] **Lessons captured** — If any retry occurred, a new lesson was added via the **self-improvement** skill
|
|
136
|
-
- [ ] **Discovered issues tracked** — Any pre-existing bugs found were tracked (Discovered Issues Policy)
|
|
137
|
-
- [ ] **Lint/type/test pass** — No new errors introduced; verification ran after code changes (Constitution rule #5)
|
|
138
|
-
- [ ] **Session logged** — `events.ndjson` has a new `session` record (Constitution rule #6 — ALWAYS required)
|
|
139
|
-
- [ ] **Delegations logged** — `events.ndjson` has a `delegation` record for each delegation (Team Lead only)
|
|
140
|
-
- [ ] **Reviews logged** — `events.ndjson` has a `review` record for each fast review (if any)
|
|
141
|
-
- [ ] **Panels logged** — `events.ndjson` has a `panel` record for each panel review (if any)
|
|
142
|
-
- [ ] **Agent expertise updated** — `AGENT-EXPERTISE.md` updated for each delegation (strong/weak areas + file familiarity) (Team Lead only)
|
|
143
|
-
- [ ] **Knowledge graph appended** — `KNOWLEDGE-GRAPH.md` has new rows for file relationships discovered (Team Lead only)
|
|
144
|
-
|
|
145
|
-
Load the **observability-logging** skill for CLI commands, Base Output Contract, and detailed schemas.
|
|
146
|
-
|
|
147
|
-
## Workflow & Governance Skills
|
|
87
|
+
> **⛔ STOP before responding.** Load **observability-logging** skill and run its pre-response checklist.
|
|
148
88
|
|
|
149
|
-
|
|
89
|
+
## Governance Skills
|
|
150
90
|
|
|
151
91
|
| Concern | Skill |
|
|
152
92
|
|---------|-------|
|
|
153
|
-
|
|
|
154
|
-
| Log
|
|
155
|
-
| Lesson writing
|
|
93
|
+
| Branching, PR rules, delivery, tracking | **git-workflow** |
|
|
94
|
+
| Log commands, schemas, output contracts | **observability-logging** |
|
|
95
|
+
| Lesson writing, categories, quality | **self-improvement** |
|
|
156
96
|
|
|
157
97
|
<!-- End of Coding Standards -->
|
|
@@ -9,64 +9,37 @@ description: "Astro framework best practices for content-driven sites, islands a
|
|
|
9
9
|
|
|
10
10
|
## Project Structure
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
- Top-level: `src/`, `public/`, `astro.config.mjs`.
|
|
14
|
-
- Inside `src/`: `pages/`, `layouts/`, `components/`, `content/`, `styles/`, `assets/`.
|
|
15
|
-
- **`public/`** — static assets served as-is (favicons, robots.txt, fonts).
|
|
16
|
-
- **`src/assets/`** — images and assets processed by Astro's build pipeline.
|
|
12
|
+
Top-level: `src/`, `public/`, `astro.config.mjs`. Inside `src/`: `pages/`, `layouts/`, `components/`, `content/`, `styles/`, `assets/`. `public/` serves static assets as-is; `src/assets/` goes through Astro's build pipeline.
|
|
17
13
|
|
|
18
14
|
```
|
|
19
15
|
src/
|
|
20
|
-
├── pages/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
├── layouts/
|
|
27
|
-
│ └── BaseLayout.astro
|
|
28
|
-
├── components/
|
|
29
|
-
│ ├── Header.astro
|
|
30
|
-
│ └── Counter.tsx # React island
|
|
31
|
-
├── content/
|
|
32
|
-
│ └── blog/ # Content collection
|
|
33
|
-
│ ├── first-post.md
|
|
34
|
-
│ └── second-post.md
|
|
35
|
-
└── styles/
|
|
36
|
-
└── global.css
|
|
16
|
+
├── pages/ # file-based routing (.astro, .md, .mdx)
|
|
17
|
+
├── layouts/ # BaseLayout.astro, etc.
|
|
18
|
+
├── components/ # .astro + framework components (React islands)
|
|
19
|
+
├── content/ # Content collections (blog/, docs/, etc.)
|
|
20
|
+
├── styles/ # global.css
|
|
21
|
+
└── assets/ # processed images
|
|
37
22
|
```
|
|
38
23
|
|
|
39
24
|
## Component Model
|
|
40
25
|
|
|
41
|
-
**Default: Zero JS** —
|
|
26
|
+
**Default: Zero JS** — `.astro` components render to HTML with no client-side JavaScript.
|
|
42
27
|
|
|
43
28
|
**Islands Architecture** — Interactive components use `client:*` directives to hydrate only where needed.
|
|
44
29
|
|
|
45
|
-
### Astro
|
|
30
|
+
### Astro Component Example
|
|
46
31
|
|
|
47
32
|
```astro
|
|
48
33
|
---
|
|
49
|
-
|
|
50
|
-
interface Props {
|
|
51
|
-
title: string;
|
|
52
|
-
description?: string;
|
|
53
|
-
}
|
|
34
|
+
interface Props { title: string; description?: string; }
|
|
54
35
|
const { title, description = 'Default description' } = Astro.props;
|
|
55
36
|
const data = await fetch('https://api.example.com/data').then(r => r.json());
|
|
56
37
|
---
|
|
57
|
-
|
|
58
38
|
<section>
|
|
59
39
|
<h2>{title}</h2>
|
|
60
|
-
<
|
|
61
|
-
<ul>
|
|
62
|
-
{data.items.map((item: { id: string; name: string }) => (
|
|
63
|
-
<li>{item.name}</li>
|
|
64
|
-
))}
|
|
65
|
-
</ul>
|
|
40
|
+
{data.items.map((item: { name: string }) => <li>{item.name}</li>)}
|
|
66
41
|
</section>
|
|
67
|
-
|
|
68
42
|
<style>
|
|
69
|
-
/* Scoped by default */
|
|
70
43
|
section { max-width: 800px; margin: 0 auto; }
|
|
71
44
|
</style>
|
|
72
45
|
```
|
|
@@ -81,22 +54,9 @@ const data = await fetch('https://api.example.com/data').then(r => r.json());
|
|
|
81
54
|
| `client:media="(max-width: 768px)"` | When media query matches | Mobile-only interactivity |
|
|
82
55
|
| `client:only="react"` | Client-only, no SSR | Components that can't server-render |
|
|
83
56
|
|
|
84
|
-
```astro
|
|
85
|
-
---
|
|
86
|
-
import Counter from '../components/Counter.tsx';
|
|
87
|
-
import HeavyChart from '../components/HeavyChart.tsx';
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
<!-- Hydrates immediately -->
|
|
91
|
-
<Counter client:load />
|
|
92
|
-
|
|
93
|
-
<!-- Hydrates when visible -->
|
|
94
|
-
<HeavyChart client:visible />
|
|
95
|
-
```
|
|
96
|
-
|
|
97
57
|
## Content Collections
|
|
98
58
|
|
|
99
|
-
Define
|
|
59
|
+
Define in `src/content.config.ts` (Astro v5+) using the Content Layer API:
|
|
100
60
|
|
|
101
61
|
```ts
|
|
102
62
|
import { defineCollection, z } from 'astro:content';
|
|
@@ -106,173 +66,56 @@ const blog = defineCollection({
|
|
|
106
66
|
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
|
|
107
67
|
schema: z.object({
|
|
108
68
|
title: z.string(),
|
|
109
|
-
description: z.string(),
|
|
110
69
|
pubDate: z.coerce.date(),
|
|
111
|
-
updatedDate: z.coerce.date().optional(),
|
|
112
|
-
heroImage: z.string().optional(),
|
|
113
70
|
draft: z.boolean().default(false),
|
|
114
71
|
tags: z.array(z.string()).default([]),
|
|
115
72
|
}),
|
|
116
73
|
});
|
|
117
|
-
|
|
118
74
|
export const collections = { blog };
|
|
119
75
|
```
|
|
120
76
|
|
|
121
|
-
|
|
77
|
+
Query collections:
|
|
122
78
|
|
|
123
79
|
```astro
|
|
124
80
|
---
|
|
125
|
-
import { getCollection
|
|
126
|
-
|
|
127
|
-
// All published posts, sorted by date
|
|
81
|
+
import { getCollection } from 'astro:content';
|
|
128
82
|
const posts = (await getCollection('blog', ({ data }) => !data.draft))
|
|
129
83
|
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
|
|
130
|
-
|
|
131
|
-
// Single entry
|
|
132
|
-
const entry = await getEntry('blog', 'first-post');
|
|
133
84
|
---
|
|
134
85
|
```
|
|
135
86
|
|
|
136
87
|
## Routing
|
|
137
88
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
Every `.astro` or `.md` file in `src/pages/` becomes a route.
|
|
141
|
-
|
|
142
|
-
### Dynamic Routes
|
|
89
|
+
Every `.astro` or `.md` file in `src/pages/` becomes a route. For dynamic routes:
|
|
143
90
|
|
|
144
91
|
```astro
|
|
145
92
|
---
|
|
146
93
|
// src/pages/blog/[slug].astro
|
|
147
94
|
import { getCollection } from 'astro:content';
|
|
148
|
-
|
|
149
95
|
export async function getStaticPaths() {
|
|
150
96
|
const posts = await getCollection('blog');
|
|
151
|
-
return posts.map(post => ({
|
|
152
|
-
params: { slug: post.id },
|
|
153
|
-
props: { post },
|
|
154
|
-
}));
|
|
97
|
+
return posts.map(post => ({ params: { slug: post.id }, props: { post } }));
|
|
155
98
|
}
|
|
156
|
-
|
|
157
99
|
const { post } = Astro.props;
|
|
158
100
|
const { Content } = await post.render();
|
|
159
101
|
---
|
|
160
|
-
|
|
161
102
|
<Content />
|
|
162
103
|
```
|
|
163
104
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
Enable SSR with an adapter in `astro.config.mjs`:
|
|
167
|
-
|
|
168
|
-
```js
|
|
169
|
-
import { defineConfig } from 'astro/config';
|
|
170
|
-
import node from '@astrojs/node';
|
|
171
|
-
|
|
172
|
-
export default defineConfig({
|
|
173
|
-
output: 'server', // or 'hybrid' for mixed static + server
|
|
174
|
-
adapter: node({ mode: 'standalone' }),
|
|
175
|
-
});
|
|
176
|
-
```
|
|
105
|
+
**SSR**: Set `output: 'server'` (or `'hybrid'`) and add an adapter (`node`, `vercel`, `netlify`, `cloudflare`) in `astro.config.mjs`.
|
|
177
106
|
|
|
178
107
|
## Layouts
|
|
179
108
|
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
// src/layouts/BaseLayout.astro
|
|
183
|
-
interface Props {
|
|
184
|
-
title: string;
|
|
185
|
-
description?: string;
|
|
186
|
-
}
|
|
187
|
-
const { title, description = 'My Astro Site' } = Astro.props;
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
<!doctype html>
|
|
191
|
-
<html lang="en">
|
|
192
|
-
<head>
|
|
193
|
-
<meta charset="UTF-8" />
|
|
194
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
195
|
-
<meta name="description" content={description} />
|
|
196
|
-
<title>{title}</title>
|
|
197
|
-
</head>
|
|
198
|
-
<body>
|
|
199
|
-
<slot />
|
|
200
|
-
</body>
|
|
201
|
-
</html>
|
|
202
|
-
```
|
|
109
|
+
Define in `src/layouts/BaseLayout.astro` — a full HTML shell with `<slot />` for page content. Pass `title` and `description` as props.
|
|
203
110
|
|
|
204
111
|
## Integrations
|
|
205
112
|
|
|
206
|
-
Use `astro add` for
|
|
207
|
-
|
|
208
|
-
```bash
|
|
209
|
-
npx astro add react # Add React support
|
|
210
|
-
npx astro add tailwind # Add Tailwind CSS v4
|
|
211
|
-
npx astro add mdx # Add MDX support
|
|
212
|
-
npx astro add sitemap # Add sitemap generation
|
|
213
|
-
npx astro add node # Add Node.js SSR adapter
|
|
214
|
-
npx astro add vercel # Add Vercel adapter
|
|
215
|
-
npx astro add netlify # Add Netlify adapter
|
|
216
|
-
npx astro add cloudflare # Add Cloudflare adapter
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## API Routes (Endpoints)
|
|
220
|
-
|
|
221
|
-
```ts
|
|
222
|
-
// src/pages/api/search.ts
|
|
223
|
-
import type { APIRoute } from 'astro';
|
|
224
|
-
|
|
225
|
-
export const GET: APIRoute = async ({ url }) => {
|
|
226
|
-
const query = url.searchParams.get('q');
|
|
227
|
-
const results = await searchDatabase(query);
|
|
228
|
-
return new Response(JSON.stringify(results), {
|
|
229
|
-
headers: { 'Content-Type': 'application/json' },
|
|
230
|
-
});
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
export const POST: APIRoute = async ({ request }) => {
|
|
234
|
-
const body = await request.json();
|
|
235
|
-
// handle mutation
|
|
236
|
-
return new Response(JSON.stringify({ ok: true }), { status: 200 });
|
|
237
|
-
};
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Actions (Server Mutations)
|
|
113
|
+
Use `astro add` for react, tailwind, mdx, sitemap, node, vercel, netlify, cloudflare.
|
|
241
114
|
|
|
242
|
-
|
|
115
|
+
## API Routes & Actions
|
|
243
116
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
import { z } from 'astro:schema';
|
|
247
|
-
|
|
248
|
-
export const server = {
|
|
249
|
-
subscribe: defineAction({
|
|
250
|
-
accept: 'form',
|
|
251
|
-
input: z.object({ email: z.string().email() }),
|
|
252
|
-
handler: async ({ email }) => {
|
|
253
|
-
await addToNewsletter(email);
|
|
254
|
-
return { success: true };
|
|
255
|
-
},
|
|
256
|
-
}),
|
|
257
|
-
};
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## Performance Patterns
|
|
261
|
-
|
|
262
|
-
- **Zero JS by default** — only ship JavaScript for interactive islands.
|
|
263
|
-
- **Image optimization** — use `astro:assets` for automatic image optimization.
|
|
264
|
-
- **View Transitions** — use `<ViewTransitions />` for smooth page navigation.
|
|
265
|
-
- **Prefetching** — enabled by default for visible links.
|
|
266
|
-
- **CSS scoping** — styles in `.astro` files are scoped automatically.
|
|
267
|
-
|
|
268
|
-
```astro
|
|
269
|
-
---
|
|
270
|
-
import { Image } from 'astro:assets';
|
|
271
|
-
import heroImage from '../assets/hero.jpg';
|
|
272
|
-
---
|
|
273
|
-
|
|
274
|
-
<Image src={heroImage} alt="Hero" width={800} />
|
|
275
|
-
```
|
|
117
|
+
- **API routes**: Export `GET`/`POST` handlers from `src/pages/api/*.ts` returning `new Response(...)`.
|
|
118
|
+
- **Actions**: Use `defineAction` in `src/actions/index.ts` for type-safe server mutations with Zod validation.
|
|
276
119
|
|
|
277
120
|
## Anti-Patterns
|
|
278
121
|
|
|
@@ -286,3 +129,4 @@ import heroImage from '../assets/hero.jpg';
|
|
|
286
129
|
| Giant monolithic pages | Hard to maintain and test | Split into layouts + reusable components |
|
|
287
130
|
| Ignoring `astro add` for integrations | Manual config is error-prone | Use `astro add` for official integrations |
|
|
288
131
|
| Missing `alt` on images | Accessibility violation | Always provide descriptive `alt` text |
|
|
132
|
+
| Not using `astro:assets` for images | Missing optimization | Use `<Image>` from `astro:assets` |
|
|
@@ -11,16 +11,36 @@ Generic Convex development methodology. For project-specific schema, functions,
|
|
|
11
11
|
|
|
12
12
|
## Critical Development Rules
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
**Function Registration**
|
|
15
|
+
- Public: `query`/`mutation`/`action`; Private: `internalQuery`/`internalMutation`/`internalAction` (import from `./_generated/server`)
|
|
16
|
+
- Always include `returns` validator; use `returns: v.null()` when the function returns nothing (JS implicitly returns `null`)
|
|
17
|
+
|
|
18
|
+
**Function References**
|
|
19
|
+
- Use `api.filename.functionName` for public and `internal.filename.functionName` for internal functions (from `./_generated/api`)
|
|
20
|
+
- Never pass functions directly to `ctx.runQuery`/`ctx.runMutation`/`ctx.runAction` — always use function references
|
|
21
|
+
|
|
22
|
+
**Queries**
|
|
23
|
+
- Do NOT use `.filter()` — define an index in the schema and use `.withIndex()` instead
|
|
24
|
+
- Use `.unique()` for single document queries
|
|
25
|
+
- No `.delete()` on queries — collect results, then call `ctx.db.delete(row._id)` on each
|
|
26
|
+
|
|
27
|
+
**Actions**
|
|
28
|
+
- Add `"use node";` at the top of files containing actions that use Node.js built-in modules
|
|
29
|
+
- Never use `ctx.db` inside actions — actions don't have database access; use `ctx.runQuery`/`ctx.runMutation` instead
|
|
30
|
+
|
|
31
|
+
**Schema**
|
|
32
|
+
- Index name must include all fields: `["field1", "field2"]` → `"by_field1_and_field2"`
|
|
33
|
+
- Index fields must be queried in definition order
|
|
34
|
+
- Do NOT define `_id` or `_creationTime` — they are automatic system fields
|
|
35
|
+
|
|
36
|
+
**General**
|
|
37
|
+
- Schema-first design: define in `convex/schema.ts` using `defineSchema`/`defineTable`
|
|
38
|
+
- Mutations are ACID transactional; use actions for external API calls or side effects
|
|
39
|
+
- Never await queries in mutations — they run in separate contexts
|
|
40
|
+
- Use `.paginate()` for large result sets
|
|
41
|
+
- Use `Id<'tableName'>` for document ID types (from `./_generated/dataModel`)
|
|
42
|
+
- Use `v.null()` not `v.undefined()` — `undefined` is not a valid Convex value
|
|
43
|
+
- Environment variables: set via Convex dashboard; access with `process.env` in actions only
|
|
24
44
|
|
|
25
45
|
## Schema Patterns
|
|
26
46
|
|
|
@@ -34,7 +54,9 @@ export default defineSchema({
|
|
|
34
54
|
name: v.string(),
|
|
35
55
|
email: v.string(),
|
|
36
56
|
role: v.union(v.literal("admin"), v.literal("user")),
|
|
37
|
-
})
|
|
57
|
+
})
|
|
58
|
+
.index("by_email", ["email"])
|
|
59
|
+
.index("by_role", ["role"]),
|
|
38
60
|
});
|
|
39
61
|
```
|
|
40
62
|
|
|
@@ -45,9 +67,12 @@ import { v } from "convex/values";
|
|
|
45
67
|
|
|
46
68
|
export const list = query({
|
|
47
69
|
args: { role: v.optional(v.string()) },
|
|
70
|
+
returns: v.array(v.any()),
|
|
48
71
|
handler: async (ctx, args) => {
|
|
49
72
|
if (args.role) {
|
|
50
|
-
return await ctx.db.query("users")
|
|
73
|
+
return await ctx.db.query("users")
|
|
74
|
+
.withIndex("by_role", q => q.eq("role", args.role!))
|
|
75
|
+
.collect();
|
|
51
76
|
}
|
|
52
77
|
return await ctx.db.query("users").collect();
|
|
53
78
|
},
|
|
@@ -61,6 +86,7 @@ import { v } from "convex/values";
|
|
|
61
86
|
|
|
62
87
|
export const create = mutation({
|
|
63
88
|
args: { name: v.string(), email: v.string() },
|
|
89
|
+
returns: v.id("users"),
|
|
64
90
|
handler: async (ctx, args) => {
|
|
65
91
|
return await ctx.db.insert("users", { ...args, role: "user" });
|
|
66
92
|
},
|
|
@@ -54,17 +54,21 @@ Place functions in `netlify/functions/`:
|
|
|
54
54
|
|
|
55
55
|
```typescript
|
|
56
56
|
// netlify/functions/hello.ts
|
|
57
|
-
import type {
|
|
57
|
+
import type { Context, Config } from "@netlify/functions";
|
|
58
58
|
|
|
59
|
-
export
|
|
60
|
-
return {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
export default async (req: Request, context: Context) => {
|
|
60
|
+
return new Response(JSON.stringify({ message: "Hello from Netlify Functions" }), {
|
|
61
|
+
headers: { "Content-Type": "application/json" },
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const config: Config = {
|
|
66
|
+
path: "/hello",
|
|
64
67
|
};
|
|
65
68
|
```
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
Functions use web standard Request/Response. The `Config` export defines routing (path) instead of the default `/.netlify/functions/<name>` path.
|
|
71
|
+
|
|
68
72
|
- Supports TypeScript out of the box
|
|
69
73
|
- Default timeout: 10s (extendable to 26s on Pro)
|
|
70
74
|
- Use background functions for long-running tasks (up to 15 min)
|
|
@@ -110,15 +114,15 @@ export const config = { path: '/geo' };
|
|
|
110
114
|
|
|
111
115
|
```typescript
|
|
112
116
|
// netlify/functions/daily-task.ts
|
|
113
|
-
import type {
|
|
117
|
+
import type { Config } from "@netlify/functions";
|
|
114
118
|
|
|
115
|
-
export
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
export default async (req: Request) => {
|
|
120
|
+
const { next_run } = await req.json();
|
|
121
|
+
console.log("Next invocation at:", next_run);
|
|
118
122
|
};
|
|
119
123
|
|
|
120
|
-
export const config = {
|
|
121
|
-
schedule:
|
|
124
|
+
export const config: Config = {
|
|
125
|
+
schedule: "0 0 * * *", // Daily at midnight UTC
|
|
122
126
|
};
|
|
123
127
|
```
|
|
124
128
|
|