Skip to main content

Content Schema Reference

Complete reference for content and course data structures.

Content Table Fields

All content (blog posts, tutorials, case studies) use these fields:

Core Fields

FieldTypeRequiredDescription
idUUIDUnique content identifier
titleString(300)Content title (max 100 chars display)
slugStringURL-friendly identifier (auto-generated)
descriptionTextShort description (300-500 chars)
contentJSONTiptap JSON content (rich text)
excerptStringFirst ~150 chars of content
featured_image_urlURLHero/thumbnail image URL
statusENUMdraft | published | archived

Organization

FieldTypeRequiredDescription
category_idUUIDForeign key to category table
author_idUUIDContent creator user ID
tagsArraySearch tags for filtering
sectionStringContent section (homepage_meta, hero, pillar, etc)

Content Details

FieldTypeRequiredDescription
read_timeIntegerEstimated read time (minutes)
word_countIntegerTotal word count
languageStringISO language code (default: en)
featuredBooleanShow on homepage featured section
positionIntegerDisplay order in lists

Engagement

FieldTypeRequiredDescription
view_countIntegerTotal views (incremented per view)
like_countIntegerTotal likes
bookmark_countIntegerTotal bookmarks

Metadata

FieldTypeDescription
seo_titleString(60)SEO title (different from display title)
seo_descriptionString(160)Meta description for search engines
seo_keywordsArrayKeywords for SEO
created_atTimestampAuto-set creation date
updated_atTimestampAuto-updated on changes
published_atTimestampWhen content was published

Content Interactions

Tracks user engagement with content:

FieldTypeDescription
idUUIDInteraction ID
user_idUUIDUser who interacted
content_idUUIDContent interacted with
interaction_typeENUMview | like | bookmark
created_atTimestampWhen interaction occurred

Categories

Content organization:

FieldTypeDescription
idUUIDCategory ID
nameStringCategory name (e.g., "AI Agents", "Tutorials")
slugStringURL-friendly category slug
descriptionStringCategory description
colorStringHex color code for UI
iconStringIcon name or emoji
positionIntegerDisplay order

Courses & Tracks

Courses (Nova Tracks)

FieldTypeRequiredDescription
idUUIDCourse ID
titleStringCourse title
slugStringURL slug (auto-generated)
descriptionStringCourse description
thumbnail_urlURLCourse image
instructor_nameStringInstructor name
levelENUMbeginner | intermediate | advanced
statusENUMdraft | coming_soon | published

Course Details

FieldTypeRequiredDescription
estimated_hoursDecimalCourse duration estimate
pricing_tierStringfree | pro | enterprise
course_codeStringInternal course code
categoryStringCourse category
positionIntegerDisplay order in course list

Lessons

FieldTypeRequiredDescription
idUUIDLesson ID
track_idUUIDParent course ID
titleStringLesson title
contentJSONLesson content (Tiptap JSON)
video_urlURLYouTube video URL
video_durationIntegerVideo length (seconds)
orderIntegerDisplay order within course
created_atTimestampCreation timestamp

Enrollments & Progress

Enrollments

FieldTypeDescription
idUUIDEnrollment ID
user_idUUIDEnrolled user
track_idUUIDCourse enrolled in
enrolled_atTimestampEnrollment date
statusENUMactive | completed | paused

Lesson Progress

FieldTypeDescription
idUUIDProgress record ID
user_idUUIDUser's progress
lesson_idUUIDLesson being tracked
video_watch_timeIntegerSeconds watched
completedBooleanLesson completed?
completed_atTimestampCompletion timestamp

JSON Data Structures

Content JSON (Tiptap)

Content is stored as Tiptap editor JSON format:

{
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Paragraph text here"
}
]
},
{
"type": "heading",
"attrs": {
"level": 2
},
"content": [
{
"type": "text",
"text": "Heading text"
}
]
}
]
}

Content Metadata JSON

{
"seo_title": "SEO title",
"seo_description": "Meta description",
"seo_keywords": ["keyword1", "keyword2"],
"og_image": "https://...",
"og_type": "article"
}

Validation Rules

Content Fields

{
title: {
required: true,
maxLength: 300,
minLength: 3,
pattern: /^[a-zA-Z0-9\s\-.,'"!?:;()]+$/
},
description: {
required: true,
maxLength: 500,
minLength: 50
},
slug: {
required: true,
pattern: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,
unique: true
},
status: {
required: true,
enum: ["draft", "published", "archived"]
}
}

Course Fields

{
title: {
maxLength: 200,
minLength: 5
},
estimated_hours: {
type: "number",
min: 0,
max: 1000
},
level: {
enum: ["beginner", "intermediate", "advanced"]
}
}

Best Practices

For Content

  1. Titles: Keep under 100 chars for display (use SEO title separately)
  2. Descriptions: 300-500 chars, write for search snippets
  3. Images: Use Cloudinary URLs with transformations
  4. Content: Use Tiptap JSON, avoid raw HTML
  5. Tags: Keep 3-5 relevant tags per piece

For Courses

  1. Course Code: Use format like "AI-001", "WEB-202"
  2. Slug: Auto-generate from title, but can customize
  3. Thumbnail: Use 16:9 aspect ratio (1280x720)
  4. Description: Include learning outcomes
  5. Hours: Estimate conservatively

For Lessons

  1. Video Duration: Parse from YouTube API
  2. Content: Rich formatting using Tiptap
  3. Order: Use sequential numbers (1, 2, 3...)
  4. Watch Time: 90% watched = completed

Database Relationships

users
├── enrollments (many)
├── content (authored, many)
├── lesson_progress (many)
└── user_profiles

categories
└── content (many)

content
├── user (author)
├── category
├── content_interactions (many)
└── homepage_sections

tracks (courses)
├── lessons (many)
├── enrollments (many)
└── certificates (many)

lessons
├── track (parent course)
├── lesson_progress (many)
└── video_metadata

contentCategories
└── content (many)

Last Updated: 2025-12-24