challenge-admin-pl/docs/TEACHER_GUIDE.md
Primakov Alexandr Alexandrovich e777b57991 init + api use
2025-11-03 17:59:08 +03:00

16 KiB
Raw Blame History

Challenge Service - Руководство для преподавателей

Специальное руководство для пользователей с ролью teacher в Keycloak.

Требования

Для создания и редактирования заданий и цепочек необходимо:

  1. Быть авторизованным через Keycloak
  2. Иметь роль teacher в клиенте journal

Особенности для преподавателей

1. Скрытые инструкции для LLM

При создании заданий вы можете добавить скрытые инструкции (hiddenInstructions), которые:

  • Видны только преподавателям
  • Передаются в LLM при проверке
  • Не видны студентам
  • Не отображаются в интерфейсе студента

Примеры использования

Пример 1: Контроль сложности

{
  "title": "Реализовать сортировку",
  "description": "Напишите функцию для сортировки массива чисел",
  "hiddenInstructions": "Проверь, чтобы сложность алгоритма была не хуже O(n log n). Не принимай bubble sort или простые O(n²) решения."
}

Пример 2: Специфичные требования

{
  "title": "REST API endpoint",
  "description": "Создайте endpoint для получения списка пользователей",
  "hiddenInstructions": "Обязательно должна быть пагинация, обработка ошибок и валидация параметров. Если чего-то не хватает - укажи в feedback."
}

Пример 3: Стиль кода

{
  "title": "Компонент React",
  "description": "Создайте компонент для отображения карточки товара",
  "hiddenInstructions": "Проверь использование TypeScript, правильное применение хуков, и соблюдение best practices React. Код должен быть чистым и читаемым."
}

Пример 4: Тонкая настройка проверки

{
  "title": "SQL запрос",
  "description": "Напишите запрос для выборки активных пользователей",
  "hiddenInstructions": "Даже если запрос работает, но неоптимален (например, использует SELECT *), укажи на это в feedback и попроси оптимизировать."
}

2. Создание задания через API

С помощью Keycloak токена

// Получение токена (пример для frontend)
const keycloakToken = keycloak.token // из keycloak-js

// Создание задания
async function createTask(title: string, description: string, hiddenInstructions: string) {
  const response = await fetch('http://localhost:8082/api/challenge/task', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${keycloakToken}`
    },
    body: JSON.stringify({
      title,
      description,
      hiddenInstructions
    })
  })
  
  return response.json()
}

С помощью curl

# Получить токен от Keycloak
TOKEN="your_keycloak_token"

# Создать задание
curl -X POST http://localhost:8082/api/challenge/task \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "title": "Написать функцию",
    "description": "# Задание\n\nНапишите функцию для...",
    "hiddenInstructions": "Проверь производительность и обработку ошибок"
  }'

3. UI компоненты для преподавателей

TaskForm с скрытыми инструкциями

import { useState } from 'react'
import ReactMarkdown from 'react-markdown'

interface TaskFormProps {
  onSubmit: (task: { title: string; description: string; hiddenInstructions: string }) => void
}

export function TeacherTaskForm({ onSubmit }: TaskFormProps) {
  const [title, setTitle] = useState('')
  const [description, setDescription] = useState('')
  const [hiddenInstructions, setHiddenInstructions] = useState('')
  const [showPreview, setShowPreview] = useState(false)

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    onSubmit({ title, description, hiddenInstructions })
  }

  return (
    <form onSubmit={handleSubmit}>
      <div className="form-group">
        <label>Заголовок задания</label>
        <input
          type="text"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          required
          maxLength={255}
        />
      </div>

      <div className="form-group">
        <label>Описание (Markdown)</label>
        <div className="tabs">
          <button type="button" onClick={() => setShowPreview(false)}>Редактор</button>
          <button type="button" onClick={() => setShowPreview(true)}>Превью</button>
        </div>
        
        {showPreview ? (
          <div className="markdown-preview">
            <ReactMarkdown>{description}</ReactMarkdown>
          </div>
        ) : (
          <textarea
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            required
            rows={15}
            placeholder="# Заголовок\n\nОписание задания..."
          />
        )}
      </div>

      <div className="form-group highlight">
        <label>
          🔒 Скрытые инструкции для LLM
          <span className="info-tooltip">
            Эти инструкции увидит только LLM при проверке. 
            Студенты их не увидят.
          </span>
        </label>
        <textarea
          value={hiddenInstructions}
          onChange={(e) => setHiddenInstructions(e.target.value)}
          rows={5}
          placeholder="Дополнительные требования к проверке..."
        />
      </div>

      <button type="submit">Создать задание</button>
    </form>
  )
}

TaskCard с индикацией скрытых инструкций

interface TaskCardProps {
  task: ChallengeTask
  isTeacher: boolean
}

export function TaskCard({ task, isTeacher }: TaskCardProps) {
  return (
    <div className="task-card">
      <h3>{task.title}</h3>
      
      <div className="task-description">
        <ReactMarkdown>{task.description}</ReactMarkdown>
      </div>
      
      {isTeacher && task.hiddenInstructions && (
        <div className="hidden-instructions-indicator">
          <span className="lock-icon">🔒</span>
          <span>Содержит скрытые инструкции для LLM</span>
        </div>
      )}
      
      {isTeacher && task.creator && (
        <div className="task-meta">
          <span>Создал: {task.creator.preferred_username}</span>
        </div>
      )}
    </div>
  )
}

4. Настройка Keycloak

Добавление роли teacher

  1. Войдите в админ панель Keycloak
  2. Выберите realm (например, bro-js или itpark)
  3. Перейдите в Clientsjournal
  4. Перейдите на вкладку Roles
  5. Добавьте роль teacher, если её нет
  6. Назначьте роль нужным пользователям через Users → [пользователь] → Role Mappings

5. Best Practices

Хорошие скрытые инструкции

"Проверь, что функция обрабатывает edge cases: пустой массив, 
один элемент, отрицательные числа. Если что-то упущено - укажи."
"Код должен следовать принципу DRY. Если есть дублирование - 
отправь на доработку с рекомендацией."
"Обязательна обработка ошибок. Если try-catch отсутствует или 
неполный - укажи в feedback."

Плохие скрытые инструкции

"Проверь" // Слишком общее
"Это задание должно быть правильным" // Бессмысленное
"Не принимай, если не идеально" // Слишком строгое, непонятное

6. Просмотр скрытых инструкций

Скрытые инструкции доступны только при запросе с токеном teacher:

// Получить задание (с токеном teacher)
async function getTaskAsTeacher(taskId: string) {
  const response = await fetch(`http://localhost:8082/api/challenge/task/${taskId}`, {
    headers: {
      'Authorization': `Bearer ${keycloakToken}`
    }
  })
  
  const { data } = await response.json()
  
  // data.hiddenInstructions будет доступно
  console.log('Hidden instructions:', data.hiddenInstructions)
}

// Получить задание (без токена или с обычным пользователем)
async function getTaskAsStudent(taskId: string) {
  const response = await fetch(`http://localhost:8082/api/challenge/task/${taskId}`)
  
  const { data } = await response.json()
  
  // data.hiddenInstructions будет undefined
  console.log('Hidden instructions:', data.hiddenInstructions) // undefined
}

7. Редактирование существующих заданий

async function updateTask(
  taskId: string, 
  updates: { 
    title?: string
    description?: string
    hiddenInstructions?: string 
  }
) {
  const response = await fetch(`http://localhost:8082/api/challenge/task/${taskId}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${keycloakToken}`
    },
    body: JSON.stringify(updates)
  })
  
  return response.json()
}

// Пример использования
updateTask('507f1f77bcf86cd799439011', {
  hiddenInstructions: 'Обновленные требования к проверке'
})

8. Мониторинг эффективности инструкций

Отслеживайте, как скрытые инструкции влияют на результаты:

interface InstructionEffectiveness {
  taskId: string
  taskTitle: string
  hasHiddenInstructions: boolean
  acceptanceRate: number // % принятых с первой попытки
  averageFeedbackQuality: number // оценка качества feedback
}

// Анализ эффективности
async function analyzeInstructionsEffectiveness() {
  const tasks = await fetchAllTasks()
  const stats = await fetchSystemStats()
  
  return tasks.map(task => ({
    taskId: task.id,
    taskTitle: task.title,
    hasHiddenInstructions: !!task.hiddenInstructions,
    acceptanceRate: calculateAcceptanceRate(task.id, stats),
    averageFeedbackQuality: calculateFeedbackQuality(task.id, stats)
  }))
}

9. Шаблоны скрытых инструкций

Для программирования

Проверь:
1. Корректность алгоритма
2. Обработку edge cases
3. Сложность алгоритма (должна быть оптимальной)
4. Читаемость кода
5. Наличие комментариев в сложных местах

Для веб-разработки

Проверь:
1. Соответствие HTML семантике
2. Доступность (accessibility)
3. Responsive design
4. Производительность
5. Best practices для используемого фреймворка

Для баз данных

Проверь:
1. Правильность SQL синтаксиса
2. Оптимальность запроса
3. Использование индексов
4. Защиту от SQL injection
5. Читаемость запроса

10. FAQ

Q: Что если я не добавлю скрытые инструкции?
A: Задание будет работать нормально. LLM проверит решение на основе только видимого описания.

Q: Могут ли студенты как-то увидеть скрытые инструкции?
A: Нет, сервер автоматически фильтрует это поле при запросах без роли teacher.

Q: Можно ли изменить скрытые инструкции после создания?
A: Да, используйте PUT /api/challenge/task/:taskId с новым значением hiddenInstructions.

Q: Влияют ли скрытые инструкции на все проверки?
A: Да, каждая проверка использует актуальные hiddenInstructions из задания.

Q: Можно ли использовать Markdown в скрытых инструкциях?
A: Можно, но это обычный текст. Markdown не рендерится, так как инструкции идут прямо в LLM.


Примеры реальных сценариев

Сценарий 1: Курс по алгоритмам

{
  "title": "Реализовать бинарный поиск",
  "description": "Напишите функцию binarySearch(arr, target), которая ищет элемент в отсортированном массиве",
  "hiddenInstructions": "Проверь сложность - должна быть O(log n). Если используется линейный поиск или неоптимальный алгоритм - отклони с объяснением. Также проверь обработку случаев, когда элемент не найден."
}

Сценарий 2: Курс по React

{
  "title": "Форма регистрации",
  "description": "Создайте компонент формы регистрации с полями email и пароль",
  "hiddenInstructions": "Обязательна валидация на стороне клиента, использование controlled components, и правильное управление state. Если используются uncontrolled components или нет валидации - отправь на доработку."
}

Сценарий 3: Курс по безопасности

{
  "title": "Безопасный API endpoint",
  "description": "Создайте endpoint для аутентификации пользователя",
  "hiddenInstructions": "Критически важно: пароли должны хешироваться, должна быть защита от SQL injection, rate limiting. Если что-то из этого отсутствует - обязательно отклони и подробно объясни риски безопасности."
}

Используйте скрытые инструкции разумно для повышения качества автоматической проверки! 🎓