api-requirements-catalog.js•14.6 kB
#!/usr/bin/env node
/**
* API Requirements Catalog
* Provides Claude with precise API field names and format requirements
* Prevention-first approach: Get it right the first time instead of fixing later
*/
export class APIRequirementsCatalog {
constructor() {
this.apiFieldMappings = this.buildAPIFieldMappings();
this.preciseExamples = this.buildPreciseExamples();
this.commonMistakes = this.buildCommonMistakes();
}
/**
* Get comprehensive API requirements for Claude
*/
getAPIRequirementsForClaude() {
return {
introduction: `CRITICAL: Use these EXACT field names and formats to prevent API errors.
The EuConquisto Composer API has specific requirements that must be followed precisely.
Using incorrect field names will cause 500 errors and workflow failure.`,
widgetAPIRequirements: this.apiFieldMappings,
workingExamples: this.preciseExamples,
commonMistakes: this.commonMistakes,
criticalReminders: [
"Quiz questions: Use 'options' array with 'correct_option' index (API will convert to 'answers')",
"List widgets: Use 'items' array (API will convert to 'list_items')",
"Hotspots: Use numeric coordinates like 50, 30 (API will convert to '50%', '30%')",
"Flashcards: Use 'flashcards_items' array with 'question'/'answer' or 'front'/'back'",
"All text content: Minimum 20 characters for validation",
"URLs: Must be complete valid URLs starting with https://"
],
validationRequirements: {
minimumContent: "All text fields need minimum 20 characters",
requiredFields: "Missing required fields will cause validation errors",
fieldTypes: "Use correct data types (strings, numbers, arrays, objects)",
urlFormat: "All URLs must be valid and accessible"
}
};
}
/**
* Precise API field mappings with exact requirements
*/
buildAPIFieldMappings() {
return {
'head-1': {
apiName: 'head-1',
description: 'Professional lesson header - always use as first widget',
requiredFields: {
category: {
type: 'string',
format: 'Plain text or HTML',
example: '"CIÊNCIAS" or "<p>BIOLOGIA</p>"',
apiFieldName: 'category'
},
author_name: {
type: 'string',
format: 'Plain text or HTML',
example: '"Professor João" or "<p>Professor João</p>"',
apiFieldName: 'author_name'
}
},
optionalFields: {
author_office: {
type: 'string',
format: 'Plain text or HTML',
example: '"Especialista em Biologia"',
apiFieldName: 'author_office'
},
background_image: {
type: 'string',
format: 'Valid URL',
example: '"https://images.unsplash.com/photo-1234567890"',
apiFieldName: 'background_image'
},
avatar: {
type: 'string',
format: 'Valid URL',
example: '"https://ui-avatars.com/api/?name=Professor"',
apiFieldName: 'avatar'
}
}
},
'text-1': {
apiName: 'text-1',
description: 'Rich HTML content display',
requiredFields: {
text: {
type: 'string',
format: 'HTML content, minimum 20 characters',
example: '"<h2>Título</h2><p>Conteúdo educacional detalhado...</p>"',
apiFieldName: 'text',
validation: 'Must be at least 20 characters long'
}
},
optionalFields: {
content_title: {
type: 'string',
format: 'Plain text title',
example: '"Introdução à Fotossíntese"',
apiFieldName: 'content_title'
},
background_color: {
type: 'string',
format: 'Hex color code',
example: '"#FFFFFF"',
apiFieldName: 'background_color'
}
}
},
'quiz-1': {
apiName: 'quiz-1',
description: 'Interactive multiple-choice quiz',
requiredFields: {
questions: {
type: 'array',
format: 'Array of question objects',
apiFieldName: 'questions',
itemStructure: {
question: {
type: 'string',
format: 'Question text, minimum 10 characters',
example: '"Qual é o principal produto da fotossíntese?"',
apiFieldName: 'question'
},
options: {
type: 'array',
format: 'Array of answer choices (will become "answers" in API)',
example: '["Oxigênio", "Glicose", "Água", "CO2"]',
apiFieldName: 'options',
apiConversion: 'Converted to "answers" field in API'
},
correct_option: {
type: 'number',
format: 'Zero-based index of correct answer',
example: '1 (for second option)',
apiFieldName: 'correct_option'
}
}
}
},
optionalFields: {
max_attempts: {
type: 'number',
format: 'Number between 1-5',
example: '3',
apiFieldName: 'max_attempts'
}
},
criticalNote: 'Use "options" array in your content - API will convert to "answers"'
},
'flashcards-1': {
apiName: 'flashcards-1',
description: 'Interactive flip cards for memorization',
requiredFields: {
flashcards_items: {
type: 'array',
format: 'Array of flashcard objects',
apiFieldName: 'flashcards_items',
itemStructure: {
question: {
type: 'string',
format: 'Front of card content',
example: '"Clorofila"',
apiFieldName: 'question'
},
answer: {
type: 'string',
format: 'Back of card content',
example: '"Pigmento verde que captura luz solar"',
apiFieldName: 'answer'
}
},
alternativeFormat: {
front: 'Can use "front" instead of "question"',
back: 'Can use "back" instead of "answer"'
}
}
}
},
'list-1': {
apiName: 'list-1',
description: 'Structured list of items',
requiredFields: {
items: {
type: 'array',
format: 'Array of strings (will become "list_items" in API)',
example: '["Item 1", "Item 2", "Item 3"]',
apiFieldName: 'items',
apiConversion: 'Converted to "list_items" field in API'
}
},
optionalFields: {
list_type: {
type: 'string',
format: '"bullet", "numbered", or "checkbox"',
example: '"bullet"',
apiFieldName: 'list_type'
}
},
criticalNote: 'Use "items" array in your content - API will convert to "list_items"'
},
'image-1': {
apiName: 'image-1',
description: 'Single image display',
requiredFields: {
image: {
type: 'string',
format: 'Valid image URL',
example: '"https://images.unsplash.com/photo-1234567890"',
apiFieldName: 'image',
validation: 'Must be accessible image URL'
}
},
optionalFields: {
caption: {
type: 'string',
format: 'Image description/caption',
example: '"Processo de fotossíntese em folhas verdes"',
apiFieldName: 'caption'
}
}
},
'video-1': {
apiName: 'video-1',
description: 'Video content display',
requiredFields: {
video: {
type: 'string',
format: 'Valid video URL (YouTube, Vimeo, etc.)',
example: '"https://www.youtube.com/watch?v=dQw4w9WgXcQ"',
apiFieldName: 'video',
validation: 'Must be accessible video URL'
}
}
},
'gallery-1': {
apiName: 'gallery-1',
description: 'Multiple image carousel',
requiredFields: {
slides: {
type: 'array',
format: 'Array of slide objects',
apiFieldName: 'slides',
itemStructure: {
image: {
type: 'string',
format: 'Valid image URL',
example: '"https://images.unsplash.com/photo-1234567890"',
apiFieldName: 'image'
},
caption: {
type: 'string',
format: 'Optional slide description',
example: '"Etapa 1 do processo"',
apiFieldName: 'caption'
}
}
}
}
},
'hotspots-1': {
apiName: 'hotspots-1',
description: 'Interactive image with clickable markers',
requiredFields: {
background_image: {
type: 'string',
format: 'Valid image URL',
example: '"https://images.unsplash.com/photo-1234567890"',
apiFieldName: 'background_image'
},
markers: {
type: 'array',
format: 'Array of marker objects (will become "marcadores" in API)',
apiFieldName: 'markers',
apiConversion: 'Converted to "marcadores" field in API',
itemStructure: {
x: {
type: 'number',
format: 'X coordinate (will become percentage string in API)',
example: '50 (becomes "50%" in API)',
apiFieldName: 'x',
apiConversion: 'Number converted to percentage string'
},
y: {
type: 'number',
format: 'Y coordinate (will become percentage string in API)',
example: '30 (becomes "30%" in API)',
apiFieldName: 'y',
apiConversion: 'Number converted to percentage string'
},
title: {
type: 'string',
format: 'Marker title/label',
example: '"Cloroplasto"',
apiFieldName: 'title'
},
content: {
type: 'string',
format: 'Marker popup content',
example: '"Organela responsável pela fotossíntese"',
apiFieldName: 'content'
}
}
}
},
criticalNote: 'Use numeric coordinates (50, 30) - API will convert to percentage strings ("50%", "30%")'
}
};
}
/**
* Working examples with correct API field names
*/
buildPreciseExamples() {
return {
completeLesson: {
metadata: {
topic: "Fotossíntese",
duration: 50,
learningObjectives: ["Compreender o processo de fotossíntese"],
subject: "Ciências",
gradeLevel: "6º ano"
},
widgets: [
{
type: "head-1",
content: {
category: "CIÊNCIAS",
author_name: "Professor(a) Virtual",
author_office: "Especialista em Biologia"
}
},
{
type: "text-1",
content: {
text: "<h2>O que é Fotossíntese?</h2><p>A fotossíntese é o processo pelo qual as plantas produzem seu próprio alimento usando luz solar, água e dióxido de carbono.</p>"
}
},
{
type: "quiz-1",
content: {
questions: [
{
question: "Qual é o principal produto da fotossíntese?",
options: ["Oxigênio", "Glicose", "Água", "CO2"],
correct_option: 1
}
],
max_attempts: 3
}
},
{
type: "flashcards-1",
content: {
flashcards_items: [
{
question: "Clorofila",
answer: "Pigmento verde que captura a luz solar"
}
]
}
},
{
type: "list-1",
content: {
items: ["Capturar luz solar", "Absorver CO2", "Produzir glicose"],
list_type: "numbered"
}
}
]
}
};
}
/**
* Common mistakes that cause API errors
*/
buildCommonMistakes() {
return {
fieldNameErrors: {
quiz: {
wrong: 'Using "choices" or "answers" in quiz content',
correct: 'Use "options" array with "correct_option" index',
consequence: '500 API error - field not found'
},
list: {
wrong: 'Using "list_items" in your content',
correct: 'Use "items" array in your content',
consequence: '500 API error - field not found'
},
hotspots: {
wrong: 'Using string percentages like "50%" in your content',
correct: 'Use numeric coordinates like 50, 30 in your content',
consequence: 'API expects numeric values to convert'
},
flashcards: {
wrong: 'Using "items" instead of "flashcards_items"',
correct: 'Always use "flashcards_items" for flashcard content',
consequence: 'Validation error - missing required field'
}
},
contentErrors: {
shortText: {
wrong: 'Text content under 20 characters',
correct: 'Minimum 20 characters for all text fields',
consequence: 'Validation error - content too short'
},
invalidUrls: {
wrong: 'Relative paths or invalid URLs',
correct: 'Complete URLs starting with https://',
consequence: 'Validation error - invalid URL format'
},
missingRequiredFields: {
wrong: 'Omitting required fields like "category" in head-1',
correct: 'Include all required fields for each widget type',
consequence: 'Validation error - missing required field'
}
}
};
}
}
export function createAPIRequirementsCatalog() {
return new APIRequirementsCatalog();
}