|
| 1 | +# Project Instructions |
| 2 | + |
| 3 | +## Critical Project Conventions |
| 4 | + |
| 5 | +### Package Manager |
| 6 | + |
| 7 | +- **ALWAYS use `yarn`, NEVER use `npm`** - This project exclusively uses Yarn |
| 8 | +- All script execution: `yarn <script-name>` |
| 9 | +- All package operations: `yarn add`, `yarn install`, etc. |
| 10 | + |
| 11 | +### Validation and Quality |
| 12 | + |
| 13 | +- **MDX/.ai.txt Pairing**: Every `.mdx` file must have a corresponding `.ai.txt` companion file |
| 14 | +- Run `yarn validate:mdx` to verify pairing before commits/PRs |
| 15 | +- Exceptions are defined in `.mdx-validation.json` (supports exact paths and glob patterns) |
| 16 | +- The validation script (`scripts/validate-mdx-pairing.ts`) checks bidirectionally |
| 17 | + |
| 18 | +### Project Structure |
| 19 | + |
| 20 | +- Documentation: `docs/developer-docs/6.0.x/` |
| 21 | +- Plans/design docs: `plans/` (project root) |
| 22 | +- Scripts: `scripts/` (TypeScript scripts executed via `tsx`) |
| 23 | +- Validation config: `.mdx-validation.json` (project root) |
| 24 | + |
| 25 | +## Documentation Structure |
| 26 | + |
| 27 | +- Documentation files live in `docs/developer-docs/6.0.x/` |
| 28 | +- `.mdx` files are the documentation pages |
| 29 | +- `.ai.txt` files are AI companion context files — read them to understand the corresponding `.mdx` file (sources, decisions, patterns, tone guidelines) |
| 30 | + |
| 31 | +### Directory Layout |
| 32 | + |
| 33 | +``` |
| 34 | +docs/developer-docs/6.0.x/ |
| 35 | +├── core-concepts/ # Foundational knowledge: architecture, applications, project structure, DI, Result pattern, multi-tenancy, local dev, env vars |
| 36 | +├── get-started/ # Welcome, installation, upgrade to Business |
| 37 | +├── cli/ # CLI commands reference |
| 38 | +├── graphql/ # GraphQL schema building with factory pattern |
| 39 | +├── headless-cms/ # Largest section — all CMS extensibility |
| 40 | +│ ├── builder/ # ModelBuilder, GroupBuilder, FieldBuilder APIs |
| 41 | +│ ├── event-handler/ # Entry/model/group lifecycle events |
| 42 | +│ ├── examples/ # Private model, single-entry model |
| 43 | +│ ├── ui/ # Field renderers |
| 44 | +│ └── use-case/ # Entry/model/group business logic |
| 45 | +├── overview/ # Pricing, security features |
| 46 | +│ └── features/ |
| 47 | +├── tasks/ # Background task system (Runner, Context, Controller) |
| 48 | +└── website-builder/ # Website Builder extensibility |
| 49 | + ├── event-handler/ # Page/redirect lifecycle events |
| 50 | + └── use-case/ # Page/redirect business logic |
| 51 | +``` |
| 52 | + |
| 53 | +### Key Patterns |
| 54 | + |
| 55 | +- Each major system follows a consistent taxonomy: **builder** (define structure) / **event-handler** (react to events) / **use-case** (custom business logic) |
| 56 | +- `core-concepts/di.mdx` and `core-concepts/result.mdx` are foundational — referenced by all other sections |
| 57 | +- `.ai.txt` files contain: source info, key decisions, understanding, code patterns, related docs, and tone guidelines |
| 58 | +- Tone is calibrated per doc type: conceptual (about), technical (reference), practical (examples) |
| 59 | + |
| 60 | +### MDX/.ai.txt Pairing Exceptions |
| 61 | + |
| 62 | +Current exceptions (defined in `.mdx-validation.json`): |
| 63 | + |
| 64 | +- `get-started/welcome.mdx` - introductory page |
| 65 | +- `get-started/install-webiny.mdx` - installation guide |
| 66 | +- `overview/pricing.mdx` - pricing overview |
| 67 | +- `overview/features/security.mdx` - security features |
| 68 | + |
| 69 | +## MDX Writing Conventions |
| 70 | + |
| 71 | +### Frontmatter |
| 72 | + |
| 73 | +Every `.mdx` file uses exactly three required fields: |
| 74 | + |
| 75 | +```yaml |
| 76 | +--- |
| 77 | +id: <8-char-alphanumeric> # e.g., "kp9m2xnf" — short, random, lowercase |
| 78 | +title: <Title Case> |
| 79 | +description: <One-line description> |
| 80 | +--- |
| 81 | +``` |
| 82 | + |
| 83 | +Optional fields (rare, only for special pages like welcome): `pageHeader: false`, `fullWidth: true`. |
| 84 | + |
| 85 | +### Page Structure |
| 86 | + |
| 87 | +Every page follows this order: |
| 88 | + |
| 89 | +1. Frontmatter |
| 90 | +2. Component imports |
| 91 | +3. `<Alert type="success" title="WHAT YOU'LL LEARN">` block with bullet list of questions |
| 92 | +4. `## Overview` — always the first H2, 1-3 paragraphs of prose |
| 93 | +5. Content sections as H2 (`##`) with H3 (`###`) subsections as needed |
| 94 | +6. No H1 headings in the body — the page title comes from frontmatter |
| 95 | + |
| 96 | +### Components |
| 97 | + |
| 98 | +Only one MDX component is used: `<Alert>` from `@/components/Alert`. |
| 99 | + |
| 100 | +```mdx |
| 101 | +import { Alert } from "@/components/Alert"; |
| 102 | + |
| 103 | +; |
| 104 | +``` |
| 105 | + |
| 106 | +Alert types: |
| 107 | + |
| 108 | +- `type="success"` — "WHAT YOU'LL LEARN" opener (every page) |
| 109 | +- `type="info"` — supplemental links or context (inline, overview pages) |
| 110 | +- `type="warning"` — important cautions (inline, overview pages) |
| 111 | + |
| 112 | +No other custom components are used (no `<Tabs>`, `<Steps>`, etc.). |
| 113 | + |
| 114 | +### Code Blocks |
| 115 | + |
| 116 | +- Language tag is always specified: ` ```typescript ` or ` ```graphql ` |
| 117 | +- **File path annotations** go after the language tag: ` ```typescript extensions/cms/group/eventHandler/create/beforeCreate.ts ` |
| 118 | +- Use ` ```tsx ` for `webiny.config.tsx` files |
| 119 | +- GraphQL SDL in TypeScript uses `/* GraphQL */` tag: `builder.addTypeDefs(/* GraphQL */ \`...\`)` |
| 120 | +- Minimal comments in code — only for pedagogical correct/wrong comparisons using `// ✅ Correct` / `// ❌ Wrong` |
| 121 | +- No shell/bash code blocks |
| 122 | + |
| 123 | +### Import Paths in Code Examples |
| 124 | + |
| 125 | +```typescript |
| 126 | +// Webiny v6 API imports — use "webiny/" prefix, NOT "@webiny/" |
| 127 | +import { ModelFactory } from "webiny/api/cms/model"; |
| 128 | +import { CreateEntryUseCase } from "webiny/api/cms/entry"; |
| 129 | +import { Logger } from "webiny/api/logger"; |
| 130 | +import { Api } from "webiny/extensions"; |
| 131 | +import { Result } from "webiny/api"; |
| 132 | + |
| 133 | +// Local file imports use .js extensions (ESM) |
| 134 | +import { BookRepository } from "./abstractions/BookRepository.js"; |
| 135 | + |
| 136 | +// Type-only imports |
| 137 | +import type { CmsEntry } from "webiny/api"; |
| 138 | +``` |
| 139 | + |
| 140 | +### Text Formatting |
| 141 | + |
| 142 | +- Backticks for: code, class names, method names, type names, package names |
| 143 | +- **Bold** for key labels: `**Naming Convention:**`, `**Key Point:**` |
| 144 | +- Bullet lists use `-`, not numbered lists (even for sequential steps) |
| 145 | +- No emojis in prose |
| 146 | +- Inline links use standard markdown: `[text](/docs/path)` |
| 147 | +- "Webiny" always capitalized |
| 148 | + |
| 149 | +## Tone and Voice |
| 150 | + |
| 151 | +### General Rules |
| 152 | + |
| 153 | +- Concise and technical — no filler, no marketing language in developer docs |
| 154 | +- Direct and instructional — "Use `createAbstraction()` to create one" |
| 155 | +- Address the reader as "you" |
| 156 | +- Explain "why" briefly before showing "how" |
| 157 | +- Avoid "we" statements — use "The system provides/offers" instead |
| 158 | +- No analogies in published docs (save those for `.ai.txt` context) |
| 159 | +- Accessible to junior developers while remaining technically complete |
| 160 | + |
| 161 | +### Per Doc Type |
| 162 | + |
| 163 | +| Doc Type | Tone | Focus | |
| 164 | +| --------------------------- | ---------------------------- | ------------------------------------------------- | |
| 165 | +| `about.mdx` | Conceptual, accessible | Why and what, link to reference for how | |
| 166 | +| `reference.mdx` | Simple, concise, API-focused | Method signatures, minimal examples | |
| 167 | +| `example.mdx` | Practical, production-ready | Complete working code, copy-paste friendly | |
| 168 | +| `event-handler/*.mdx` | Production-ready examples | When/why to use each event, real-world scenarios | |
| 169 | +| `use-case/*.mdx` | Technical and complete | Full abstraction + implementation patterns | |
| 170 | +| `builder/*.mdx` | Technical reference | Complete method docs, practical examples per type | |
| 171 | +| `management.mdx` | Practical, operation-focused | Complete examples, error handling | |
| 172 | +| `get-started/`, `overview/` | Conversational, welcoming | High-level survey, no code | |
| 173 | + |
| 174 | +## TypeScript Code Patterns |
| 175 | + |
| 176 | +### DI Pattern (used in all implementations) |
| 177 | + |
| 178 | +```typescript |
| 179 | +import { SomeAbstraction } from "webiny/api/cms/entity"; |
| 180 | +import { Logger } from "webiny/api/logger"; |
| 181 | + |
| 182 | +// Implementation class with Impl suffix |
| 183 | +class SomeAbstractionImpl implements SomeAbstraction.Interface { |
| 184 | + public constructor(private logger: Logger.Interface) {} |
| 185 | + |
| 186 | + public async handle(event: SomeAbstraction.Event): Promise<void> { |
| 187 | + // implementation |
| 188 | + } |
| 189 | +} |
| 190 | + |
| 191 | +// Factory registration — MUST be default export |
| 192 | +const SomeAbstractionConst = SomeAbstraction.createImplementation({ |
| 193 | + implementation: SomeAbstractionImpl, |
| 194 | + dependencies: [Logger] |
| 195 | +}); |
| 196 | + |
| 197 | +export default SomeAbstractionConst; |
| 198 | +``` |
| 199 | + |
| 200 | +### Result Pattern (used in all use cases) |
| 201 | + |
| 202 | +```typescript |
| 203 | +const result = await someUseCase.execute(params); |
| 204 | +if (result.isFail()) { |
| 205 | + // handle error — return early (guard clause) |
| 206 | + return { error: result.error, data: null }; |
| 207 | +} |
| 208 | +const value = result.value; |
| 209 | +``` |
| 210 | + |
| 211 | +### Namespace Export Pattern (abstractions) |
| 212 | + |
| 213 | +```typescript |
| 214 | +export namespace MyAbstraction { |
| 215 | + export type Interface = IMyAbstraction; |
| 216 | + export type Params = IMyAbstractionParams; |
| 217 | + export type Return = IMyAbstractionReturn; |
| 218 | +} |
| 219 | +``` |
| 220 | + |
| 221 | +### Registration in webiny.config.tsx |
| 222 | + |
| 223 | +```tsx |
| 224 | +import React from "react"; |
| 225 | +import { Api } from "webiny/extensions"; |
| 226 | + |
| 227 | +export const Extensions = () => { |
| 228 | + return ( |
| 229 | + <> |
| 230 | + {/* ... all your other extensions */} |
| 231 | + <Api.Extension src={"/extensions/cms/entity/path/to/file.ts"} /> |
| 232 | + </> |
| 233 | + ); |
| 234 | +}; |
| 235 | +``` |
| 236 | + |
| 237 | +### Event Handler Naming |
| 238 | + |
| 239 | +- Class names: `On[Resource][Before|After][Operation]Handler` (e.g., `OnPageBeforeCreateHandler`) |
| 240 | +- Abstraction tokens: `[Resource][Before|After][Operation]Handler` (without "On" prefix) |
| 241 | +- "Before" handlers receive `payload.input`; "After" handlers receive the completed entity (e.g., `payload.page`) |
| 242 | + |
| 243 | +## .ai.txt File Format |
| 244 | + |
| 245 | +Each `.ai.txt` companion file contains these sections: |
| 246 | + |
| 247 | +1. `AI Context: [Page Title] ([filename])` — header |
| 248 | +2. `Source of Information:` — numbered list of research sources |
| 249 | +3. `Key Documentation Decisions:` — editorial choices made |
| 250 | +4. `[Topic-specific understanding]` — detailed domain knowledge |
| 251 | +5. `[Code patterns/snippets]` — verified TypeScript templates |
| 252 | +6. `Related Documents:` — cross-references to sibling docs |
| 253 | +7. `Key Code Locations:` — source code paths in the Webiny repo |
| 254 | +8. `Tone Guidelines:` — explicit style instructions for the page |
| 255 | + |
| 256 | +### Maintenance |
| 257 | + |
| 258 | +- When new documentation files (`.mdx` or `.ai.txt`) are added, update the directory layout and notes in this AGENTS.md to reflect the changes. |
0 commit comments