init commit

This commit is contained in:
2025-10-19 18:27:00 +09:00
commit 150891b29d
219 changed files with 70016 additions and 0 deletions

486
server-demo.js Normal file
View File

@@ -0,0 +1,486 @@
/**
* Demo server for SmartSolTech website
* Uses mock data instead of MongoDB for demonstration
*/
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const flash = require('connect-flash');
const helmet = require('helmet');
const compression = require('compression');
const rateLimit = require('express-rate-limit');
const i18n = require('i18n');
const app = express();
const PORT = process.env.PORT || 3000;
// Configure i18n
i18n.configure({
locales: ['en', 'ko', 'ru', 'kk'],
directory: path.join(__dirname, 'locales'),
defaultLocale: 'ko',
cookie: 'language',
queryParameter: 'lang',
autoReload: true,
syncFiles: true,
objectNotation: true
});
// Security middleware
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net", "https://cdnjs.cloudflare.com", "https://unpkg.com"],
scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net", "https://cdnjs.cloudflare.com", "https://unpkg.com"],
imgSrc: ["'self'", "data:", "https:", "blob:"],
fontSrc: ["'self'", "https://cdnjs.cloudflare.com"],
connectSrc: ["'self'", "https:"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
}
}
}));
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP, please try again later.'
});
app.use(limiter);
// Compression
app.use(compression());
// View engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// Middleware
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Initialize i18n
app.use(i18n.init);
// Session configuration
app.use(session({
secret: 'demo-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // Set to true in production with HTTPS
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
}));
// Flash messages
app.use(flash());
// Global variables for templates
app.use((req, res, next) => {
res.locals.success_msg = req.flash('success');
res.locals.error_msg = req.flash('error');
res.locals.error = req.flash('error');
res.locals.currentYear = new Date().getFullYear();
next();
});
// Mock data
const mockPortfolio = [
{
_id: '1',
title: 'E-commerce 플랫폼',
description: '현대적인 온라인 쇼핑몰 플랫폼을 개발했습니다. React와 Node.js를 활용하여 높은 성능과 사용자 경험을 제공하며, 결제 시스템과 재고 관리 기능을 포함합니다.',
shortDescription: '반응형 온라인 쇼핑몰 플랫폼 개발',
category: 'web-development',
technologies: ['React', 'Node.js', 'MongoDB', 'Express', 'Stripe', 'AWS'],
images: [
{ url: '/images/portfolio/ecommerce-1.jpg', alt: 'E-commerce 메인페이지', isPrimary: true }
],
clientName: '패션 브랜드 ABC',
projectUrl: 'https://example-ecommerce.demo',
status: 'completed',
featured: true,
publishedAt: new Date('2024-01-15'),
completedAt: new Date('2024-01-10'),
isPublished: true,
viewCount: 150,
likes: 25
},
{
_id: '2',
title: '모바일 피트니스 앱',
description: 'React Native를 사용하여 크로스플랫폼 피트니스 애플리케이션을 개발했습니다. 운동 계획, 칼로리 추적, 소셜 기능을 포함하여 사용자들의 건강한 라이프스타일을 지원합니다.',
shortDescription: '건강 관리를 위한 크로스플랫폼 모바일 앱',
category: 'mobile-app',
technologies: ['React Native', 'Redux', 'Firebase', 'Node.js', 'PostgreSQL'],
images: [
{ url: '/images/portfolio/fitness-1.jpg', alt: '피트니스 앱 메인화면', isPrimary: true }
],
clientName: '헬스케어 스타트업 FIT',
status: 'completed',
featured: true,
publishedAt: new Date('2024-02-20'),
completedAt: new Date('2024-02-15'),
isPublished: true,
viewCount: 200,
likes: 35
},
{
_id: '3',
title: '기업 웹사이트 리뉴얼',
description: '기업의 브랜드 아이덴티티를 반영한 웹사이트 리뉴얼 프로젝트입니다. 사용자 경험을 개선하고 모던한 디자인을 적용하여 브랜드 가치를 높였습니다.',
shortDescription: '브랜드 아이덴티티를 반영한 기업 웹사이트 리뉴얼',
category: 'ui-ux-design',
technologies: ['Figma', 'React', 'Sass', 'Framer Motion', 'Contentful'],
images: [
{ url: '/images/portfolio/corporate-1.jpg', alt: '기업 웹사이트 메인페이지', isPrimary: true }
],
clientName: '기술 기업 TechCorp',
projectUrl: 'https://example-corp.demo',
status: 'completed',
featured: true,
publishedAt: new Date('2024-03-10'),
completedAt: new Date('2024-03-05'),
isPublished: true,
viewCount: 120,
likes: 18
}
];
const mockServices = [
{
_id: '1',
name: '웹 개발',
description: '현대적이고 반응형인 웹사이트와 웹 애플리케이션을 개발합니다. React, Node.js, MongoDB 등 최신 기술 스택을 활용하여 성능과 사용자 경험을 최적화합니다.',
shortDescription: '현대적이고 반응형 웹사이트 및 웹 애플리케이션 개발',
icon: 'fas fa-code',
category: 'development',
pricing: {
basePrice: 500000,
currency: 'KRW',
priceType: 'project',
priceRange: { min: 500000, max: 5000000 }
},
featured: true,
isActive: true
},
{
_id: '2',
name: '모바일 앱 개발',
description: 'iOS와 Android 플랫폼을 위한 네이티브 및 크로스플랫폼 모바일 애플리케이션을 개발합니다. React Native, Flutter 등을 활용하여 효율적인 개발을 진행합니다.',
shortDescription: 'iOS/Android 네이티브 및 크로스플랫폼 앱 개발',
icon: 'fas fa-mobile-alt',
category: 'development',
pricing: {
basePrice: 800000,
currency: 'KRW',
priceType: 'project',
priceRange: { min: 800000, max: 8000000 }
},
featured: true,
isActive: true
},
{
_id: '3',
name: 'UI/UX 디자인',
description: '사용자 중심의 직관적이고 아름다운 인터페이스를 디자인합니다. 사용자 경험 연구와 프로토타이핑을 통해 최적의 디자인 솔루션을 제공합니다.',
shortDescription: '사용자 중심의 직관적이고 아름다운 인터페이스 디자인',
icon: 'fas fa-palette',
category: 'design',
pricing: {
basePrice: 300000,
currency: 'KRW',
priceType: 'project',
priceRange: { min: 300000, max: 2000000 }
},
featured: true,
isActive: true
},
{
_id: '4',
name: '디지털 마케팅',
description: 'SEO, 소셜미디어 마케팅, 온라인 광고를 통해 디지털 마케팅 전략을 수립하고 실행합니다. 데이터 분석을 통한 지속적인 최적화를 제공합니다.',
shortDescription: 'SEO, 소셜미디어, 온라인 광고를 통한 디지털 마케팅',
icon: 'fas fa-chart-line',
category: 'marketing',
pricing: {
basePrice: 200000,
currency: 'KRW',
priceType: 'project',
priceRange: { min: 200000, max: 1500000 }
},
featured: true,
isActive: true
}
];
const mockSettings = {
siteName: 'SmartSolTech',
siteDescription: '혁신적인 기술 솔루션으로 비즈니스의 성장을 지원합니다',
contact: {
email: 'info@smartsoltech.kr',
phone: '+82-10-1234-5678',
address: 'Seoul, South Korea'
},
social: {
facebook: 'https://facebook.com/smartsoltech',
twitter: 'https://twitter.com/smartsoltech',
linkedin: 'https://linkedin.com/company/smartsoltech',
instagram: 'https://instagram.com/smartsoltech'
}
};
// Helper function for category names
function getCategoryName(category) {
const categoryNames = {
'web-development': '웹 개발',
'mobile-app': '모바일 앱',
'ui-ux-design': 'UI/UX 디자인',
'branding': '브랜딩',
'marketing': '디지털 마케팅'
};
return categoryNames[category] || category;
}
// Language switching route
app.get('/lang/:language', (req, res) => {
const language = req.params.language;
const supportedLanguages = ['en', 'ko', 'ru', 'kk'];
if (supportedLanguages.includes(language)) {
res.cookie('language', language, { maxAge: 365 * 24 * 60 * 60 * 1000 }); // 1 year
req.setLocale(language);
}
const redirectUrl = req.get('Referer') || '/';
res.redirect(redirectUrl);
});
// Middleware to set language and theme preferences
app.use((req, res, next) => {
// Set language
const language = req.cookies.language || req.query.lang || 'ko';
if (['en', 'ko', 'ru', 'kk'].includes(language)) {
req.setLocale(language);
}
// Set theme preference
const theme = req.cookies.theme || 'light';
res.locals.theme = theme;
res.locals.currentLanguage = req.getLocale();
res.locals.__ = res.__;
next();
});
// Theme switching route
app.get('/theme/:theme', (req, res) => {
const theme = req.params.theme;
if (['light', 'dark'].includes(theme)) {
res.cookie('theme', theme, { maxAge: 365 * 24 * 60 * 60 * 1000 }); // 1 year
}
const redirectUrl = req.get('Referer') || '/';
res.redirect(redirectUrl);
});
// Routes
app.get('/', (req, res) => {
res.render('index', {
title: res.__('navigation.home') + ' - SmartSolTech',
settings: mockSettings,
featuredPortfolio: mockPortfolio.filter(p => p.featured),
featuredServices: mockServices.filter(s => s.featured),
currentPage: 'home'
});
});
app.get('/portfolio', (req, res) => {
const category = req.query.category;
let filteredPortfolio = mockPortfolio;
if (category && category !== 'all') {
filteredPortfolio = mockPortfolio.filter(p => p.category === category);
}
res.render('portfolio', {
title: res.__('navigation.portfolio') + ' - SmartSolTech',
portfolioItems: filteredPortfolio,
currentPage: 'portfolio'
});
});
app.get('/portfolio/:id', (req, res) => {
const portfolio = mockPortfolio.find(p => p._id === req.params.id);
if (!portfolio) {
return res.status(404).render('error', {
title: '404 - ' + res.__('common.error'),
message: res.__('common.error'),
currentPage: 'error'
});
}
const relatedProjects = mockPortfolio.filter(p =>
p._id !== portfolio._id && p.category === portfolio.category
).slice(0, 3);
res.render('portfolio-detail', {
title: `${portfolio.title} - ${res.__('navigation.portfolio')}`,
portfolio,
relatedProjects,
currentPage: 'portfolio'
});
});
app.get('/services', (req, res) => {
res.render('services', {
title: res.__('navigation.services') + ' - SmartSolTech',
services: mockServices,
currentPage: 'services'
});
});
app.get('/about', (req, res) => {
res.render('about', {
title: res.__('navigation.about') + ' - SmartSolTech',
currentPage: 'about'
});
});
app.get('/contact', (req, res) => {
res.render('contact', {
title: res.__('navigation.contact') + ' - SmartSolTech',
settings: mockSettings,
currentPage: 'contact'
});
});
app.post('/contact', (req, res) => {
// Simulate contact form processing
console.log('Contact form submission:', req.body);
req.flash('success', res.__('common.success'));
res.redirect('/contact');
});
app.get('/calculator', (req, res) => {
res.render('calculator', {
title: res.__('navigation.calculator') + ' - SmartSolTech',
services: mockServices,
currentPage: 'calculator'
});
});
// API Routes for calculator
app.post('/api/calculator/estimate', (req, res) => {
const { service, projectType, timeline, features } = req.body;
// Simple calculation logic
let basePrice = 500000;
const selectedService = mockServices.find(s => s._id === service);
if (selectedService) {
basePrice = selectedService.pricing.basePrice;
}
// Apply multipliers based on project complexity
const typeMultipliers = {
'simple': 1,
'medium': 1.5,
'complex': 2.5,
'enterprise': 4
};
const timelineMultipliers = {
'urgent': 1.5,
'normal': 1,
'flexible': 0.9
};
const typeMultiplier = typeMultipliers[projectType] || 1;
const timelineMultiplier = timelineMultipliers[timeline] || 1;
const featuresMultiplier = 1 + (features?.length || 0) * 0.2;
const estimatedPrice = Math.round(basePrice * typeMultiplier * timelineMultiplier * featuresMultiplier);
res.json({
success: true,
estimate: {
basePrice,
estimatedPrice,
breakdown: {
basePrice,
projectType: projectType,
typeMultiplier,
timeline,
timelineMultiplier,
features: features || [],
featuresMultiplier
}
}
});
});
// API Routes for portfolio interactions
app.post('/api/portfolio/:id/like', (req, res) => {
const portfolio = mockPortfolio.find(p => p._id === req.params.id);
if (portfolio) {
portfolio.likes = (portfolio.likes || 0) + 1;
res.json({ success: true, likes: portfolio.likes });
} else {
res.status(404).json({ success: false, message: 'Portfolio not found' });
}
});
app.post('/api/portfolio/:id/view', (req, res) => {
const portfolio = mockPortfolio.find(p => p._id === req.params.id);
if (portfolio) {
portfolio.viewCount = (portfolio.viewCount || 0) + 1;
res.json({ success: true, viewCount: portfolio.viewCount });
} else {
res.status(404).json({ success: false, message: 'Portfolio not found' });
}
});
// Error handling
app.use((req, res) => {
res.status(404).render('error', {
title: '404 - 페이지를 찾을 수 없습니다',
message: '요청하신 페이지를 찾을 수 없습니다.',
currentPage: '404'
});
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).render('error', {
title: '500 - 서버 오류',
message: '서버에서 오류가 발생했습니다.',
currentPage: 'error'
});
});
// Start server
app.listen(PORT, () => {
console.log(`🚀 SmartSolTech Demo Server running on http://localhost:${PORT}`);
console.log('📋 Available pages:');
console.log(' • Home: http://localhost:3000/');
console.log(' • About: http://localhost:3000/about');
console.log(' • Portfolio: http://localhost:3000/portfolio');
console.log(' • Services: http://localhost:3000/services');
console.log(' • Contact: http://localhost:3000/contact');
console.log(' • Calculator: http://localhost:3000/calculator');
console.log('');
console.log('💡 This is a demo version using mock data');
console.log('💾 To use with MongoDB, run: npm start');
});
module.exports = app;