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.
Files changed (69) hide show
  1. package/README.md +13 -3
  2. package/bin/cli.mjs +2 -0
  3. package/package.json +1 -1
  4. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  5. package/src/orchestrator/agents/api-designer.agent.md +25 -34
  6. package/src/orchestrator/agents/architect.agent.md +40 -84
  7. package/src/orchestrator/agents/content-engineer.agent.md +29 -31
  8. package/src/orchestrator/agents/copywriter.agent.md +35 -60
  9. package/src/orchestrator/agents/data-expert.agent.md +24 -30
  10. package/src/orchestrator/agents/database-engineer.agent.md +26 -31
  11. package/src/orchestrator/agents/developer.agent.md +32 -34
  12. package/src/orchestrator/agents/devops-expert.agent.md +31 -26
  13. package/src/orchestrator/agents/documentation-writer.agent.md +29 -29
  14. package/src/orchestrator/agents/performance-expert.agent.md +36 -33
  15. package/src/orchestrator/agents/release-manager.agent.md +25 -34
  16. package/src/orchestrator/agents/researcher.agent.md +41 -95
  17. package/src/orchestrator/agents/reviewer.agent.md +24 -34
  18. package/src/orchestrator/agents/security-expert.agent.md +35 -39
  19. package/src/orchestrator/agents/seo-specialist.agent.md +25 -32
  20. package/src/orchestrator/agents/session-guard.agent.md +20 -79
  21. package/src/orchestrator/agents/team-lead.agent.md +50 -254
  22. package/src/orchestrator/agents/testing-expert.agent.md +37 -49
  23. package/src/orchestrator/agents/ui-ux-expert.agent.md +33 -39
  24. package/src/orchestrator/customizations/KNOWN-ISSUES.md +0 -1
  25. package/src/orchestrator/customizations/agents/skill-matrix.json +12 -0
  26. package/src/orchestrator/instructions/general.instructions.md +24 -84
  27. package/src/orchestrator/plugins/astro/SKILL.md +23 -179
  28. package/src/orchestrator/plugins/convex/SKILL.md +38 -12
  29. package/src/orchestrator/plugins/netlify/SKILL.md +17 -13
  30. package/src/orchestrator/plugins/nextjs/SKILL.md +55 -261
  31. package/src/orchestrator/plugins/nx/SKILL.md +20 -72
  32. package/src/orchestrator/plugins/playwright/SKILL.md +5 -17
  33. package/src/orchestrator/plugins/slack/SKILL.md +28 -190
  34. package/src/orchestrator/plugins/teams/SKILL.md +10 -140
  35. package/src/orchestrator/plugins/vitest/SKILL.md +2 -2
  36. package/src/orchestrator/prompts/bug-fix.prompt.md +25 -63
  37. package/src/orchestrator/prompts/implement-feature.prompt.md +29 -66
  38. package/src/orchestrator/prompts/quick-refinement.prompt.md +31 -66
  39. package/src/orchestrator/skills/accessibility-standards/SKILL.md +50 -105
  40. package/src/orchestrator/skills/agent-hooks/SKILL.md +60 -110
  41. package/src/orchestrator/skills/agent-memory/SKILL.md +44 -93
  42. package/src/orchestrator/skills/api-patterns/SKILL.md +20 -68
  43. package/src/orchestrator/skills/code-commenting/SKILL.md +49 -101
  44. package/src/orchestrator/skills/context-map/SKILL.md +47 -88
  45. package/src/orchestrator/skills/data-engineering/SKILL.md +27 -74
  46. package/src/orchestrator/skills/decomposition/SKILL.md +50 -98
  47. package/src/orchestrator/skills/deployment-infrastructure/SKILL.md +44 -107
  48. package/src/orchestrator/skills/documentation-standards/SKILL.md +28 -89
  49. package/src/orchestrator/skills/fast-review/SKILL.md +51 -276
  50. package/src/orchestrator/skills/frontend-design/SKILL.md +53 -163
  51. package/src/orchestrator/skills/git-workflow/SKILL.md +18 -54
  52. package/src/orchestrator/skills/memory-merger/SKILL.md +51 -88
  53. package/src/orchestrator/skills/observability-logging/SKILL.md +29 -75
  54. package/src/orchestrator/skills/orchestration-protocols/SKILL.md +58 -117
  55. package/src/orchestrator/skills/panel-majority-vote/SKILL.md +65 -140
  56. package/src/orchestrator/skills/performance-optimization/SKILL.md +21 -85
  57. package/src/orchestrator/skills/project-consistency/SKILL.md +62 -281
  58. package/src/orchestrator/skills/react-development/SKILL.md +38 -86
  59. package/src/orchestrator/skills/security-hardening/SKILL.md +40 -84
  60. package/src/orchestrator/skills/self-improvement/SKILL.md +26 -60
  61. package/src/orchestrator/skills/seo-patterns/SKILL.md +40 -105
  62. package/src/orchestrator/skills/session-checkpoints/SKILL.md +26 -68
  63. package/src/orchestrator/skills/team-lead-reference/SKILL.md +66 -206
  64. package/src/orchestrator/skills/testing-workflow/SKILL.md +42 -112
  65. package/src/orchestrator/skills/validation-gates/SKILL.md +39 -170
  66. package/src/orchestrator/snippets/base-output-contract.md +14 -0
  67. package/src/orchestrator/snippets/discovered-issues-policy.md +15 -0
  68. package/src/orchestrator/snippets/logging-mandatory.md +11 -0
  69. package/src/orchestrator/snippets/never-expose-secrets.md +22 -0
@@ -3,118 +3,74 @@ name: security-hardening
3
3
  description: "Security architecture including authentication, authorization, RLS policies, security headers, CSP, input validation, API security, and OAuth patterns. Use when implementing auth flows, writing RLS policies, configuring security headers, validating inputs, or auditing security."
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
  # Security Hardening
9
7
 
10
- ## Security Architecture
11
-
12
- ```
13
- Edge Network (WAF, DDoS)
14
- → Security Headers (framework config: HSTS, CSP, X-Frame-Options)
15
- → Middleware (session refresh)
16
- → Server Actions (Auth: CSRF protection)
17
- → RLS Policies (row-level authorization)
18
- ```
8
+ ## Architecture
19
9
 
20
- | Layer | Role | Protection |
10
+ | Layer | Tool | Protection |
21
11
  |-------|------|------------|
22
12
  | Edge | WAF / CDN | DDoS, bot detection |
23
- | Headers | Framework config | HSTS, CSP, XSS protection |
24
- | Middleware | Proxy / middleware layer | Session management |
13
+ | Headers | Framework config | HSTS, CSP, X-Frame-Options |
14
+ | Middleware | Proxy layer | Session refresh, protected routes |
25
15
  | Server Actions | Auth provider | Authentication, CSRF |
26
16
  | Database | RLS Policies | Row-level authorization |
27
- | API Routes | CRON_SECRET | Cron job authorization |
17
+ | API Routes | `CRON_SECRET` | Cron job authorization |
28
18
  | Input | Zod | Schema validation |
29
19
  | Rate Limiting | Proxy layer | IP-based throttling |
30
20
 
31
21
  ## Authentication
32
22
 
33
- **Platform:** Auth provider with Server Actions pattern. Resolve specific auth library and configuration via the **database** capability slot in the skill matrix.
34
-
35
- - **Server Actions** for sign in/up/out, session management.
36
- - **Middleware** for session refresh, protected routes.
37
- - **RLS Policies** in the database.
38
- - **OAuth providers:** Configured in the auth provider's dashboard.
39
- - **User roles:** Stored in the user profiles table (e.g., `profiles.roles TEXT[]`).
40
- - **Key auth files:** Resolve via project-specific customization files.
41
- - **Cron authorization:** `CRON_SECRET` env var, `Bearer` token in `authorization` header
42
-
43
- ### Server Actions Pattern Benefits
44
-
45
- - Automatic CSRF protection (POST-only Server Actions).
46
- - No exposed API endpoints for auth.
47
- - Server-side session management.
23
+ Auth provider with Server Actions pattern. Resolve library via **database** capability slot in skill matrix.
48
24
 
49
- ### Session Management
25
+ | Concern | Approach |
26
+ |---------|----------|
27
+ | Sign in/up/out | Server Actions (POST-only → automatic CSRF protection) |
28
+ | Session refresh | Middleware `updateSession()`, HTTP-only cookies |
29
+ | Protected routes | Middleware check |
30
+ | OAuth | Configured in auth provider dashboard |
31
+ | User roles | `profiles.roles TEXT[]` |
32
+ | Cron auth | `CRON_SECRET` env var, `Bearer` token in `authorization` header |
50
33
 
51
- - HTTP-only cookies (auth client managed).
52
- - Automatic refresh via middleware (`updateSession()`).
53
- - Sign out clears cookie and invalidates session.
34
+ ## CSP
54
35
 
55
- ## Content Security Policy
36
+ Principle of least privilege. External domains are project-specific (see deployment customization).
56
37
 
57
- ### Allowed External Domains (framework config)
38
+ - `default-src 'self'` deny by default
39
+ - `object-src 'none'` — block plugins
40
+ - `frame-ancestors 'self'` — prevent clickjacking
41
+ - `upgrade-insecure-requests` — enforce HTTPS
42
+ - Whitelist only required external domains per directive
58
43
 
59
- | Purpose | Domains |
60
- |---------|--------|
61
- | Scripts | Project-specific — see deployment customization |
62
- | Styles | Project-specific — see deployment customization |
63
- | Fonts | Project-specific — see deployment customization |
64
- | Frames | Project-specific — see deployment customization |
44
+ **Note:** `'unsafe-inline'`/`'unsafe-eval'` may be required in dev mode — use nonces/hashes in production.
65
45
 
66
- ### Directives
46
+ ## RLS
67
47
 
68
- General CSP directives follow the principle of least privilege:
69
- - `default-src 'self'` — deny by default.
70
- - Whitelist only required external domains per directive.
71
- - `object-src 'none'` — block plugins.
72
- - `frame-ancestors 'self'` — prevent clickjacking.
73
- - `upgrade-insecure-requests` — enforce HTTPS.
48
+ > **SQL examples and role system:** See the **database** skill (authoritative source for RLS).
74
49
 
75
- **Known weaknesses:** `'unsafe-inline'` and `'unsafe-eval'` in script-src (may be required for framework dev mode). Consider nonces/hashes for production inline scripts.
76
-
77
- ## RLS Policy Patterns
78
-
79
- > **Detailed RLS patterns and SQL examples:** See the **database** skill (resolved via skill matrix), which is the authoritative source for RLS policies, role systems, and migration rules.
80
-
81
- ### Best Practices
82
-
83
- - Enable RLS on all tables: `ALTER TABLE x ENABLE ROW LEVEL SECURITY;`
84
- - Test policies with different user roles.
85
- - Use `auth.uid()` for authentication checks.
86
- - EXISTS subqueries for role checks.
87
- - Never rely solely on client-side authorization.
88
- - Never disable RLS in production.
50
+ - `ALTER TABLE x ENABLE ROW LEVEL SECURITY;` on all tables
51
+ - Use `auth.uid()` for auth checks; EXISTS subqueries for role checks
52
+ - Never rely solely on client-side authorization; never disable RLS in production
89
53
 
90
54
  ## API Security
91
55
 
92
- ### Cron Job Authorization
93
-
94
56
  ```typescript
95
- export async function GET(request: NextRequest) {
96
- const authHeader = request.headers.get('authorization');
97
- if (!authHeader || authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
98
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
99
- }
57
+ // Cron authorization pattern
58
+ const authHeader = request.headers.get('authorization');
59
+ if (!authHeader || authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
60
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
100
61
  }
101
62
  ```
102
63
 
103
- - Strong random CRON_SECRET: `openssl rand -hex 32`
104
- - Rotate quarterly.
105
-
106
- ### Input Validation
64
+ Generate secret: `openssl rand -hex 32`. Rotate quarterly.
107
65
 
108
- - Zod schemas for all request validation.
109
- - React Hook Form for client-side validation.
110
- - Server-side validation in all Server Actions and route handlers.
66
+ Input: Zod schemas in all Server Actions and route handlers; React Hook Form client-side.
111
67
 
112
68
  ## Critical Rules
113
69
 
114
- 1. Never commit secrets — use deployment platform environment variables.
115
- 2. Always use Server Actions for auth operations.
116
- 3. Enable RLS on all tables — default-deny, explicit-allow.
117
- 4. Validate all inputs with Zod before database operations.
118
- 5. Sanitize user content escape HTML in reviews/descriptions.
119
- 6. Parameterized queries (database client handles automatically).
120
- 7. Rotate secrets regularly (quarterly).
70
+ 1. Never commit secrets — use env vars.
71
+ 2. Server Actions for all auth operations.
72
+ 3. RLS on all tables — default-deny, explicit-allow.
73
+ 4. Validate all inputs with Zod before DB operations.
74
+ 5. Sanitize user content (escape HTML).
75
+ 6. Parameterized queries (DB client handles automatically).
76
+ 7. Rotate secrets quarterly.
@@ -3,96 +3,62 @@ name: self-improvement
3
3
  description: "Protocol for reading and updating the lessons-learned knowledge base. MUST be followed by ALL agents — read lessons before work, write lessons after retries. This makes the agent team self-improving across sessions."
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
  # Self-Improvement Protocol
9
7
 
10
- This skill defines how agents learn from mistakes and share knowledge so the same pitfalls are never repeated.
11
-
12
- ## Core Principle
13
-
14
- **If you retry something with a different approach and it works, document the lesson immediately.** The cost of writing a lesson (2 minutes) is always less than the cost of someone else hitting the same pitfall (5-30 minutes).
15
-
16
- ## The Lessons File
17
-
18
- Location: `.opencastle/LESSONS-LEARNED.md`
19
-
20
- This is the team's collective memory — a structured log of tool/command pitfalls, workarounds, and correct approaches discovered through execution.
8
+ ## Core Rule
21
9
 
22
- ## Protocol for All Agents
10
+ **Retry with a different approach and it works → document the lesson immediately.** File: `.opencastle/LESSONS-LEARNED.md`
23
11
 
24
- The core protocol (read lessons → write on retry → log session) is referenced from `general.instructions.md` via the **Workflow & Governance** table. This skill provides the detailed reference material for writing lessons.
12
+ ## Writing a Lesson
25
13
 
26
- ## How to Write a Lesson
27
-
28
- > **⛔ HARD GATE — Use the CLI to write lessons. Do NOT edit LESSONS-LEARNED.md directly.**
29
-
30
- Use the `opencastle lesson` CLI command. It auto-increments the lesson ID, formats the entry, and updates the category index.
14
+ > **⛔ HARD GATE Use the CLI. Do NOT edit LESSONS-LEARNED.md directly.**
31
15
 
32
16
  ```sh
33
17
  opencastle lesson --title "Short descriptive title" --category general --severity high \
34
- --problem "What went wrong and what error/behavior was observed" \
35
- --wrong "The obvious/intuitive approach that fails" \
36
- --correct "The working solution" \
37
- --why "Root cause explanation"
18
+ --problem "What was observed" --wrong "Failing approach" --correct "Working solution" \
19
+ --why "Root cause"
38
20
  ```
39
21
 
40
- Required flags: `--title`, `--category`, `--severity`, `--problem`
41
- Optional flags: `--wrong`, `--correct`, `--why`
42
-
43
- Run `opencastle lesson --help` for full usage and valid category/severity values.
44
-
45
- ### After writing the lesson
46
-
47
- If the lesson reveals a gap in existing instruction/skill files, **also update those files** to include the correct approach. This prevents the pitfall at the source level, not just as a retroactive note.
22
+ Required: `--title`, `--category`, `--severity`, `--problem` · Optional: `--wrong`, `--correct`, `--why`
48
23
 
49
- Examples:
50
- - Lesson about task tracker tools → update the skill mapped by the `task-management` slot in the skill matrix
51
- - Lesson about codebase-tool commands → update the skill mapped by the `codebase-tool` slot in the skill matrix
52
- - Lesson about CMS queries → update the skill mapped by the `cms` slot in the skill matrix
53
- - Lesson about browser testing → update the skill mapped by the `e2e-testing` slot in the skill matrix
24
+ After writing: if the lesson reveals a gap in a skill/instruction file, update that file too (prevents the pitfall at source).
54
25
 
55
26
  ## Categories
56
27
 
57
28
  | Category | Covers |
58
29
  |----------|--------|
59
30
  | `task-management` | Task tracker tools, issue management, workflow states |
60
- | `jira` | Jira MCP tools (Atlassian Rovo), issue management, workflows |
61
- | `mcp-tools` | Any MCP server tool quirks (deferred loading, parameters) |
31
+ | `jira` | Jira MCP tools (Atlassian Rovo) |
32
+ | `mcp-tools` | MCP server tool quirks (deferred loading, parameters) |
62
33
  | `codebase-tool` | Task runner CLI commands, caching, build tools |
63
- | `terminal` | Shell commands, port management, process management |
34
+ | `terminal` | Shell commands, port/process management |
64
35
  | `framework` | App framework, build, dev server, SSR |
65
36
  | `cms` | CMS content queries, schema deployment |
66
37
  | `database` | Database auth, migrations, RLS, SQL |
67
38
  | `git` | Git operations, branching, merge conflicts |
68
39
  | `deployment` | Deployment, environment variables, edge config |
69
40
  | `browser-testing` | E2E testing, screenshots, browser automation |
70
- | `general` | Anything that doesn't fit above |
41
+ | `general` | Anything else |
71
42
 
72
- ## Severity Guide
43
+ ## Severity
73
44
 
74
- | Level | Meaning | Impact |
75
- |-------|---------|--------|
76
- | `high` | Blocks work entirely | Agent cannot proceed without the workaround |
77
- | `medium` | Wastes 5+ minutes | Agent will eventually figure it out but wastes time |
78
- | `low` | Minor friction | Slight annoyance, easy to work around |
45
+ | Level | Impact |
46
+ |-------|--------|
47
+ | `high` | Blocks work agent cannot proceed without the workaround |
48
+ | `medium` | Wastes 5+ minutes |
49
+ | `low` | Minor friction |
79
50
 
80
- ## Quality Standards
51
+ ## Quality Rules
81
52
 
82
- - **Be specific** — include exact error messages, exact commands, exact tool parameters
83
- - **Show both wrong and right** — the contrast is what makes lessons actionable
84
- - **Explain why** root cause helps agents reason about similar situations
85
- - **Keep it concise** one lesson per entry, no essays
86
- - **Code blocks are mandatory** — for commands, tool calls, and configurations
53
+ - Include exact error messages, commands, and tool parameters
54
+ - Show wrong **and** correct approaches — the contrast is actionable
55
+ - Explain why (root cause)
56
+ - One lesson per entry; code blocks mandatory for commands
87
57
 
88
58
  ## Anti-Patterns
89
59
 
90
- - **Never skip reading lessons** before starting work this is the #1 cause of repeated mistakes
91
- - **Never "fix it and move on"** without documenting — your fix dies with your session
92
- - **Never write vague lessons** like "the tracker is tricky" — be specific about what fails and what works
93
- - **Never duplicate existing lessons** — check the index first
94
- - **Never wait until the end of a session** to write lessons — write them immediately when the retry succeeds
60
+ Never skip reading lessons · Never fix without documenting · Never write vague entries · Never duplicate · Never defer to end of session
95
61
 
96
- ## Agent Memory Protocol
62
+ ## Agent Memory
97
63
 
98
- For agent expertise tracking and cross-session knowledge graphs, load the **agent-memory** skill. It covers memory templates, update triggers, retrieval protocols, and the knowledge graph format.
64
+ For expertise tracking and cross-session knowledge graphs, load the **agent-memory** skill.
@@ -3,8 +3,6 @@ name: seo-patterns
3
3
  description: "Technical SEO patterns for meta tags, structured data, sitemaps, URL strategy, and rendering. Use when optimizing pages for search engines or implementing SEO features."
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
  # SEO Patterns
9
7
 
10
8
  ## Core Principles
@@ -16,10 +14,7 @@ description: "Technical SEO patterns for meta tags, structured data, sitemaps, U
16
14
 
17
15
  ## Meta Tags & Open Graph
18
16
 
19
- Every page template must include the full set of meta tags:
20
-
21
17
  ```tsx
22
- // Next.js App Router — layout or page metadata
23
18
  export const metadata: Metadata = {
24
19
  title: 'Product Name — Short Descriptor',
25
20
  description: 'Concise 150-160 char description with primary keyword.',
@@ -31,35 +26,24 @@ export const metadata: Metadata = {
31
26
  type: 'website',
32
27
  images: [{ url: 'https://example.com/og-image.jpg', width: 1200, height: 630 }],
33
28
  },
34
- twitter: {
35
- card: 'summary_large_image',
36
- title: 'Product Name — Short Descriptor',
37
- images: ['https://example.com/og-image.jpg'],
38
- },
29
+ twitter: { card: 'summary_large_image', title: 'Product Name — Short Descriptor', images: ['https://example.com/og-image.jpg'] },
39
30
  robots: { index: true, follow: true },
40
31
  };
41
32
  ```
42
33
 
43
- ### Meta Tag Checklist
44
-
45
- - [ ] `<title>` is unique, 50-60 chars, includes primary keyword
46
- - [ ] `<meta name="description">` is unique, 150-160 chars, includes CTA
47
- - [ ] `<link rel="canonical">` points to the single authoritative URL
48
- - [ ] `og:title`, `og:description`, `og:image` (1200×630 px min), `og:type` are set
49
- - [ ] `twitter:card`, `twitter:title`, `twitter:image` are set
50
- - [ ] `robots` directives are correct (`noindex` on admin/draft pages only)
34
+ **Checklist:** unique title (50-60 chars) · unique description (150-160 chars) · canonical URL · `og:title/description/image` (1200×630 px) · `og:type` · `twitter:card/title/image` · `noindex` only on admin/draft pages.
51
35
 
52
36
  ## Structured Data (JSON-LD)
53
37
 
54
- Use JSON-LD `<script>` blocks — never microdata or RDFa. Choose schema types based on page purpose:
38
+ Use JSON-LD `<script>` blocks — never microdata or RDFa.
55
39
 
56
40
  | Page Type | Schema Type(s) | Required Properties |
57
41
  |-----------|----------------|---------------------|
58
42
  | Homepage | `WebSite`, `Organization` | `name`, `url`, `searchAction`, `logo` |
59
- | Detail page | `Product`, `Article`, or domain-specific type | `name`, `description`, `image` |
60
- | Listing / category page | `ItemList` + `ListItem` | `itemListElement`, `position`, `url` |
61
- | Breadcrumb navigation | `BreadcrumbList` | `itemListElement`, `position`, `name` |
62
- | Blog post | `Article` or `BlogPosting` | `headline`, `datePublished`, `author` |
43
+ | Detail page | `Product`, `Article`, or domain type | `name`, `description`, `image` |
44
+ | Listing page | `ItemList` + `ListItem` | `itemListElement`, `position`, `url` |
45
+ | Breadcrumbs | `BreadcrumbList` | `itemListElement`, `position`, `name` |
46
+ | Blog post | `Article` / `BlogPosting` | `headline`, `datePublished`, `author` |
63
47
  | FAQ page | `FAQPage` | `mainEntity` with `Question` + `Answer` |
64
48
 
65
49
  ### Example: Breadcrumb + Article
@@ -67,27 +51,15 @@ Use JSON-LD `<script>` blocks — never microdata or RDFa. Choose schema types b
67
51
  ```tsx
68
52
  function StructuredData({ breadcrumbs, article }: Props) {
69
53
  const breadcrumbLd = {
70
- '@context': 'https://schema.org',
71
- '@type': 'BreadcrumbList',
72
- itemListElement: breadcrumbs.map((crumb, i) => ({
73
- '@type': 'ListItem',
74
- position: i + 1,
75
- name: crumb.label,
76
- item: crumb.url,
77
- })),
54
+ '@context': 'https://schema.org', '@type': 'BreadcrumbList',
55
+ itemListElement: breadcrumbs.map((crumb, i) => ({ '@type': 'ListItem', position: i + 1, name: crumb.label, item: crumb.url })),
78
56
  };
79
-
80
57
  const articleLd = {
81
- '@context': 'https://schema.org',
82
- '@type': 'Article',
83
- headline: article.title,
84
- description: article.summary,
85
- image: article.imageUrl,
86
- datePublished: article.publishedAt,
87
- dateModified: article.updatedAt,
88
- author: { '@type': 'Person', name: article.author },
58
+ '@context': 'https://schema.org', '@type': 'Article',
59
+ headline: article.title, description: article.summary,
60
+ image: article.imageUrl, datePublished: article.publishedAt,
61
+ dateModified: article.updatedAt, author: { '@type': 'Person', name: article.author },
89
62
  };
90
-
91
63
  return (
92
64
  <>
93
65
  <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }} />
@@ -97,20 +69,13 @@ function StructuredData({ breadcrumbs, article }: Props) {
97
69
  }
98
70
  ```
99
71
 
100
- ### Validation
101
-
102
- - Run every JSON-LD block through [Google's Rich Results Test](https://search.google.com/test/rich-results) before merging.
103
- - Validate against [schema.org](https://schema.org) definitions for required/recommended properties.
104
- - Check the Search Console **Enhancements** report after deployment.
72
+ Validate every block via [Google's Rich Results Test](https://search.google.com/test/rich-results) before merging. Check Search Console **Enhancements** after deployment.
105
73
 
106
74
  ## Sitemap & Crawlability
107
75
 
108
- - Generate an XML sitemap dynamically from your data source (CMS, database, filesystem).
109
- - Use a **sitemap index** when page count exceeds 50,000 URLs or file size exceeds 50 MB.
110
- - Include `<lastmod>` timestamps omit if you can't guarantee accuracy.
111
- - Submit sitemaps via Google Search Console and reference them in `robots.txt`.
112
-
113
- ### Example: robots.txt
76
+ - Generate XML sitemap dynamically from your data source (CMS, DB, filesystem).
77
+ - Use a **sitemap index** when >50,000 URLs or >50 MB.
78
+ - Include `<lastmod>` only if accurate; submit via Google Search Console and reference in `robots.txt`.
114
79
 
115
80
  ```txt
116
81
  User-agent: *
@@ -118,26 +83,13 @@ Allow: /
118
83
  Disallow: /admin/
119
84
  Disallow: /api/
120
85
  Disallow: /preview/
121
-
122
86
  Sitemap: https://example.com/sitemap.xml
123
87
  ```
124
88
 
125
- ### Crawlability Checklist
126
-
127
- - [ ] `robots.txt` allows crawling of all public pages
128
- - [ ] `robots.txt` blocks admin, API, and preview routes
129
- - [ ] XML sitemap is auto-generated and up to date
130
- - [ ] Sitemap is referenced in `robots.txt`
131
- - [ ] Internal links connect all public pages (no orphan pages)
132
- - [ ] Page load time < 3s (crawl budget efficiency)
89
+ **Checklist:** robots.txt allows all public pages · blocks admin/API/preview · XML sitemap auto-generated and current · referenced in robots.txt · no orphan pages · page load < 3s.
133
90
 
134
91
  ## URL Strategy
135
92
 
136
- - Use lowercase, hyphen-separated slugs: `/blog/my-post-title`
137
- - Keep URLs short, keyword-relevant, and human-readable.
138
- - Enforce trailing-slash consistency (pick one, redirect the other).
139
- - Implement 301 redirects for any renamed or moved pages.
140
-
141
93
  | Pattern | Good | Bad |
142
94
  |---------|------|-----|
143
95
  | Slug format | `/products/blue-widget` | `/products/Blue_Widget` |
@@ -145,56 +97,39 @@ Sitemap: https://example.com/sitemap.xml
145
97
  | Consistency | Always `/path/` or `/path` | Mixed trailing slashes |
146
98
  | Parameters | `/products?sort=price` | `/products/sort/price/asc` |
147
99
 
148
- ### Redirect Example (Next.js)
149
-
150
100
  ```ts
151
101
  // next.config.ts
152
- const nextConfig = {
153
- async redirects() {
154
- return [
155
- { source: '/old-page', destination: '/new-page', permanent: true },
156
- { source: '/blog/:slug/amp', destination: '/blog/:slug', permanent: true },
157
- ];
158
- },
159
- };
102
+ const redirects = [
103
+ { source: '/old-page', destination: '/new-page', permanent: true },
104
+ { source: '/blog/:slug/amp', destination: '/blog/:slug', permanent: true },
105
+ ];
160
106
  ```
161
107
 
162
108
  ## Rendering & Indexability
163
109
 
164
- - **Server-render** all content that must be indexed titles, descriptions, body text, structured data.
165
- - **Client-hydrated** interactive elements (filters, modals) are fine, but content behind JS-only rendering will not be indexed reliably.
166
- - Use semantic HTML (`<h1>`–`<h6>`, `<article>`, `<nav>`, `<main>`) for crawlers to understand page structure.
110
+ Server-render all indexed content. Use semantic HTML (`<h1>`–`<h6>`, `<article>`, `<nav>`, `<main>`) for crawler structure.
167
111
 
168
- ### Image SEO
169
-
170
- | Attribute | Purpose | Example |
171
- |-----------|---------|---------|
172
- | `alt` | Describes image for screen readers + crawlers | `alt="Blue widget on white background"` |
173
- | `loading` | Lazy-load below-fold images | `loading="lazy"` |
174
- | `width` / `height` | Prevents layout shift (CLS) | `width={800} height={600}` |
112
+ | Image Attribute | Purpose | Example |
113
+ |-----------------|---------|---------|
114
+ | `alt` | Describes for crawlers + screen readers | `alt="Blue widget on white background"` |
115
+ | `loading` | Lazy-load below-fold | `loading="lazy"` |
116
+ | `width` / `height` | Prevents CLS | `width={800} height={600}` |
175
117
  | File name | Keyword signal | `blue-widget-front.webp` |
176
- | Format | Performance + quality | Use WebP/AVIF with JPEG fallback |
177
-
178
- ### Indexability Checklist
118
+ | Format | Performance + quality | WebP/AVIF with JPEG fallback |
179
119
 
180
- - [ ] Primary content renders in initial HTML (view source, not inspect)
181
- - [ ] `<h1>` is unique per page and contains the primary keyword
182
- - [ ] Structured data is present in the server-rendered HTML
183
- - [ ] Images have descriptive `alt` text
184
- - [ ] No `noindex` on pages that should be indexed
185
- - [ ] Hydration does not remove or rewrite structured data scripts
120
+ **Checklist:** primary content in initial HTML · unique `<h1>` with primary keyword · structured data in SSR HTML · descriptive `alt` on all images · no stray `noindex` · hydration preserves structured data scripts.
186
121
 
187
122
  ## Anti-Patterns
188
123
 
189
124
  | Anti-Pattern | Why It's Bad | Correct Approach |
190
125
  |---|---|---|
191
- | Duplicate `<title>` across pages | Dilutes ranking signals; confuses crawlers | Unique, keyword-specific title per page |
192
- | Missing canonical URL | Causes duplicate content penalties | Add `<link rel="canonical">` to every page |
193
- | Client-only rendered content | Googlebot may not execute JS reliably | Server-render all indexable content |
194
- | Hardcoded sitemap file | Goes stale as pages are added/removed | Generate sitemap dynamically from data source |
195
- | Using `noindex` as a "temporary" fix | Often forgotten; pages stay de-indexed | Fix the underlying issue instead |
196
- | Stuffing keywords in meta tags | Penalized by search engines | Write natural, user-focused descriptions |
197
- | Missing `alt` text on images | Lost image search traffic + accessibility failure | Descriptive alt text on every meaningful image |
198
- | Structured data without validation | Silent errors cause rich result loss | Validate with Google Rich Results Test before merge |
199
- | Blocking CSS/JS in `robots.txt` | Prevents Googlebot from rendering the page | Only block admin/API routes |
200
- | Mixed trailing slash URLs | Splits link equity between two URLs | Pick one convention, 301-redirect the other |
126
+ | Duplicate `<title>` | Dilutes ranking signals | Unique, keyword-specific title per page |
127
+ | Missing canonical URL | Duplicate content penalties | Add `<link rel="canonical">` to every page |
128
+ | Client-only rendered content | Googlebot may miss JS | Server-render all indexable content |
129
+ | Hardcoded sitemap | Goes stale | Generate sitemap dynamically |
130
+ | `noindex` as "temporary" fix | Often forgotten | Fix the underlying issue |
131
+ | Keyword stuffing in meta tags | Penalized by search engines | Natural, user-focused descriptions |
132
+ | Missing `alt` on images | Lost image traffic + a11y failure | Descriptive alt on every meaningful image |
133
+ | Unvalidated structured data | Silent errors = rich result loss | Validate with Rich Results Test before merge |
134
+ | Blocking CSS/JS in robots.txt | Prevents page rendering | Only block admin/API routes |
135
+ | Mixed trailing slash URLs | Splits link equity | Pick one convention, 301-redirect other |