nca-ai-cms-astro-plugin 1.0.7 → 1.0.8

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 CHANGED
@@ -88,6 +88,58 @@ ncaAiCms({
88
88
 
89
89
  All `/api/*` and `/editor` routes are protected by cookie-based authentication.
90
90
 
91
+ ## Settings Best Practice
92
+
93
+ The editor has a **Settings** tab with two groups of fields (Homepage and Website) that control how AI generates content. It also has three prompt categories (Content-KI, Analyse-KI, Bild-KI) where you create reusable prompts. Filling these in with values tailored to your business dramatically improves output quality.
94
+
95
+ ### Settings fields
96
+
97
+ | Tab | Field | Key | Description |
98
+ |---|---|---|---|
99
+ | Homepage | Hero Ueberschrift | `hero_headline` | Main headline shown on your homepage |
100
+ | Homepage | Hero Text | `hero_text` | Supporting text below the hero headline |
101
+ | Homepage | Zielgruppe | `target_audience` | Who your content is for (e.g. "CTOs at mid-size SaaS companies") |
102
+ | Homepage | Tonalitaet | `tone` | Voice and tone for generated content (e.g. "professional but approachable") |
103
+ | Homepage | Kernbotschaft | `core_message` | The one key message your site should communicate |
104
+ | Website | CTA Link | `cta_url` | Default call-to-action URL (e.g. "/contact" or "/demo") |
105
+ | Website | CTA Stil | `cta_style` | Style or label for the CTA button (e.g. "Jetzt starten") |
106
+ | Website | CTA Prompt | `cta_prompt` | Prompt text used to generate CTA copy |
107
+ | Website | Core Tags | `core_tags` | Comma-separated keywords for your site (e.g. "AI, CMS, Astro, Open Source") |
108
+ | Website | Markenrichtlinien | `brand_guidelines` | Brand rules the AI should follow (colors, dos/don'ts, terminology) |
109
+
110
+ ### Get values for your business with one AI prompt
111
+
112
+ Copy the prompt below into any AI chat (ChatGPT, Claude, Gemini) and replace the placeholder with a description of your business. You will get ready-to-paste values for every field.
113
+
114
+ ```text
115
+ I run the following business/website:
116
+ [Describe your business in 1-2 sentences, e.g. "An open-source community that organizes charity coding events for nonprofits in Germany."]
117
+
118
+ Please generate values for each of the following content management settings.
119
+ Return them as a simple list so I can copy-paste each value into the corresponding field.
120
+
121
+ 1. hero_headline — A compelling hero headline (max ~10 words)
122
+ 2. hero_text — Supporting hero text (2-3 sentences)
123
+ 3. target_audience — Target audience description (one sentence)
124
+ 4. tone — Tone of voice for all generated content (2-4 descriptive words)
125
+ 5. core_message — Core message / value proposition (1-2 sentences)
126
+ 6. cta_url — Suggested CTA link path (e.g. /contact)
127
+ 7. cta_style — CTA button label text (2-4 words)
128
+ 8. cta_prompt — Short prompt the AI uses to generate CTA copy (one sentence)
129
+ 9. core_tags — 5-8 comma-separated keywords/tags for the site
130
+ 10. brand_guidelines — Brand guidelines for AI-generated content (3-5 bullet points covering tone, terminology, and things to avoid)
131
+ ```
132
+
133
+ ### Prompt categories
134
+
135
+ The three prompt tabs let you create reusable prompts that the AI uses when generating or analysing content.
136
+
137
+ | Category | Purpose | Tips for good prompts |
138
+ |---|---|---|
139
+ | **Content-KI** | Controls how the AI writes blog articles and text | Define word count, structure (intro/sections/CTA), target keywords, and writing style. The more specific, the better. |
140
+ | **Analyse-KI** | Controls how the AI analyses existing text | Specify what to check — SEO, readability, accessibility, keyword density — and ask for concrete improvement suggestions. |
141
+ | **Bild-KI** | Controls how the AI generates images | Describe the visual style, color palette, composition, and aspect ratio. Mention what should *not* appear in the image. |
142
+
91
143
  ## Development
92
144
 
93
145
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nca-ai-cms-astro-plugin",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
@@ -32,21 +32,21 @@ interface SourceAnalysis {
32
32
 
33
33
  // Fallback values when database is not available
34
34
  const DEFAULT_CONTACT_URL =
35
- 'https://nevercodealone.de/de/landingpages/barrierefreies-webdesign';
35
+ 'https://nevercodealone.de/de/kontakt';
36
36
 
37
- const DEFAULT_CORE_TAGS = ['Semantik', 'HTML', 'Barrierefrei'];
37
+ const DEFAULT_CORE_TAGS = ['Web-Entwicklung', 'Best Practices'];
38
38
 
39
39
  const DEFAULT_SYSTEM_PROMPT = `Du bist ein erfahrener technischer Content-Writer für Web-Entwicklung.
40
40
  Deine Aufgabe ist es, hochwertige deutsche Fachartikel zu erstellen.
41
41
 
42
- Zielgruppe: Content-Marketing-Professionals und Frontend-Entwickler
42
+ Zielgruppe: Content-Marketing-Professionals und Entwickler
43
43
  Tonalität: Professionell, aber zugänglich. Technisch korrekt, nicht übermäßig akademisch.
44
44
 
45
45
  KRITISCH - 100% Originalität:
46
46
  - Schreibe einen KOMPLETT EIGENSTÄNDIGEN Artikel
47
47
  - KEINE Sätze, Formulierungen oder Strukturen aus externen Quellen übernehmen
48
48
  - KEINE Hinweise auf Quellen, Referenzen oder Inspiration im Text
49
- - Nutze ausschließlich DEIN Expertenwissen zur Barrierefreiheit
49
+ - Nutze ausschließlich DEIN Expertenwissen zum jeweiligen Thema
50
50
  - Jeder Satz muss NEU formuliert sein - wie von einem Experten geschrieben
51
51
  - Der Artikel muss wirken als käme er aus eigener Fachkenntnis
52
52
 
@@ -57,7 +57,6 @@ Regeln:
57
57
  - WICHTIG: Content MUSS mit einer H1-Überschrift (# Titel) beginnen
58
58
  - Danach H2 (##) und H3 (###) Hierarchie ohne Sprünge
59
59
  - WICHTIG: Nur Markdown, KEINE HTML-Tags wie <p>, <div>, <span> etc.
60
- - WICHTIG: Integriere die Keywords "Semantik", "HTML" und "Barrierefrei" natürlich in den Text
61
60
 
62
61
  Titel-Regeln:
63
62
  - Das Hauptthema/Keyword MUSS im Titel vorkommen
@@ -148,8 +147,10 @@ export class ContentGenerator {
148
147
  private async analyzeSource(
149
148
  fetched: FetchedContent
150
149
  ): Promise<SourceAnalysis> {
150
+ const systemPrompt = await this.buildSystemPrompt();
151
151
  const model = this.client.getGenerativeModel({
152
152
  model: this.model,
153
+ systemInstruction: systemPrompt,
153
154
  generationConfig: {
154
155
  responseMimeType: 'application/json',
155
156
  responseSchema: buildSourceAnalysisSchema(),
@@ -165,7 +166,7 @@ Inhalt:
165
166
  ${fetched.content.slice(0, 12000)}
166
167
 
167
168
  Identifiziere:
168
- 1. Das Hauptthema (fokussiert auf Web-Entwicklung/Barrierefreiheit)
169
+ 1. Das Hauptthema
169
170
  2. Die wichtigsten Kernaussagen
170
171
  3. Besondere Erkenntnisse oder einzigartige Tipps
171
172
  4. Relevante Code-Beispiele oder Patterns`;
@@ -180,23 +181,23 @@ Identifiziere:
180
181
  }
181
182
 
182
183
  private async researchKeywords(keywords: string): Promise<SourceAnalysis> {
184
+ const systemPrompt = await this.buildSystemPrompt();
183
185
  const model = this.client.getGenerativeModel({
184
186
  model: this.model,
187
+ systemInstruction: systemPrompt,
185
188
  generationConfig: {
186
189
  responseMimeType: 'application/json',
187
190
  responseSchema: buildSourceAnalysisSchema(),
188
191
  },
189
192
  });
190
193
 
191
- const prompt = `Du bist ein Experte für Web-Accessibility und barrierefreie Webentwicklung.
192
-
193
- Recherchiere zum Thema: "${keywords}"
194
+ const prompt = `Recherchiere zum Thema: "${keywords}"
194
195
 
195
196
  Nutze dein Fachwissen um:
196
- 1. Das Hauptthema klar zu definieren (Bezug zu Barrierefreiheit/Web-Accessibility)
197
- 2. Die wichtigsten Fakten, Best Practices und WCAG-Richtlinien zusammenzufassen
197
+ 1. Das Hauptthema klar zu definieren
198
+ 2. Die wichtigsten Fakten, Best Practices und Standards zusammenzufassen
198
199
  3. Weniger bekannte aber wichtige Tipps und Erkenntnisse zu identifizieren
199
- 4. Praktische Code-Beispiele oder Patterns vorzuschlagen
200
+ 4. Praktische Beispiele oder Patterns vorzuschlagen
200
201
 
201
202
  Fokussiere auf aktuelle Standards und praktische Anwendbarkeit.`;
202
203
 
@@ -296,13 +297,13 @@ Fokussiere auf aktuelle Standards und praktische Anwendbarkeit.`;
296
297
  }
297
298
 
298
299
  private buildUserPrompt(analysis: SourceAnalysis): string {
299
- return `Schreibe als Accessibility-Experte einen deutschen Fachartikel zum Thema: ${analysis.topic}
300
+ return `Schreibe einen deutschen Fachartikel zum Thema: ${analysis.topic}
300
301
 
301
302
  Behandle diese Aspekte aus deinem Fachwissen:
302
303
  ${analysis.keyPoints.map((p) => `- ${p}`).join('\n')}
303
304
  ${analysis.uniqueInsights.map((p) => `- ${p}`).join('\n')}
304
305
 
305
- ${analysis.codeExamples.length > 0 ? `Zeige praktische Code-Beispiele für:\n${analysis.codeExamples.map((c) => `- ${c}`).join('\n')}` : ''}
306
+ ${analysis.codeExamples.length > 0 ? `Zeige praktische Beispiele für:\n${analysis.codeExamples.map((c) => `- ${c}`).join('\n')}` : ''}
306
307
 
307
308
  Wichtig: Schreibe komplett eigenständig aus deiner Expertise heraus.`;
308
309
  }
@@ -58,10 +58,24 @@ export class PromptService {
58
58
  }
59
59
 
60
60
  async updateSetting(key: string, value: string): Promise<void> {
61
- await db
62
- .update(SiteSettings)
63
- .set({ value, updatedAt: new Date() })
64
- .where(eq(SiteSettings.key, key));
61
+ const existing = await db
62
+ .select()
63
+ .from(SiteSettings)
64
+ .where(eq(SiteSettings.key, key))
65
+ .get();
66
+
67
+ if (existing) {
68
+ await db
69
+ .update(SiteSettings)
70
+ .set({ value, updatedAt: new Date() })
71
+ .where(eq(SiteSettings.key, key));
72
+ } else {
73
+ await db.insert(SiteSettings).values({
74
+ key,
75
+ value,
76
+ updatedAt: new Date(),
77
+ });
78
+ }
65
79
  }
66
80
 
67
81
  async getAllSettings(): Promise<Array<{ key: string; value: string }>> {
@@ -88,11 +102,11 @@ export class PromptService {
88
102
 
89
103
  async getCoreTags(): Promise<string[]> {
90
104
  const tags = await this.getSetting('core_tags');
91
- if (!tags) return ['Semantik', 'HTML', 'Barrierefrei'];
105
+ if (!tags) return ['Web-Entwicklung', 'Best Practices'];
92
106
  try {
93
107
  return JSON.parse(tags);
94
108
  } catch {
95
- return ['Semantik', 'HTML', 'Barrierefrei'];
109
+ return ['Web-Entwicklung', 'Best Practices'];
96
110
  }
97
111
  }
98
112
  }
package/update.md CHANGED
@@ -1,3 +1,20 @@
1
+ # v1.0.8
2
+
3
+ ## Generalize content generator for any topic
4
+ - Removed hardcoded accessibility/Barrierefreiheit references from all prompts
5
+ - `analyzeSource` now uses `systemInstruction` consistently with `researchKeywords` and `generateContent`
6
+ - Default system prompt uses topic-agnostic language ("zum jeweiligen Thema" instead of "zur Barrierefreiheit")
7
+ - Removed hardcoded keyword integration rule from default system prompt
8
+ - Default core tags changed from accessibility-specific to general (`Web-Entwicklung`, `Best Practices`)
9
+ - Default contact URL updated to generic contact page
10
+ - Domain specialization now lives entirely in configurable database prompts
11
+
12
+ ## Fix: updateSetting upsert
13
+ - `PromptService.updateSetting()` now inserts if key doesn't exist instead of silently doing nothing
14
+ - Enables creating new settings through the settings UI without pre-seeding the database
15
+
16
+ ---
17
+
1
18
  # v1.0.6
2
19
 
3
20
  ## Separate settings from prompts in SettingsTab