Major changes: - Replace Payload CMS with Tina CMS (self-hosted) - Add Astro DB for consent logging (PDPA compliant) - Update Tailwind v3 to v4 (@tailwindcss/vite plugin) - Add astro-tina-starter template - Rewrite consent template for Astro (ConsentBanner.astro, Astro DB, Nano Stores) - Add install-tina-backend.sh for self-hosted Tina per customer - Rename convert-astro.sh to migrate-tina.sh - Add AGENTS.md template for generated websites - Delete all Payload/Next.js files Technical updates: - Astro DB using defineDb with eq operators for queries - Tailwind v4 with @theme block - Tina CMS local development mode - Proper Astro API routes for consent Research-verified with official documentation (April 2026)
193 lines
3.9 KiB
YAML
193 lines
3.9 KiB
YAML
# Blog SEO Article Template
|
|
channel: blog
|
|
priority: 4
|
|
language: [th, en]
|
|
|
|
# Article structure
|
|
structure:
|
|
min_word_count:
|
|
thai: 1500
|
|
english: 2000
|
|
max_word_count:
|
|
thai: 3000
|
|
english: 3000
|
|
keyword_density:
|
|
thai: 1.0-1.5%
|
|
english: 1.5-2.0%
|
|
|
|
sections:
|
|
- introduction:
|
|
word_count: 150-250
|
|
must_include:
|
|
- hook
|
|
- problem_statement
|
|
- promise
|
|
- primary_keyword_in_first_100_words
|
|
|
|
- body:
|
|
h2_sections: 4-7
|
|
h3_subsections: "as needed"
|
|
keyword_in_h2: "at least 2-3"
|
|
|
|
- conclusion:
|
|
word_count: 150-250
|
|
must_include:
|
|
- summary_of_key_points
|
|
- primary_keyword
|
|
- call_to_action
|
|
|
|
- cta_placement:
|
|
recommended_locations:
|
|
- after_first_value_section
|
|
- after_comparison_proof_section
|
|
- at_end
|
|
min_cta_count: 2
|
|
max_cta_count: 4
|
|
|
|
# Frontmatter requirements
|
|
frontmatter:
|
|
required_fields:
|
|
- title: 50-60 chars
|
|
- description: 150-160 chars (meta description)
|
|
- keywords: array of 5-10 keywords
|
|
- slug: url-friendly
|
|
- lang: th_or_en
|
|
- category: string
|
|
- tags: array of strings
|
|
- created: "YYYY-MM-DD"
|
|
- author: string_optional
|
|
|
|
optional_fields:
|
|
- updated: "YYYY-MM-DD"
|
|
- draft: boolean
|
|
- featured: boolean
|
|
- image:
|
|
src: path
|
|
alt: string
|
|
caption: string
|
|
|
|
# SEO requirements
|
|
seo:
|
|
meta_title:
|
|
min_chars: 50
|
|
max_chars: 60
|
|
must_include_primary_keyword: true
|
|
|
|
meta_description:
|
|
min_chars: 150
|
|
max_chars: 160
|
|
must_include_primary_keyword: true
|
|
must_include_cta: true
|
|
|
|
url_slug:
|
|
max_words: 5
|
|
format: "lowercase-with-hyphens"
|
|
include_primary_keyword: true
|
|
thai: "use_transliteration_or_keep_thai"
|
|
|
|
headings:
|
|
h1:
|
|
count: 1
|
|
include_primary_keyword: true
|
|
|
|
h2:
|
|
count: 4-7
|
|
include_keyword_variations: "2-3 minimum"
|
|
|
|
h3:
|
|
count: "as needed"
|
|
proper_nesting: true
|
|
|
|
internal_links:
|
|
min_count: 3
|
|
max_count: 7
|
|
anchor_text: "descriptive_with_keywords"
|
|
|
|
external_links:
|
|
min_count: 2
|
|
max_count: 4
|
|
authority_sources_only: true
|
|
|
|
images:
|
|
min_count: 2
|
|
max_count: 10
|
|
alt_text_required: true
|
|
descriptive_filenames: true
|
|
compressed: true
|
|
|
|
# Image handling for blog
|
|
images:
|
|
hero_image:
|
|
required: true
|
|
size: "1200x630"
|
|
location: "public/images/blog/{slug}/hero.png"
|
|
|
|
inline_images:
|
|
recommended_frequency: "every 300-400 words"
|
|
size: "800x600 or 1080x1080"
|
|
location: "public/images/blog/{slug}/"
|
|
|
|
generation:
|
|
for_product_content: "browse_repo_then_image_edit"
|
|
for_non_product: "image_generation"
|
|
|
|
# Content quality requirements
|
|
quality:
|
|
min_score: 70
|
|
checks:
|
|
- keyword_optimization
|
|
- brand_voice_alignment
|
|
- thai_formality_level
|
|
- readability_score
|
|
- factual_accuracy
|
|
- actionability
|
|
- originality
|
|
|
|
readability:
|
|
thai:
|
|
avg_sentence_length: "15-25 words"
|
|
grade_level: "ม.6-ม.12"
|
|
formality: "auto-detect_from_context"
|
|
|
|
english:
|
|
flesch_reading_ease: "60-70"
|
|
flesch_kincaid_grade: "8-10"
|
|
avg_sentence_length: "15-20 words"
|
|
|
|
# Output configuration
|
|
output:
|
|
format: markdown_with_frontmatter
|
|
encoding: "utf-8"
|
|
line_endings: "unix"
|
|
|
|
payload_cms_integration:
|
|
collection: "posts"
|
|
language_prefix:
|
|
thai: "th/"
|
|
english: ""
|
|
image_collection: "media"
|
|
|
|
publishing:
|
|
auto_publish: "optional (user_choice)"
|
|
git_commit: true
|
|
git_push: true
|
|
trigger_deploy: true
|
|
|
|
# API readiness (for future CMS integration)
|
|
api_ready:
|
|
cms_compatible:
|
|
- "WordPress"
|
|
- "Contentful"
|
|
- "Sanity"
|
|
- "Strapi"
|
|
|
|
schema_org:
|
|
type: "BlogPosting"
|
|
required_fields:
|
|
- headline
|
|
- description
|
|
- image
|
|
- datePublished
|
|
- author
|
|
- publisher
|