Instruction file imported from jungfrau70/ed_platform (
.cursor/rules/development-environment.mdc). Copyright stays with the author.
description: κ΅μ‘ κ΅κ΅¬ μμ€ν κ°λ° νκ²½ μ€μ λ° κ΄λ¦¬ κ·μΉ globs: "/*.py", "/.ts", "**/.vue", "/*.json", "/*.md" alwaysApply: true
κ΅μ‘ κ΅κ΅¬ μμ€ν κ°λ° νκ²½ κ·μΉ
π οΈ κ°λ° νκ²½ ꡬμ±
κ΅μ‘ κ΅κ΅¬ μμ€ν κ°λ° μ€ν
- Frontend: Nuxt.js 3 + Vue.js 3 + TypeScript
- Backend: FastAPI + Python 3.9+
- Database: PostgreSQL 14+ (κ΅μ‘ μλ£ λ° μ§λ κ΄λ¦¬)
- Cache: Redis 6+ (μ±λ₯ μ΅μ ν)
- AI Integration: OpenAI API / Anthropic Claude API
- Testing: Vitest (Frontend) + Pytest (Backend)
κ°λ° νκ²½ μ€μ
# β
DO: κ°λ° νκ²½ μ΄κΈ° μ€μ
# 1. νλ‘μ νΈ ν΄λ‘
git clone <repository-url>
cd mcp_cloud
# 2. λ°±μλ νκ²½ μ€μ
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
# 3. νλ‘ νΈμλ νκ²½ μ€μ
cd ../frontend
npm install
# 4. λ°μ΄ν°λ² μ΄μ€ μ€μ
docker-compose up -d postgres redis
# 5. νκ²½ λ³μ μ€μ
cp .env.example .env
# .env νμΌμ νμν νκ²½ λ³μ μ€μ
π― κ΅μ‘ κ΅κ΅¬ μμ€ν νΉν μ€μ
κ΅μ‘ μλ£ κ΄λ¦¬ μ€μ
# β
DO: κ΅μ‘ μλ£ κ΄λ¦¬ μ€μ
# backend/app/config/education.py
class EducationConfig:
# κ΅μ‘ μλ£ λ£¨νΈ λλ ν 리
KNOWLEDGE_BASE_ROOT = Path("mcp_knowledge_base")
# μ§μνλ κ΅μ‘ κ³Όμ
SUPPORTED_COURSES = [
"cloud_basic",
"cloud_container",
"cloud_master"
]
# κ΅μ‘ μλ£ νμΌ νμ₯μ
SUPPORTED_EXTENSIONS = [".md", ".mdx"]
# μ΅μ»€ λ§ν¬ μλ κ²μ¦ μ€μ
AUTO_VALIDATE_ANCHORS = True
ANCHOR_VALIDATION_SCHEDULE = "weekly" # weekly, daily, on_change
AI μμ΄μ νΈ μ€μ
# β
DO: AI μμ΄μ νΈ μ€μ
# backend/app/config/ai_agent.py
class AIAgentConfig:
# AI λͺ¨λΈ μ€μ
DEFAULT_MODEL = "gpt-4"
FALLBACK_MODEL = "gpt-3.5-turbo"
# κ΅μ‘ λꡬ νΉν ν둬ννΈ
EDUCATION_PROMPTS = {
"content_generation": "κ΅μ‘ μλ£ μμ± ν둬ννΈ",
"practice_guide": "μ€μ΅ κ°μ΄λ μμ± ν둬ννΈ",
"assessment": "νκ° κΈ°μ€ μμ± ν둬ννΈ"
}
# μλ΅ νμ§ μ€μ
MAX_TOKENS = 4000
TEMPERATURE = 0.7
TOP_P = 0.9
π§ͺ κ΅μ‘ κ΅κ΅¬ μμ€ν ν μ€νΈ νκ²½
κ΅μ‘ μλ£ ν μ€νΈ
# β
DO: κ΅μ‘ μλ£ ν
μ€νΈ μ€μ
# tests/education/test_content_validation.py
import pytest
from backend.app.utils.content_validator import ContentValidator
class TestEducationContent:
def test_anchor_links_validation(self):
# μ΅μ»€ λ§ν¬ κ²μ¦ ν
μ€νΈ
validator = ContentValidator()
result = validator.validate_anchor_links("test_course.md")
assert result.is_valid == True
assert len(result.errors) == 0
def test_learning_objectives_completeness(self):
# νμ΅ λͺ©ν μμ±λ ν
μ€νΈ
validator = ContentValidator()
result = validator.validate_learning_objectives("test_course.md")
assert len(result.objectives) >= 2
assert all(obj.is_measurable for obj in result.objectives)
def test_practice_guide_structure(self):
# μ€μ΅ κ°μ΄λ ꡬ쑰 ν
μ€νΈ
validator = ContentValidator()
result = validator.validate_practice_guide("test_course.md")
assert len(result.steps) >= 3
assert all(step.has_expected_result for step in result.steps)
κ΅μ‘ κ³Όμ ν΅ν© ν μ€νΈ
// β
DO: κ΅μ‘ κ³Όμ ν΅ν© ν
μ€νΈ
// frontend/tests/education/course-integration.test.ts
import { describe, it, expect } from 'vitest'
import { CourseManager } from '@/composables/useCourseManager'
describe('Course Integration', () => {
it('should load course curriculum correctly', async () => {
const courseManager = new CourseManager()
const curriculum = await courseManager.loadCurriculum('cloud_basic')
expect(curriculum).toBeDefined()
expect(curriculum.title).toContain('Cloud Basic')
expect(curriculum.days).toHaveLength(3)
})
it('should validate all anchor links', async () => {
const courseManager = new CourseManager()
const validation = await courseManager.validateAnchorLinks('cloud_basic')
expect(validation.isValid).toBe(true)
expect(validation.brokenLinks).toHaveLength(0)
})
})
π κ΅μ‘ κ΅κ΅¬ μμ€ν λ°°ν¬ νκ²½
Docker 컨ν μ΄λ μ€μ
# β
DO: κ΅μ‘ κ΅κ΅¬ μμ€ν
Dockerfile
# Dockerfile.education
FROM node:18-alpine AS frontend-builder
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci --only=production
COPY frontend/ ./
RUN npm run build
FROM python:3.9-slim AS backend-builder
WORKDIR /app/backend
COPY backend/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY backend/ ./
FROM nginx:alpine AS production
# κ΅μ‘ μλ£ μ μ νμΌ μλΉ μ€μ
COPY --from=frontend-builder /app/frontend/dist /usr/share/nginx/html
COPY nginx/education.conf /etc/nginx/conf.d/default.conf
κ΅μ‘ νκ²½λ³ μ€μ
# β
DO: κ΅μ‘ νκ²½λ³ Docker Compose μ€μ
# docker-compose.education.yml
version: '3.8'
services:
education-app:
build:
context: .
dockerfile: Dockerfile.education
ports:
- "3000:80"
environment:
- NODE_ENV=production
- EDUCATION_MODE=true
volumes:
- ./mcp_knowledge_base:/app/knowledge_base:ro
depends_on:
- postgres
- redis
postgres:
image: postgres:14
environment:
POSTGRES_DB: education_db
POSTGRES_USER: education_user
POSTGRES_PASSWORD: education_pass
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:6-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
π κ΅μ‘ κ΅κ΅¬ μμ€ν λͺ¨λν°λ§
κ΅μ‘ μλ£ νμ§ λͺ¨λν°λ§
# β
DO: κ΅μ‘ μλ£ νμ§ λͺ¨λν°λ§
# backend/app/monitoring/education_metrics.py
class EducationMetricsCollector:
def __init__(self):
self.metrics = {}
def collect_content_quality_metrics(self):
# κ΅μ‘ μλ£ νμ§ μ§ν μμ§
return {
'total_courses': self.count_courses(),
'valid_anchor_links': self.count_valid_anchors(),
'broken_links': self.count_broken_links(),
'content_freshness': self.calculate_freshness(),
'learner_satisfaction': self.get_satisfaction_score()
}
def collect_learning_effectiveness_metrics(self):
# νμ΅ ν¨κ³Ό μ§ν μμ§
return {
'completion_rates': self.get_completion_rates(),
'learning_progress': self.get_progress_metrics(),
'practice_success_rates': self.get_practice_success(),
'assessment_scores': self.get_assessment_scores()
}
μ±λ₯ λͺ¨λν°λ§ μ€μ
# β
DO: κ΅μ‘ κ΅κ΅¬ μμ€ν
λͺ¨λν°λ§ μ€μ
# monitoring/prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'education-backend'
static_configs:
- targets: ['backend:8000']
metrics_path: '/metrics'
- job_name: 'education-frontend'
static_configs:
- targets: ['frontend:3000']
metrics_path: '/api/metrics'
- job_name: 'education-database'
static_configs:
- targets: ['postgres:5432']
π§ κ°λ° λꡬ λ° μ νΈλ¦¬ν°
κ΅μ‘ μλ£ κ΄λ¦¬ λꡬ
# β
DO: κ΅μ‘ μλ£ κ΄λ¦¬ λꡬ
# tools/education_manager.py
class EducationManager:
def __init__(self):
self.knowledge_base = KnowledgeBase()
self.validator = ContentValidator()
def create_new_course(self, course_name: str, structure: dict):
# μ κ΅μ‘ κ³Όμ μμ±
# 1. λλ ν 리 ꡬ쑰 μμ±
self.create_course_structure(course_name, structure)
# 2. κΈ°λ³Έ ν
νλ¦Ώ νμΌ μμ±
self.create_template_files(course_name)
# 3. μ΅μ»€ λ§ν¬ κ²μ¦
self.validate_course_links(course_name)
# 4. νμ΅ κ²½λ‘ μ
λ°μ΄νΈ
self.update_learning_paths(course_name)
def validate_all_courses(self):
# λͺ¨λ κ΅μ‘ κ³Όμ κ²μ¦
results = {}
for course in self.knowledge_base.get_courses():
results[course] = self.validator.validate_course(course)
return results
π κ΄λ ¨ νμΌ
- package.json - νλ‘ νΈμλ μμ‘΄μ±
- requirements.txt - λ°±μλ μμ‘΄μ±
- docker-compose.yml - 컨ν μ΄λ μ€μ
- vitest.config.ts - νλ‘ νΈμλ ν μ€νΈ μ€μ
- pytest.ini - λ°±μλ ν μ€νΈ μ€μ
μ΄ κ·μΉμ ν΅ν΄ κ΅μ‘ κ΅κ΅¬ μμ€ν μ κ°λ° νκ²½μ ν¨μ¨μ μΌλ‘ κ΄λ¦¬ν μ μμ΅λλ€.