# Challenge Service - Руководство для преподавателей
Специальное руководство для пользователей с ролью `teacher` в Keycloak.
## Требования
Для создания и редактирования заданий и цепочек необходимо:
1. Быть авторизованным через Keycloak
2. Иметь роль `teacher` в клиенте `journal`
## Особенности для преподавателей
### 1. Скрытые инструкции для LLM
При создании заданий вы можете добавить **скрытые инструкции** (`hiddenInstructions`), которые:
- ✅ Видны только преподавателям
- ✅ Передаются в LLM при проверке
- ❌ Не видны студентам
- ❌ Не отображаются в интерфейсе студента
#### Примеры использования
**Пример 1: Контроль сложности**
```json
{
"title": "Реализовать сортировку",
"description": "Напишите функцию для сортировки массива чисел",
"hiddenInstructions": "Проверь, чтобы сложность алгоритма была не хуже O(n log n). Не принимай bubble sort или простые O(n²) решения."
}
```
**Пример 2: Специфичные требования**
```json
{
"title": "REST API endpoint",
"description": "Создайте endpoint для получения списка пользователей",
"hiddenInstructions": "Обязательно должна быть пагинация, обработка ошибок и валидация параметров. Если чего-то не хватает - укажи в feedback."
}
```
**Пример 3: Стиль кода**
```json
{
"title": "Компонент React",
"description": "Создайте компонент для отображения карточки товара",
"hiddenInstructions": "Проверь использование TypeScript, правильное применение хуков, и соблюдение best practices React. Код должен быть чистым и читаемым."
}
```
**Пример 4: Тонкая настройка проверки**
```json
{
"title": "SQL запрос",
"description": "Напишите запрос для выборки активных пользователей",
"hiddenInstructions": "Даже если запрос работает, но неоптимален (например, использует SELECT *), укажи на это в feedback и попроси оптимизировать."
}
```
### 2. Создание задания через API
#### С помощью Keycloak токена
```typescript
// Получение токена (пример для 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
```bash
# Получить токен от 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 с скрытыми инструкциями
```typescript
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 (
)
}
```
#### TaskCard с индикацией скрытых инструкций
```typescript
interface TaskCardProps {
task: ChallengeTask
isTeacher: boolean
}
export function TaskCard({ task, isTeacher }: TaskCardProps) {
return (
{task.title}
{task.description}
{isTeacher && task.hiddenInstructions && (
🔒
Содержит скрытые инструкции для LLM
)}
{isTeacher && task.creator && (
Создал: {task.creator.preferred_username}
)}
)
}
```
### 4. Настройка Keycloak
#### Добавление роли teacher
1. Войдите в админ панель Keycloak
2. Выберите realm (например, `bro-js` или `itpark`)
3. Перейдите в **Clients** → `journal`
4. Перейдите на вкладку **Roles**
5. Добавьте роль `teacher`, если её нет
6. Назначьте роль нужным пользователям через **Users** → [пользователь] → **Role Mappings**
### 5. Best Practices
#### ✅ Хорошие скрытые инструкции
```
"Проверь, что функция обрабатывает edge cases: пустой массив,
один элемент, отрицательные числа. Если что-то упущено - укажи."
```
```
"Код должен следовать принципу DRY. Если есть дублирование -
отправь на доработку с рекомендацией."
```
```
"Обязательна обработка ошибок. Если try-catch отсутствует или
неполный - укажи в feedback."
```
#### ❌ Плохие скрытые инструкции
```
"Проверь" // Слишком общее
```
```
"Это задание должно быть правильным" // Бессмысленное
```
```
"Не принимай, если не идеально" // Слишком строгое, непонятное
```
### 6. Просмотр скрытых инструкций
Скрытые инструкции доступны только при запросе с токеном `teacher`:
```typescript
// Получить задание (с токеном 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. Редактирование существующих заданий
```typescript
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. Мониторинг эффективности инструкций
Отслеживайте, как скрытые инструкции влияют на результаты:
```typescript
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: Курс по алгоритмам
```json
{
"title": "Реализовать бинарный поиск",
"description": "Напишите функцию binarySearch(arr, target), которая ищет элемент в отсортированном массиве",
"hiddenInstructions": "Проверь сложность - должна быть O(log n). Если используется линейный поиск или неоптимальный алгоритм - отклони с объяснением. Также проверь обработку случаев, когда элемент не найден."
}
```
### Сценарий 2: Курс по React
```json
{
"title": "Форма регистрации",
"description": "Создайте компонент формы регистрации с полями email и пароль",
"hiddenInstructions": "Обязательна валидация на стороне клиента, использование controlled components, и правильное управление state. Если используются uncontrolled components или нет валидации - отправь на доработку."
}
```
### Сценарий 3: Курс по безопасности
```json
{
"title": "Безопасный API endpoint",
"description": "Создайте endpoint для аутентификации пользователя",
"hiddenInstructions": "Критически важно: пароли должны хешироваться, должна быть защита от SQL injection, rate limiting. Если что-то из этого отсутствует - обязательно отклони и подробно объясни риски безопасности."
}
```
---
Используйте скрытые инструкции разумно для повышения качества автоматической проверки! 🎓