project init

This commit is contained in:
2026-02-06 02:17:59 +03:00
commit b9d9b9ed17
129 changed files with 22835 additions and 0 deletions

View File

@ -0,0 +1,204 @@
// Default AI model for all tiers (can override in user settings on PRO)
const DEFAULT_AI_MODEL = 'openai/gpt-4o-mini';
// Subscription tier limits
export const SUBSCRIPTION_LIMITS = {
FREE: {
coursesPerMonth: 2,
defaultAiModel: DEFAULT_AI_MODEL,
},
PREMIUM: {
coursesPerMonth: 5,
defaultAiModel: DEFAULT_AI_MODEL,
},
PRO: {
coursesPerMonth: 15,
defaultAiModel: DEFAULT_AI_MODEL,
},
} as const;
// Prices in RUB for Russian locale (approximate)
const PRICE_RUB = {
FREE: 0,
PREMIUM: 999,
PRO: 2999,
} as const;
// Subscription plans for display
export const SUBSCRIPTION_PLANS = [
{
tier: 'FREE' as const,
name: 'Free',
nameRu: 'Бесплатный',
description: 'Perfect for trying out CourseCraft',
descriptionRu: 'Идеально для знакомства с CourseCraft',
price: 0,
priceRu: PRICE_RUB.FREE,
currency: 'USD',
features: [
'2 courses per month',
'Basic AI model',
'Standard support',
],
featuresRu: [
'2 курса в месяц',
'Базовая нейросеть',
'Стандартная поддержка',
],
stripePriceId: null,
},
{
tier: 'PREMIUM' as const,
name: 'Premium',
nameRu: 'Премиум',
description: 'For creators who need more',
descriptionRu: 'Для тех, кому нужно больше',
price: 9.99,
priceRu: PRICE_RUB.PREMIUM,
currency: 'USD',
features: [
'5 courses per month',
'Enhanced AI model',
'Priority support',
'Advanced editing tools',
],
featuresRu: [
'5 курсов в месяц',
'Улучшенная нейросеть',
'Приоритетная поддержка',
'Расширенные инструменты редактирования',
],
stripePriceId: process.env.STRIPE_PRICE_PREMIUM || null,
},
{
tier: 'PRO' as const,
name: 'Pro',
nameRu: 'Профессиональный',
description: 'For power users and teams',
descriptionRu: 'Для профессионалов и команд',
price: 29.99,
priceRu: PRICE_RUB.PRO,
currency: 'USD',
features: [
'15 courses per month',
'Best AI model available',
'Priority support 24/7',
'Advanced editing tools',
'Custom AI model selection',
'Export to PDF (coming soon)',
],
featuresRu: [
'15 курсов в месяц',
'Лучшая доступная нейросеть',
'Приоритетная поддержка 24/7',
'Расширенные инструменты редактирования',
'Выбор модели нейросети',
'Экспорт в PDF (скоро)',
],
stripePriceId: process.env.STRIPE_PRICE_PRO || null,
},
] as const;
export type SubscriptionPlan = (typeof SUBSCRIPTION_PLANS)[number];
/** Format plan price for display. Uses RUB when language is Russian. */
export function formatPlanPrice(
plan: { price: number; priceRu: number; currency: string },
language: string
): { amount: number; currency: string; formatted: string } {
const isRu = language === 'ru' || language.startsWith('ru');
if (isRu) {
const amount = plan.priceRu;
return {
amount,
currency: 'RUB',
formatted: amount === 0 ? 'Бесплатно' : `${amount.toLocaleString('ru-RU')}`,
};
}
return {
amount: plan.price,
currency: plan.currency,
formatted: plan.price === 0 ? 'Free' : `$${plan.price}`,
};
}
// Generation progress steps
export const GENERATION_STEPS = {
PENDING: { progress: 0, label: 'Waiting to start', labelRu: 'Ожидание запуска' },
ANALYZING: { progress: 10, label: 'Analyzing your request', labelRu: 'Анализ запроса' },
ASKING_QUESTIONS: { progress: 15, label: 'Preparing questions', labelRu: 'Подготовка вопросов' },
WAITING_FOR_ANSWERS: { progress: 20, label: 'Waiting for your answers', labelRu: 'Ожидание ваших ответов' },
RESEARCHING: { progress: 30, label: 'Researching the topic', labelRu: 'Исследование темы' },
GENERATING_OUTLINE: { progress: 50, label: 'Creating course structure', labelRu: 'Создание структуры курса' },
GENERATING_CONTENT: { progress: 70, label: 'Writing course content', labelRu: 'Написание содержания' },
COMPLETED: { progress: 100, label: 'Course completed!', labelRu: 'Курс готов!' },
FAILED: { progress: 0, label: 'Generation failed', labelRu: 'Ошибка генерации' },
CANCELLED: { progress: 0, label: 'Generation cancelled', labelRu: 'Генерация отменена' },
} as const;
// API Routes
export const API_ROUTES = {
AUTH: {
ME: '/auth/me',
CALLBACK: '/auth/callback',
LOGOUT: '/auth/logout',
},
USERS: {
PROFILE: '/users/profile',
SETTINGS: '/users/settings',
},
COURSES: {
LIST: '/courses',
CREATE: '/courses',
GET: (id: string) => `/courses/${id}`,
UPDATE: (id: string) => `/courses/${id}`,
DELETE: (id: string) => `/courses/${id}`,
},
CHAPTERS: {
LIST: (courseId: string) => `/courses/${courseId}/chapters`,
CREATE: (courseId: string) => `/courses/${courseId}/chapters`,
UPDATE: (courseId: string, chapterId: string) => `/courses/${courseId}/chapters/${chapterId}`,
DELETE: (courseId: string, chapterId: string) => `/courses/${courseId}/chapters/${chapterId}`,
REORDER: (courseId: string) => `/courses/${courseId}/chapters/reorder`,
},
LESSONS: {
GET: (courseId: string, lessonId: string) => `/courses/${courseId}/lessons/${lessonId}`,
UPDATE: (courseId: string, lessonId: string) => `/courses/${courseId}/lessons/${lessonId}`,
},
GENERATION: {
START: '/generation/start',
STATUS: (id: string) => `/generation/${id}/status`,
ANSWER: (id: string) => `/generation/${id}/answer`,
CANCEL: (id: string) => `/generation/${id}/cancel`,
},
SUBSCRIPTIONS: {
PLANS: '/subscriptions/plans',
CURRENT: '/subscriptions/current',
CHECKOUT: '/subscriptions/checkout',
PORTAL: '/subscriptions/portal',
},
SEARCH: {
COURSES: '/search/courses',
},
} as const;
// Validation
export const VALIDATION = {
COURSE: {
TITLE_MIN: 3,
TITLE_MAX: 200,
DESCRIPTION_MAX: 5000,
},
CHAPTER: {
TITLE_MIN: 2,
TITLE_MAX: 200,
},
LESSON: {
TITLE_MIN: 2,
TITLE_MAX: 200,
},
PROMPT: {
MIN: 10,
MAX: 2000,
},
} as const;