feat: Add smart package recommendations feature

- Implement onboarding modal with 3-step wizard
  - Category selection (up to 3 categories)
  - OS detection with manual override
  - Experience level selection

- Add intelligent recommendation engine
  - Hybrid scoring algorithm (category 40%, popularity 30%, OS 20%, preset 10%)
  - 7 curated categories with preset packages
  - Support for all platforms (Windows, macOS, Ubuntu, Debian, Arch, Fedora)

- Create recommendation UI components
  - RecommendationsSection with grid layout
  - Package cards with recommendation scores and reasons
  - User profile display with customization options

- Add localStorage-based profile management
  - Persistent user preferences
  - Automatic OS detection
  - Profile CRUD operations via useRecommendationProfile hook

- Implement API endpoint
  - POST /api/recommendations
  - GET /api/recommendations (query params)
  - Request validation and error handling

- Add full i18n support
  - English and Turkish translations
  - Onboarding flow, categories, and UI labels

- Update TypeScript config (lib: es2017 for array.includes)

Closes #1
This commit is contained in:
ersaayan
2025-11-22 16:20:36 +03:00
parent afd4456893
commit 73f9248e98
12 changed files with 2169 additions and 8 deletions
+157
View File
@@ -0,0 +1,157 @@
import { NextRequest, NextResponse } from 'next/server'
import { RecommendationService } from '@/services/recommendationService'
import { RecommendationRequest } from '@/types/recommendations'
export async function POST(request: NextRequest) {
try {
const body: RecommendationRequest = await request.json()
// Validate required fields
if (!body.platform_id) {
return NextResponse.json(
{ error: 'platform_id is required' },
{ status: 400 }
)
}
if (!body.categories || body.categories.length === 0) {
return NextResponse.json(
{ error: 'At least one category is required' },
{ status: 400 }
)
}
// Validate platform_id
const validPlatforms = ['windows', 'macos', 'ubuntu', 'debian', 'arch', 'fedora']
if (!validPlatforms.includes(body.platform_id)) {
return NextResponse.json(
{ error: `Invalid platform_id. Must be one of: ${validPlatforms.join(', ')}` },
{ status: 400 }
)
}
// Validate categories
const validCategories = [
'development',
'design',
'multimedia',
'system-tools',
'gaming',
'productivity',
'education'
]
const invalidCategories = body.categories.filter(
cat => !validCategories.includes(cat)
)
if (invalidCategories.length > 0) {
return NextResponse.json(
{
error: `Invalid categories: ${invalidCategories.join(', ')}`,
validCategories
},
{ status: 400 }
)
}
// Set default limit
const limit = body.limit && body.limit > 0 && body.limit <= 50
? body.limit
: 20
// Generate recommendations
const recommendations = await RecommendationService.generateRecommendations({
platform_id: body.platform_id,
categories: body.categories,
experienceLevel: body.experienceLevel,
limit
})
return NextResponse.json({
recommendations,
total: recommendations.length,
userProfile: {
categories: body.categories,
platform: body.platform_id,
experienceLevel: body.experienceLevel
}
})
} catch (error) {
console.error('Error generating recommendations:', error)
return NextResponse.json(
{
error: 'Failed to generate recommendations',
details: error instanceof Error ? error.message : 'Unknown error'
},
{ status: 500 }
)
}
}
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const platformId = searchParams.get('platform_id')
const categoriesParam = searchParams.get('categories')
const experienceLevel = searchParams.get('experience_level')
const limit = searchParams.get('limit')
// Validate required fields
if (!platformId) {
return NextResponse.json(
{ error: 'platform_id query parameter is required' },
{ status: 400 }
)
}
if (!categoriesParam) {
return NextResponse.json(
{ error: 'categories query parameter is required (comma-separated)' },
{ status: 400 }
)
}
// Parse categories
const categories = categoriesParam.split(',').map(c => c.trim())
// Validate platform_id
const validPlatforms = ['windows', 'macos', 'ubuntu', 'debian', 'arch', 'fedora']
if (!validPlatforms.includes(platformId)) {
return NextResponse.json(
{ error: `Invalid platform_id. Must be one of: ${validPlatforms.join(', ')}` },
{ status: 400 }
)
}
// Set default limit
const parsedLimit = limit && parseInt(limit) > 0 && parseInt(limit) <= 50
? parseInt(limit)
: 20
// Generate recommendations
const recommendations = await RecommendationService.generateRecommendations({
platform_id: platformId,
categories: categories as any,
experienceLevel: experienceLevel as any,
limit: parsedLimit
})
return NextResponse.json({
recommendations,
total: recommendations.length,
userProfile: {
categories,
platform: platformId,
experienceLevel
}
})
} catch (error) {
console.error('Error generating recommendations:', error)
return NextResponse.json(
{
error: 'Failed to generate recommendations',
details: error instanceof Error ? error.message : 'Unknown error'
},
{ status: 500 }
)
}
}