Skip to content

Commit 7ec5754

Browse files
authored
Merge pull request #293 from OpenElements/origin/actions-auto
Enhance documentation for blog post creation and content structure
2 parents 5305bdf + 6875f20 commit 7ec5754

8 files changed

Lines changed: 237 additions & 78 deletions

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Netlify builds run `pnpm install` and `pnpm run build` (see `netlify.toml`).
9191

9292
## Documentation
9393

94-
- **[Docs Hub](docs/README.md)** - First stop for contributors (repo overview, content guide, first contribution checklist, automation)
95-
- **[Adding New Pages Guide](ADDING_PAGES.md)** - Complete guide on how to add new pages with EN/DE versions, including image handling and layout options
94+
- **[Docs Hub](docs/README.md)** - First stop for contributors (repository architecture, content workflows, quality checks)
95+
- **[Adding Blog Posts](docs/04-adding-blog-post.md)** - Post-specific workflow for `content/posts/`, front matter, and `/posts/...` linking conventions
96+
- **[Adding New Pages Guide](ADDING_PAGES.md)** - Legacy page-creation guide with EN/DE examples and image/layout notes
9697

docs/02-content-folder.md

Lines changed: 86 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ content/posts/
7272

7373
**Usage**: Blog articles, release notes, announcements
7474

75+
For a complete, post-specific workflow (including front matter and link conventions), see [04 - Adding Blog Posts](./04-adding-blog-post.md).
76+
7577
### Pattern 3: Version Updates CHANGELOG
7678

7779
Release notes and version updates use semantic versioning for organization.
@@ -117,21 +119,26 @@ Every markdown file begins with YAML front matter enclosed by `---` delimiters.
117119

118120
### Common Front Matter Fields
119121

120-
| Field | Type | Purpose | Example |
121-
|-------|------|---------|---------|
122-
| `title` | String | Page title displayed in browser tab and page header | `"Getting Started with Open Elements"` |
123-
| `description` | String | SEO description for search results and social sharing | `"Learn how to set up and use Open Elements in your projects"` |
124-
| `layout` | String | Template/layout used for rendering (defines page structure) | `"article"`, `"page"`, `"post"` |
125-
| `url` | String | URL path for the page (must match routing structure) | `"/getting-started"` or `"/de/getting-started"` |
126-
| `keywords` | Array | SEO keywords for search optimization | `["open-elements", "tutorial", "setup"]` |
127-
| `aliases` | Array | Alternative URLs that redirect to this page (for migrations) | `["/old-path", "/another-path"]` |
128-
| `date` | String | Publication or creation date in YYYY-MM-DD format | `"2024-02-25"` |
129-
| `author` | String | Content author name (for blog posts) | `"John Smith"` |
130-
| `newsletterPopup` | Boolean | Whether to show newsletter signup popup | `true` or `false` |
131-
132-
### Minimum Required Front Matter
133-
134-
Every content file must include these fields at minimum:
122+
Different content types use different metadata shapes.
123+
124+
| Field | Type | Primary Use | Example |
125+
|-------|------|-------------|---------|
126+
| `title` | String | Pages and posts | `"Getting Started with Open Elements"` |
127+
| `description` | String | Standard pages (SEO) | `"Learn how to set up and use Open Elements"` |
128+
| `layout` | String | Standard pages | `"article"`, `"single"`, `"contact"` |
129+
| `url` | String | Standard pages only | `"/getting-started"` or `"/de/getting-started"` |
130+
| `keywords` | Array | Standard pages (optional SEO) | `["open-elements", "tutorial", "setup"]` |
131+
| `aliases` | Array | Standard pages redirects | `["/old-path", "/another-path"]` |
132+
| `newsletterPopup` | Boolean | Standard pages where needed | `true` or `false` |
133+
| `date` | String | Blog posts (publication date) | `"2024-02-25"` |
134+
| `author` | String | Blog posts (team id) | `"hendrik"` |
135+
| `excerpt` | String | Blog posts (listing/meta summary) | `"Short preview for cards"` |
136+
| `categories` | Array | Blog posts (tags) | `["open-source", "maven"]` |
137+
| `preview_image` | String | Blog posts card/OG image | `"/posts/preview-images/open-source-green.svg"` |
138+
| `showInBlog` | Boolean | Blog posts visibility filter | `true` or `false` |
139+
| `outdated` | Boolean | Blog posts visibility filter | `false` |
140+
141+
### Minimum Required Front Matter for Standard Pages
135142

136143
```yaml
137144
---
@@ -142,39 +149,54 @@ url: "/page-slug"
142149
---
143150
```
144151

152+
### Minimum Required Front Matter for Blog Posts
153+
154+
```yaml
155+
---
156+
outdated: false
157+
showInBlog: true
158+
title: "How to Build Scalable Java Applications"
159+
date: 2024-02-25
160+
author: hendrik
161+
excerpt: "Discover best practices and patterns for scalable Java applications."
162+
categories: [java, scalability, performance, architecture]
163+
preview_image: "/posts/preview-images/software-development-green.svg"
164+
---
165+
```
166+
145167
### Front Matter Best Practices
146168

147169
- **Title**: Keep it concise (50-60 characters), clear, and descriptive
148-
- **Description**: Write for search engines (160 characters max), include key terms
149-
- **URL**: Must match the actual route and locale prefix (`/de/...` for German)
150-
- **Keywords**: Use 3-7 relevant keywords, separated by commas in array format
151-
- **Dates**: Use ISO 8601 format (YYYY-MM-DD) for consistency
170+
- **Description**: Use on standard pages for SEO metadata (150-160 characters)
171+
- **URL**: Use on standard pages only; must match route and locale prefix for German (`/de/...`)
172+
- **Dates**: Use ISO 8601 format (`YYYY-MM-DD`) for posts
173+
- **Author IDs**: Use team ids that exist in `src/data/en/team.json` and `src/data/de/team.json`
174+
- **Post Images**: Use web paths (for example `/posts/...`), never filesystem paths
152175

153176
### Example Front Matter
154177

155-
**English Blog Post:**
178+
**Standard Page (EN):**
156179
```yaml
157180
---
158-
title: "How to Build Scalable Java Applications"
159-
description: "Discover best practices and patterns for building scalable Java applications in production environments"
160-
layout: "post"
161-
url: "/blog/scalable-java"
162-
keywords: ["java", "scalability", "performance", "architecture"]
163-
author: "Jane Developer"
164-
date: "2024-02-25"
181+
title: "Frequently Asked Questions"
182+
description: "Find answers to common questions about Open Elements."
183+
layout: "article"
184+
url: "/faq"
185+
keywords: ["faq", "help", "support"]
165186
---
166187
```
167188

168-
**German Translation of Same Post:**
189+
**Blog Post (EN):**
169190
```yaml
170191
---
171-
title: "Skalierbare Java-Anwendungen entwickeln"
172-
description: "Entdecken Sie Best Practices und Muster für die Entwicklung skalierbarer Java-Anwendungen in Produktionsumgebungen"
173-
layout: "post"
174-
url: "/de/blog/skalierbare-java"
175-
keywords: ["java", "skalierbarkeit", "performance", "architektur"]
176-
author: "Jane Developer"
177-
date: "2024-02-25"
192+
outdated: false
193+
showInBlog: true
194+
title: "How to Build Scalable Java Applications"
195+
date: 2024-02-25
196+
author: hendrik
197+
excerpt: "Discover best practices and patterns for scalable Java applications."
198+
categories: [java, scalability, performance, architecture]
199+
preview_image: "/posts/preview-images/software-development-green.svg"
178200
---
179201
```
180202

@@ -208,14 +230,15 @@ content/posts/
208230
### Parity Requirements
209231

210232
**User-Facing Pages**
211-
- Pages visible to end users must maintain structural parityBetween English and German
233+
- Pages visible to end users must maintain structural parity between English and German
212234
- Both language versions must exist before merging the PR
213235
- Update simultaneous in the same PR rather than separate PRs
214236

215237
**Content Structure Parity**
216-
- Headings, section organization should match between EN and DE versions
217-
- Same media (images, etc.) referenced in both versions
218-
- Front matter structure identical except for `url` (includes `/de/` prefix) and translated `title`/`description`
238+
- Headings and section organization should match between EN and DE versions
239+
- Same media (images, etc.) should generally be referenced in both versions
240+
- For standard pages: front matter structure is identical except localized `title`/`description` and `url` with `/de/` prefix
241+
- For blog posts: front matter fields should stay aligned across locales while keeping translated text in `title` and `excerpt`
219242

220243
**When Single-Language Content is Acceptable**
221244
- Technical documentation or release notes specifically for developers
@@ -229,7 +252,7 @@ When translating content from English to German:
229252
1. **Maintain Meaning**: Preserve semantic meaning even if literal translation doesn't fit
230253
2. **Preserve Formatting**: Keep heading levels, lists, code blocks identical
231254
3. **Terminology**: Use consistent terminology across all German content
232-
4. **Links**: Update internal links to use German routing (`/de/...`)
255+
4. **Links**: Update internal links to use German routing (`/de/...` for standard pages, `/de/posts/...` for blog posts)
233256
5. **Date Format**: Adapt date formatting if appropriate for German audience
234257

235258
## URL and SEO Configuration
@@ -238,11 +261,11 @@ When translating content from English to German:
238261

239262
**English URLs:**
240263
- Start with `/` immediately (no locale prefix)
241-
- Examples: `/about`, `/blog/post-title`, `/contact`
264+
- Examples: `/about`, `/posts/2024-02-25-post-title`, `/contact`
242265

243266
**German URLs:**
244267
- Include `/de/` at the beginning
245-
- Examples: `/de/about`, `/de/blog/post-title`, `/de/kontakt`
268+
- Examples: `/de/about`, `/de/posts/2024-02-25-post-title`, `/de/kontakt`
246269

247270
### URL Naming Rules
248271

@@ -251,18 +274,22 @@ When translating content from English to German:
251274
- If a URL change is necessary, implement 301 redirects or use `aliases` in front matter
252275

253276
2. **Consistency**: Use lowercase letters and hyphens (kebab-case)
254-
-`/blog/new-release`
255-
-`/blog/New_Release`
256-
-`/blog/NewRelease`
277+
-`/posts/2024-02-25-new-release`
278+
-`/posts/2024-02-25-New_Release`
279+
-`/posts/2024-02-25-NewRelease`
257280

258281
3. **Descriptiveness**: URLs should indicate content topic
259-
-`/blog/performance-optimization-tips`
260-
-`/blog/post-123`
261-
-`/blog/article-1`
282+
-`/posts/2024-02-25-performance-optimization-tips`
283+
-`/posts/2024-02-25-post-123`
284+
-`/posts/2024-02-25-article-1`
285+
286+
4. **Front Matter URL Field (Standard Pages Only)**: Must exactly match the route structure
287+
- English page: `"url": "/about"`
288+
- German page: `"url": "/de/about"`
262289

263-
4. **Front Matter URL Field**: Must exactly match the route structure
264-
- English: `"url": "/blog/my-post"`
265-
- German: `"url": "/de/blog/my-post"`
290+
5. **Blog Post URL Source**: URL is derived from filename
291+
- English file: `content/posts/2024-02-25-my-post.md` -> `/posts/2024-02-25-my-post`
292+
- German file: `content/posts/2024-02-25-my-post.de.md` -> `/de/posts/2024-02-25-my-post`
266293

267294
### SEO Best Practices
268295

@@ -363,7 +390,7 @@ When referencing assets in markdown or JSX, use **web paths only** (not filesyst
363390
| Mistake | ❌ Wrong | ✅ Right | Impact |
364391
|---------|---------|---------|--------|
365392
| Asset path with `public/` | `![](/public/img.png)` | `![](/img.png)` | Assets won't load |
366-
| Wrong URL in front matter | `url: "/about"` (EN) | `url: "/de/about"` (DE) | Broken routing for German version |
393+
| Wrong localized page URL in front matter | `url: "/about"` in `index.de.md` | `url: "/de/about"` in `index.de.md` | Broken routing for German version |
367394
| Inconsistent heading hierarchy | Skip from H2 to H4 | H2 → H3 → H4 | SEO and accessibility issues |
368395
| Inconsistent filename patterns | Mix `.md` and `.en.md` | Use `.md` and `.de.md` consistently | Localization breaks |
369396
| Removing old aliases | Delete `aliases` field | Keep for backward compatibility | Broken external links and SEO loss |
@@ -389,14 +416,16 @@ Before submitting a pull request with content changes, systematically verify eac
389416

390417
- [ ] **Front Matter**:
391418
- YAML is syntactically valid (no indentation errors)
392-
- All required fields present: `title`, `description`, `layout`, `url`
393-
- `url` field exactly matches the route structure
419+
- Standard pages include required fields: `title`, `description`, `layout`, `url`
420+
- Blog posts include required fields: `title`, `date`, `author`, `excerpt`, `categories`, `preview_image`
421+
- If blog post visibility is intentional, `showInBlog` and `outdated` are set correctly
394422

395423
- [ ] **Localization Parity**:
396-
- Both English and German versions exist
424+
- Standard pages: both English and German versions exist
425+
- Blog posts: German translation is added when user-facing and intended for DE listing
397426
- Content is structurally similar between language versions
398-
- `url` fields differ only in `/de/` prefix
399-
- Titles and descriptions are properly translated
427+
- Standard page `url` fields differ only in `/de/` prefix
428+
- Localized text fields are translated (`title`, `description` for pages; `title`, `excerpt` for posts)
400429

401430
- [ ] **SEO Optimization**:
402431
- `title`: 50-60 characters, descriptive, includes keyword

docs/03-adding-pages.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ This comprehensive guide walks you through the entire process of adding a new pa
99
Before starting, ensure you're familiar with:
1010
- [01 - Repository Overview](./01-repo-overview.md): Project structure and technology stack
1111
- [02 - Content Folder Guide](./02-content-folder.md): Content organization, front matter standards, and localization
12+
- [04 - Adding Blog Posts](./04-adding-blog-post.md): Use this instead when your change is in `content/posts/`
1213
- Basic Next.js App Router concepts (routes, layouts, page components)
1314

15+
This guide is for standard pages (`content/<slug>/index.md` + route files).
16+
For posts in `content/posts/`, follow [04 - Adding Blog Posts](./04-adding-blog-post.md).
17+
1418
## Step-by-Step Implementation Workflow
1519

1620
### Step 1: Create Markdown Content Files

docs/04-adding-blog-post.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# 04 - Adding Blog Posts
2+
3+
## Purpose
4+
5+
This guide documents the exact workflow for adding posts to the Open Elements article section.
6+
7+
Use this guide for anything under `content/posts/`.
8+
For standard pages (for example `content/about/index.md`), use [03 - Adding Pages](./03-adding-pages.md).
9+
10+
## 1. Create Post Files
11+
12+
Blog posts are flat files in `content/posts/`:
13+
14+
```text
15+
content/posts/
16+
YYYY-MM-DD-post-slug.md
17+
YYYY-MM-DD-post-slug.de.md
18+
```
19+
20+
- English file: `YYYY-MM-DD-post-slug.md`
21+
- German translation: `YYYY-MM-DD-post-slug.de.md` (recommended for user-facing content)
22+
23+
Example:
24+
25+
```text
26+
content/posts/2026-02-27-dependency-health-checks.md
27+
content/posts/2026-02-27-dependency-health-checks.de.md
28+
```
29+
30+
The URL slug is derived from the filename:
31+
32+
- `2026-02-27-dependency-health-checks.md` -> `/posts/2026-02-27-dependency-health-checks`
33+
- `2026-02-27-dependency-health-checks.de.md` -> `/de/posts/2026-02-27-dependency-health-checks`
34+
35+
## 2. Add Front Matter (Required Fields)
36+
37+
Posts in this repository are parsed by `src/lib/markdown.ts` and must use this schema:
38+
39+
```yaml
40+
---
41+
outdated: false
42+
showInBlog: true
43+
title: "Dependency Health Checks for Maven Builds"
44+
date: 2026-02-27
45+
author: sebastian
46+
excerpt: "A short teaser shown in article cards and metadata."
47+
categories: [open-source, maven, security]
48+
preview_image: "/posts/preview-images/open-source-green.svg"
49+
---
50+
```
51+
52+
Field notes:
53+
54+
- `title`: display title and SEO title base
55+
- `date`: `YYYY-MM-DD`
56+
- `author`: author id (not free text). Match an id in `src/data/en/team.json` and `src/data/de/team.json`
57+
- `excerpt`: used in listing cards and metadata description
58+
- `categories`: array rendered as tags
59+
- `preview_image`: web path under `public/`
60+
- `showInBlog`: set `false` to hide from listing pages
61+
- `outdated`: set `true` to hide from listing pages
62+
63+
## 3. Write Content and Use Correct Links
64+
65+
Write markdown below the front matter. Keep heading structure consistent between EN/DE versions.
66+
67+
Internal link rules:
68+
69+
- Standard pages:
70+
- EN: `/about`, `/contact`
71+
- DE: `/de/about`, `/de/contact`
72+
- Blog posts:
73+
- EN: `/posts/<YYYY-MM-DD-slug>`
74+
- DE: `/de/posts/<YYYY-MM-DD-slug>`
75+
76+
Do not use `/blog/...` in new content. The active route is `/posts/...`.
77+
78+
## 4. Add Images
79+
80+
Store post-specific assets in a folder matching the post slug:
81+
82+
```text
83+
public/posts/2026-02-27-dependency-health-checks/
84+
architecture.png
85+
pipeline-diff.png
86+
```
87+
88+
Reference them with web paths:
89+
90+
```markdown
91+
![Pipeline comparison](/posts/2026-02-27-dependency-health-checks/pipeline-diff.png)
92+
```
93+
94+
## 5. Validate Locally
95+
96+
1. Run `pnpm run dev`
97+
2. Open:
98+
- EN listing: `http://localhost:3000/posts`
99+
- DE listing: `http://localhost:3000/de/posts`
100+
- EN post: `http://localhost:3000/posts/<slug>`
101+
- DE post: `http://localhost:3000/de/posts/<slug>`
102+
3. Verify preview image, excerpt, categories, author card, and all links
103+
104+
## 6. Common Pitfalls
105+
106+
- Wrong route prefix in links (`/blog/...` instead of `/posts/...`)
107+
- Missing `.de.md` suffix for German files
108+
- `author` not matching a team id
109+
- Using filesystem-like image paths (`public/...`) instead of web paths (`/...`)
110+
- Missing `excerpt` or `preview_image`, causing weak list cards and metadata
111+
112+
## Related Docs
113+
114+
- [02 - Content Folder Guide](./02-content-folder.md)
115+
- [05 - First Contribution Checklist](./05-first-contribution-checklist.md)
116+
- [06 - Testing and Quality Checks](./06-testing-and-quality-checks.md)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 04 - First Contribution Checklist
1+
# 05 - First Contribution Checklist
22

33
## Purpose and Scope
44

@@ -438,4 +438,4 @@ git push origin fix/issue-123-description
438438
- **Stuck on implementation?** → Check [01 - Repository Overview](./01-repo-overview.md)
439439
- **Content structure unclear?** → See [02 - Content Folder Guide](./02-content-folder.md)
440440
- **Adding a new page?** → Follow [03 - Adding Pages](./03-adding-pages.md)
441-
- **Build or test failures?** → Check [05 - Testing and Quality Checks](./05-testing-and-quality-checks.md)
441+
- **Build or test failures?** → Check [06 - Testing and Quality Checks](./06-testing-and-quality-checks.md)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 05 - Testing and Quality Checks
1+
# 06 - Testing and Quality Checks
22

33
## Overview
44

0 commit comments

Comments
 (0)