microtecflix/src/db/db.ts

456 lines
16 KiB
TypeScript

import fs from 'fs';
import path from 'path';
import bcrypt from 'bcryptjs';
import { User, Course, Module, Lesson, Note, LessonProgress, WebhookLog, SubscriptionPayment, Plan } from '../types';
const DATA_DIR = process.env.DATA_DIR || (fs.existsSync('/app/data') ? '/app/data' : process.cwd());
const DB_FILE = path.join(DATA_DIR, 'database.json');
export interface DatabaseSchema {
users: User[];
courses: Course[];
modules: Module[];
lessons: Lesson[];
notes: Note[];
progress: LessonProgress[];
webhookLogs: WebhookLog[];
payments: SubscriptionPayment[];
activities: any[];
moduleGrades: any[];
certificates: any[];
notifications: any[];
settings: any; // SystemSettings
plans: Plan[];
}
const DEFAULT_DB: DatabaseSchema = {
users: [],
courses: [],
modules: [],
lessons: [],
notes: [],
progress: [],
webhookLogs: [],
payments: [],
activities: [],
moduleGrades: [],
certificates: [],
notifications: [],
settings: {
trialDurationDays: 7,
asaasEnvironment: 'sandbox',
asaasApiKey: '',
asaasWebhookUrl: '',
asaasWebhookSecret: '',
helpText: '# Central de Ajuda\n\nAqui você encontra todas as informações sobre os cursos e funcionamento da plataforma.'
},
plans: []
};
// Helper to load db
export function loadDb(): DatabaseSchema {
try {
if (!fs.existsSync(DB_FILE)) {
const db = createInitialDb();
saveDb(db);
return db;
}
const data = fs.readFileSync(DB_FILE, 'utf-8');
const parsedData = JSON.parse(data);
if (!parsedData.plans) {
parsedData.plans = [];
}
return parsedData;
} catch (err) {
console.error('Error loading database:', err);
return DEFAULT_DB;
}
}
// Helper to save db
export function saveDb(data: DatabaseSchema): void {
try {
fs.writeFileSync(DB_FILE, JSON.stringify(data, null, 2), 'utf-8');
} catch (err) {
console.error('Error saving database:', err);
}
}
function createInitialDb(): DatabaseSchema {
const salt = bcrypt.genSaltSync(10);
const adminPasswordHash = bcrypt.hashSync('admin123', salt);
const studentPasswordHash = bcrypt.hashSync('aluno123', salt);
const now = new Date().toISOString();
const users: User[] = [
{
id: 'usr_admin',
name: 'Sidney Gomes (Admin)',
email: 'sidney.gomes1989@gmail.com',
password: adminPasswordHash,
role: 'admin',
subscriptionStatus: 'ACTIVE',
asaasCustomerId: null,
cpf: '691.238.910-40',
whatsapp: '11999999999',
birthDate: '1989-05-15',
unlockedCourses: [],
createdAt: now
},
{
id: 'usr_student1',
name: 'João Silva',
email: 'joao@microtecflix.com',
password: studentPasswordHash,
role: 'student',
subscriptionStatus: 'ACTIVE',
asaasCustomerId: 'cus_00001',
cpf: '691.238.910-40',
whatsapp: '11999999999',
birthDate: '1989-05-15',
unlockedCourses: ['crs_excel'], // Excel starts unlocked for Joao
createdAt: new Date(Date.now() - 30 * 24 * 3600 * 1000).toISOString()
},
{
id: 'usr_student2',
name: 'Maria Santos',
email: 'maria@microtecflix.com',
password: studentPasswordHash,
role: 'student',
subscriptionStatus: 'ACTIVE',
asaasCustomerId: 'cus_00002',
cpf: '691.238.910-40',
whatsapp: '11999999999',
birthDate: '1989-05-15',
unlockedCourses: [],
createdAt: new Date(Date.now() - 15 * 24 * 3600 * 1000).toISOString()
},
{
id: 'usr_student3',
name: 'Pedro Oliveira',
email: 'pedro@microtecflix.com',
password: studentPasswordHash,
role: 'student',
subscriptionStatus: 'OVERDUE',
asaasCustomerId: 'cus_00003',
cpf: '691.238.910-40',
whatsapp: '11999999999',
birthDate: '1989-05-15',
unlockedCourses: [],
createdAt: new Date(Date.now() - 45 * 24 * 3600 * 1000).toISOString()
},
{
id: 'usr_student4',
name: 'Ana Costa',
email: 'ana@microtecflix.com',
password: studentPasswordHash,
role: 'student',
subscriptionStatus: 'CANCELED',
asaasCustomerId: 'cus_00004',
cpf: '691.238.910-40',
whatsapp: '11999999999',
birthDate: '1989-05-15',
unlockedCourses: [],
createdAt: new Date(Date.now() - 60 * 24 * 3600 * 1000).toISOString()
},
{
id: 'usr_student_test',
name: 'Aluno de Teste',
email: 'aluno@microtecflix.com',
password: studentPasswordHash,
role: 'student',
subscriptionStatus: 'ACTIVE',
asaasCustomerId: 'cus_test',
cpf: '691.238.910-40',
whatsapp: '11999999999',
birthDate: '1989-05-15',
unlockedCourses: [], // Starts with only the free courses unlocked
createdAt: now
}
];
const courses: Course[] = [
{
id: 'crs_windows',
title: 'Sistema Operacional Windows 11 para Escritório',
description: 'Domine o sistema operacional mais utilizado no mundo corporativo. Aprenda a organizar arquivos, configurar o painel de controle, gerenciar usuários e utilizar ferramentas de produtividade para escritório de forma ágil e segura.',
thumbnail: 'https://images.unsplash.com/photo-1624555130581-1d9cca783bc0?q=80&w=600&auto=format&fit=crop',
category: 'Sistemas Operacionais',
isLocked: false,
price: 0,
createdAt: now
},
{
id: 'crs_word',
title: 'Microsoft Word Profissional',
description: 'Crie relatórios, contratos, trabalhos acadêmicos nas normas ABNT e documentos de escritório altamente profissionais. Domine formatação avançada, tabelas, sumários automáticos e malas diretas dinâmicas.',
thumbnail: 'https://images.unsplash.com/photo-1586075010923-2dd4570fb338?q=80&w=600&auto=format&fit=crop',
category: 'Pacote Office',
isLocked: false,
price: 0,
createdAt: now
},
{
id: 'crs_excel',
title: 'Microsoft Excel - Do Básico ao Dashboard',
description: 'O software de planilhas mais exigido pelo mercado de trabalho mundial. Aprenda desde fórmulas fundamentais (SOMA, SE, PROCV, CONT.SE) até tabelas dinâmicas, gráficos executivos, automações e dashboards de impacto profissional.',
thumbnail: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?q=80&w=600&auto=format&fit=crop',
category: 'Pacote Office',
isLocked: true,
price: 89.90,
createdAt: now
},
{
id: 'crs_powerpoint',
title: 'PowerPoint para Apresentações de Impacto',
description: 'Aprenda a estruturar e desenhar apresentações profissionais e persuasivas para reuniões de negócios, projetos ou aulas. Domine o efeito de transição Transformar (Morph), inserção de mídias inteligentes e animações profissionais.',
thumbnail: 'https://images.unsplash.com/photo-1516321318423-f06f85e504b3?q=80&w=600&auto=format&fit=crop',
category: 'Pacote Office',
isLocked: true,
price: 59.90,
createdAt: now
}
];
const modules: Module[] = [
// Windows 11
{ id: 'mdl_win_1', courseId: 'crs_windows', title: 'Fundamentos e Área de Trabalho', order: 1, createdAt: now },
{ id: 'mdl_win_2', courseId: 'crs_windows', title: 'Configurações e Segurança de Dados', order: 2, createdAt: now },
// Word
{ id: 'mdl_wrd_1', courseId: 'crs_word', title: 'Interface e Formatação de Textos', order: 1, createdAt: now },
{ id: 'mdl_wrd_2', courseId: 'crs_word', title: 'Layouts, Tabelas e Sumários', order: 2, createdAt: now },
// Excel
{ id: 'mdl_exc_1', courseId: 'crs_excel', title: 'Células, Fórmulas e Funções Principais', order: 1, createdAt: now },
{ id: 'mdl_exc_2', courseId: 'crs_excel', title: 'Tabelas Dinâmicas e Dashboards', order: 2, createdAt: now },
// PowerPoint
{ id: 'mdl_ppt_1', courseId: 'crs_powerpoint', title: 'Layout de Slides e Formas', order: 1, createdAt: now },
{ id: 'mdl_ppt_2', courseId: 'crs_powerpoint', title: 'Transições Especiais e Apresentação', order: 2, createdAt: now }
];
const lessons: Lesson[] = [
// Windows - Módulo 1
{
id: 'lsn_win_1_1',
moduleId: 'mdl_win_1',
title: 'Dominando a Nova Área de Trabalho e Barra de Tarefas do Windows 11',
videoUrl: 'https://www.youtube.com/embed/9e9D_bZfT8o',
videoType: 'youtube',
order: 1,
content: 'Nesta aula, você aprenderá a se localizar e customizar a nova barra de tarefas centralizada e a área de trabalho do Windows 11.',
createdAt: now
},
{
id: 'lsn_win_1_2',
moduleId: 'mdl_win_1',
title: 'Gerenciador de Arquivos e Organização Eficiente de Pastas',
videoUrl: 'https://www.youtube.com/embed/Pj1_bAn_m4Y',
videoType: 'youtube',
order: 2,
content: 'Aprenda a criar estruturas de pastas organizadas, atalhos rápidos e a usar o novo explorador de arquivos com abas do Windows.',
createdAt: now
},
// Windows - Módulo 2
{
id: 'lsn_win_2_1',
moduleId: 'mdl_win_2',
title: 'Painel de Configurações e Segurança com Windows Defender',
videoUrl: 'https://www.youtube.com/embed/K8w3m_pM6lA',
videoType: 'youtube',
order: 1,
content: 'Como configurar rede wi-fi, dispositivos bluetooth, impressoras e garantir que seu antivírus integrado esteja sempre atualizado.',
createdAt: now
},
// Word - Módulo 1
{
id: 'lsn_wrd_1_1',
moduleId: 'mdl_wrd_1',
title: 'Conhecendo a Faixa de Opções e Formatando Fontes e Parágrafos',
videoUrl: 'https://www.youtube.com/embed/Epn879GkIis',
videoType: 'youtube',
order: 1,
content: 'Entenda os principais comandos da guia Página Inicial e como aplicar formatações essenciais de texto.',
createdAt: now
},
// Word - Módulo 2
{
id: 'lsn_wrd_2_1',
moduleId: 'mdl_wrd_2',
title: 'Criação de Sumários Automáticos com Estilos de Título',
videoUrl: 'https://www.youtube.com/embed/2_W6C3vjD1s',
videoType: 'youtube',
order: 1,
content: 'Evite o trabalho manual! Aprenda a usar os Estilos (Título 1, Título 2) para que o Microsoft Word gere seu sumário em um clique.',
createdAt: now
},
// Excel - Módulo 1
{
id: 'lsn_exc_1_1',
moduleId: 'mdl_exc_1',
title: 'Dominando Fórmulas Básicas: SOMA, MÉDIA e Função Lógica SE',
videoUrl: 'https://www.youtube.com/embed/3S-F9h-gRjA',
videoType: 'youtube',
order: 1,
content: 'Entenda a sintaxe de fórmulas no Excel, referências relativas/absolutas ($) e como aplicar a famosa função SE.',
createdAt: now
},
// Excel - Módulo 2
{
id: 'lsn_exc_2_1',
moduleId: 'mdl_exc_2',
title: 'Criando sua Primeira Tabela Dinâmica e Gráficos de Vendas',
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4',
videoType: 'direct',
order: 1,
content: 'Aprenda a consolidar milhares de linhas de dados em resumos inteligentes usando tabelas dinâmicas.',
createdAt: now
},
// PowerPoint - Módulo 1
{
id: 'lsn_ppt_1_1',
moduleId: 'mdl_ppt_1',
title: 'Trabalhando com Layouts Próprios e Inserção de Imagens e Ícones',
videoUrl: 'https://www.youtube.com/embed/Y0iI9wzY_L4',
videoType: 'youtube',
order: 1,
content: 'Esqueça os designs prontos e ultrapassados! Aprenda a criar layouts autorais limpos, modernos e profissionais.',
createdAt: now
},
// PowerPoint - Módulo 2
{
id: 'lsn_ppt_2_1',
moduleId: 'mdl_ppt_2',
title: 'O Poder da Transição Transformar (Morph) em Apresentações',
videoUrl: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
videoType: 'direct',
order: 1,
content: 'Aprenda a criar animações fluidas e dinâmicas dignas de cinema utilizando o Morph do PowerPoint.',
createdAt: now
}
];
const notes: Note[] = [
{
id: 'note_1',
userId: 'usr_student_test',
lessonId: 'lsn_win_1_1',
content: 'Anotação de Teste: Atalho Windows + D serve para mostrar ou ocultar a Área de Trabalho instantaneamente!',
createdAt: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString()
}
];
const progress: LessonProgress[] = [
{
id: 'prog_1',
userId: 'usr_student_test',
lessonId: 'lsn_win_1_1',
watchedPercentage: 95,
completed: true,
updatedAt: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString()
},
{
id: 'prog_2',
userId: 'usr_student_test',
lessonId: 'lsn_win_1_2',
watchedPercentage: 45,
completed: false,
updatedAt: now
}
];
const payments: SubscriptionPayment[] = [
{
id: 'pay_1',
userId: 'usr_student1',
value: 49.90,
status: 'CONFIRMED',
billingType: 'PIX',
invoiceUrl: 'https://www.asaas.com/i/fake_invoice_1',
dueDate: new Date(Date.now() - 5 * 24 * 3600 * 1000).toISOString().split('T')[0],
paidAt: new Date(Date.now() - 5 * 24 * 3600 * 1000).toISOString(),
createdAt: new Date(Date.now() - 6 * 24 * 3600 * 1000).toISOString()
},
{
id: 'pay_2',
userId: 'usr_student2',
value: 49.90,
status: 'CONFIRMED',
billingType: 'CREDIT_CARD',
invoiceUrl: 'https://www.asaas.com/i/fake_invoice_2',
dueDate: new Date(Date.now() - 2 * 24 * 3600 * 1000).toISOString().split('T')[0],
paidAt: new Date(Date.now() - 2 * 24 * 3600 * 1000).toISOString(),
createdAt: new Date(Date.now() - 2 * 24 * 3600 * 1000).toISOString()
},
{
id: 'pay_3',
userId: 'usr_student3',
value: 49.90,
status: 'OVERDUE',
billingType: 'BOLETO',
invoiceUrl: 'https://www.asaas.com/i/fake_invoice_3',
dueDate: new Date(Date.now() - 10 * 24 * 3600 * 1000).toISOString().split('T')[0],
paidAt: null,
createdAt: new Date(Date.now() - 10 * 24 * 3600 * 1000).toISOString()
},
{
id: 'pay_test_1',
userId: 'usr_student_test',
value: 49.90,
status: 'CONFIRMED',
billingType: 'PIX',
invoiceUrl: 'https://www.asaas.com/i/fake_invoice_test',
dueDate: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString().split('T')[0],
paidAt: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString(),
createdAt: new Date(Date.now() - 1 * 24 * 3600 * 1000).toISOString()
}
];
const webhookLogs: WebhookLog[] = [
{
id: 'wh_log_1',
event: 'PAYMENT_RECEIVED',
payload: JSON.stringify({ id: 'pay_1', subscription: 'sub_0001', value: 49.90, customer: 'cus_00001' }),
receivedAt: new Date(Date.now() - 5 * 24 * 3600 * 1000).toISOString()
},
{
id: 'wh_log_2',
event: 'PAYMENT_CONFIRMED',
payload: JSON.stringify({ id: 'pay_2', subscription: 'sub_0002', value: 49.90, customer: 'cus_00002' }),
receivedAt: new Date(Date.now() - 2 * 24 * 3600 * 1000).toISOString()
},
{
id: 'wh_log_3',
event: 'PAYMENT_OVERDUE',
payload: JSON.stringify({ id: 'pay_3', subscription: 'sub_0003', value: 49.90, customer: 'cus_00003' }),
receivedAt: new Date(Date.now() - 10 * 24 * 3600 * 1000).toISOString()
}
];
return {
users,
courses,
modules,
lessons,
notes,
progress,
webhookLogs,
payments,
activities: [],
moduleGrades: [],
certificates: [],
notifications: [],
settings: {
trialDurationDays: 7,
asaasEnvironment: 'sandbox',
asaasApiKey: '',
asaasWebhookUrl: '',
asaasWebhookSecret: '',
helpText: '# Central de Ajuda\n\nAqui você encontra todas as informações sobre os cursos e funcionamento da plataforma.'
},
plans: []
};
}