Update refactor to modules all

This commit is contained in:
Cesar Mendivil 2025-11-03 14:42:20 -07:00
parent a795d1ad9f
commit ebff1353f8
71 changed files with 5076 additions and 63 deletions

296
ARCHITECTURE.md Normal file
View File

@ -0,0 +1,296 @@
# AvanzaCast - Arquitectura Modular
## Visión General
AvanzaCast se divide en 4 módulos principales que funcionan de forma independiente pero comunicada:
```
AvanzaCast/
├── packages/
│ ├── landing-page/ # Módulo público (Next.js/Vite)
│ ├── backend-api/ # API central (Node.js + Express)
│ ├── broadcast-studio/ # Studio de streaming (React + WebRTC)
│ └── admin-panel/ # Panel SaaS (React + Admin UI)
├── shared/
│ ├── types/ # TypeScript types compartidos
│ ├── utils/ # Utilidades compartidas
│ └── config/ # Configuración compartida
└── docs/
├── api/ # Documentación de APIs
└── deployment/ # Guías de despliegue
```
## Módulos
### 1. Landing Page (Public)
**Tecnología**: Next.js 15 / Vite + React
**Puerto**: 3000
**Responsabilidades**:
- Marketing y presentación del producto
- Registro de nuevos usuarios
- Login y autenticación inicial
- Pricing y planes
- Blog/recursos
- SEO optimizado
**Conexiones**:
- → `backend-api` para registro/login
- → Redirección a `broadcast-studio` post-login
- → Redirección a `admin-panel` para admins
---
### 2. Backend API (Core)
**Tecnología**: Node.js + Express + TypeScript
**Puerto**: 4000
**Base de datos**: PostgreSQL + Redis
**Responsabilidades**:
- Autenticación (JWT) y autorización
- Gestión de usuarios y perfiles
- Planes de pago (Stripe/PayPal)
- Integraciones externas:
- YouTube API
- Facebook Graph API
- Twitch API
- LinkedIn API
- WebSocket para streaming en vivo
- Storage (S3/MinIO) para grabaciones
- Transcoding (FFmpeg) de videos
- Analytics y métricas
**Endpoints principales**:
```
/api/v1/auth/* # Autenticación
/api/v1/users/* # Gestión de usuarios
/api/v1/subscriptions/* # Planes y pagos
/api/v1/streaming/* # Sesiones de streaming
/api/v1/integrations/* # Conexiones a plataformas
/api/v1/media/* # Grabaciones y assets
```
**Conexiones**:
- ← Recibe requests de todos los frontends
- → PostgreSQL para persistencia
- → Redis para cache y sesiones
- → S3/MinIO para almacenamiento
- → APIs externas (YouTube, Facebook, etc)
---
### 3. Broadcast Studio (App Principal)
**Tecnología**: React + TypeScript + WebRTC
**Puerto**: 3001
**Responsabilidades**:
- Estudio virtual de streaming
- WebRTC para captura de video/audio
- Gestión de escenas y overlays
- Multistream simultáneo
- Chat en tiempo real
- Invitados y colaboración
- Controles de streaming (start/stop/pause)
- Preview en tiempo real
**Características clave**:
- Editor de escenas drag & drop
- Biblioteca de overlays y branding
- Monitor de calidad de stream
- Grabación local y en la nube
- Gestión de invitados (green room)
**Conexiones**:
- → `backend-api` para autenticación
- → `backend-api` WebSocket para streaming
- → APIs de plataformas vía `backend-api`
---
### 4. Admin Panel (SaaS Dashboard)
**Tecnología**: React + TypeScript + Admin UI (Ant Design/Material-UI)
**Puerto**: 3002
**Responsabilidades**:
- Dashboard de métricas globales
- Gestión de usuarios:
- CRUD de usuarios
- Asignación de roles
- Suspensión/activación de cuentas
- Gestión de planes de pago:
- Crear/editar planes
- Ver suscripciones activas
- Historial de pagos
- Facturación
- Configuración de plataforma:
- Límites de streaming
- Integraciones habilitadas
- Configuración de storage
- Analytics y reportes:
- Usuarios activos
- Minutos de streaming
- Revenue por plan
- Uso de recursos
- Soporte:
- Tickets de usuarios
- Logs de errores
- Auditoría de sistema
**Roles**:
- Super Admin: Acceso total
- Admin: Gestión de usuarios y contenido
- Support: Solo lectura y soporte
**Conexiones**:
- → `backend-api` con permisos de admin
- ← Solo accesible para usuarios con rol admin
---
## Comunicación entre Módulos
### Autenticación Compartida (JWT)
```typescript
// Token JWT compartido entre módulos
interface JWTPayload {
userId: string;
email: string;
role: 'user' | 'admin' | 'super_admin';
subscription: {
plan: 'free' | 'starter' | 'pro' | 'enterprise';
status: 'active' | 'cancelled' | 'expired';
};
exp: number;
}
```
### Flow de Autenticación
```
1. Usuario → Landing Page (login)
2. Landing → Backend API (/api/v1/auth/login)
3. Backend → Responde con JWT
4. Landing → Guarda JWT en localStorage
5. Landing → Redirige a Broadcast Studio con token
6. Broadcast Studio → Valida JWT con Backend
7. Broadcast Studio → Inicia sesión del usuario
```
### Variables de Entorno por Módulo
**landing-page/.env**:
```bash
VITE_API_URL=http://localhost:4000
VITE_STUDIO_URL=http://localhost:3001
VITE_ADMIN_URL=http://localhost:3002
```
**backend-api/.env**:
```bash
PORT=4000
DATABASE_URL=postgresql://user:pass@localhost:5432/avanzacast
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-secret-key
STRIPE_SECRET_KEY=sk_test_...
AWS_S3_BUCKET=avanzacast-recordings
# Platform APIs
YOUTUBE_CLIENT_ID=...
YOUTUBE_CLIENT_SECRET=...
FACEBOOK_APP_ID=...
FACEBOOK_APP_SECRET=...
TWITCH_CLIENT_ID=...
TWITCH_CLIENT_SECRET=...
```
**broadcast-studio/.env**:
```bash
VITE_API_URL=http://localhost:4000
VITE_WS_URL=ws://localhost:4000
```
**admin-panel/.env**:
```bash
VITE_API_URL=http://localhost:4000
```
---
## Stack Tecnológico Detallado
### Frontend (Todos los módulos)
- **Framework**: React 18 + TypeScript
- **Build Tool**: Vite 4
- **Routing**: React Router v6
- **State Management**: Zustand / Redux Toolkit
- **UI Components**:
- Landing: Tailwind CSS + HeadlessUI
- Studio: Tailwind CSS + Custom Components
- Admin: Ant Design / Material-UI
- **HTTP Client**: Axios
- **WebSocket**: Socket.io-client
- **Forms**: React Hook Form + Zod
### Backend
- **Runtime**: Node.js 20 LTS
- **Framework**: Express.js
- **Language**: TypeScript
- **ORM**: Prisma / TypeORM
- **Validation**: Zod
- **Authentication**: Passport.js + JWT
- **WebSocket**: Socket.io
- **File Upload**: Multer
- **Video Processing**: FFmpeg
### Base de datos
- **Primary**: PostgreSQL 15
- **Cache**: Redis 7
- **Storage**: AWS S3 / MinIO
### DevOps
- **Containerización**: Docker + Docker Compose
- **Monorepo**: Turborepo / Nx
- **CI/CD**: GitHub Actions
- **Hosting**:
- Frontend: Vercel / Netlify
- Backend: Railway / Render / AWS EC2
- DB: Railway / AWS RDS
---
## Próximos Pasos de Implementación
1. ✅ Crear estructura de carpetas
2. ⏳ Configurar monorepo (Turborepo)
3. ⏳ Migrar landing actual a `packages/landing-page`
4. ⏳ Crear backend-api base con Express + TypeScript
5. ⏳ Configurar base de datos (Prisma + PostgreSQL)
6. ⏳ Implementar autenticación JWT
7. ⏳ Crear broadcast-studio base
8. ⏳ Crear admin-panel base
9. ⏳ Configurar comunicación entre módulos
10. ⏳ Implementar integraciones con plataformas
---
## Estructura de Desarrollo
```bash
# Instalar dependencias de todos los módulos
npm install
# Desarrollo (todos los módulos)
npm run dev
# Desarrollo individual
npm run dev:landing
npm run dev:api
npm run dev:studio
npm run dev:admin
# Build de producción
npm run build
# Tests
npm run test
```
---
**Fecha**: 3 de noviembre de 2025
**Versión**: 1.0.0
**Estado**: En diseño

178
README.md
View File

@ -1,13 +1,175 @@
# AvanzaCast - Vite prototype # AvanzaCast - Plataforma de Streaming SaaS Modular# AvanzaCast - Vite prototype
Pequeño prototipo con Vite + React + TypeScript + Tailwind (estilo Vristo minimal).
Instalación:
```bash ## 📋 DescripciónPequeño prototipo con Vite + React + TypeScript + Tailwind (estilo Vristo minimal).
cd vite-app
npm install Plataforma de streaming en vivo tipo StreamYard con arquitectura modular SaaS:
npm run dev
- 🎬 Transmisión multistream (YouTube, Facebook, Twitch, LinkedIn)Instalación:
- 🎥 Estudio virtual con WebRTC
- 💬 Chat en tiempo real```bash
- 📹 Grabación y almacenamiento en la nubecd vite-app
- 👥 Gestión de invitados y colaboraciónnpm install
- 🎨 Personalización de escenas con overlaysnpm run dev
- 💳 Sistema de suscripciones y pagos```
## 🏗️ Arquitectura MonorepoEl servidor dev arranca en http://localhost:5173 por defecto.
Este proyecto usa **npm workspaces** con 4 módulos principales:
```
packages/
├── landing-page/ # Landing y registro (Puerto 3000)
├── backend-api/ # API REST + WebSocket (Puerto 4000)
├── broadcast-studio/ # Estudio de streaming (Puerto 3001)
└── admin-panel/ # Panel SaaS admin (Puerto 3002)
``` ```
El servidor dev arranca en http://localhost:5173 por defecto. ### 🌐 Landing Page (Puerto 3000)
- **Tech**: React 18 + Vite + Tailwind CSS
- **Función**: Marketing, registro, login
- **Rutas**: `/`, `/login`, `/register`
### 🔌 Backend API (Puerto 4000)
- **Tech**: Node.js 20 + Express + TypeScript + Prisma + PostgreSQL + Redis
- **Función**: Autenticación JWT, gestión usuarios, pagos, integraciones
- **Endpoints**: `/api/v1/*`
### 🎬 Broadcast Studio (Puerto 3001)
- **Tech**: React 18 + Vite + WebRTC + Socket.IO + Tailwind CSS
- **Función**: Estudio virtual, multistream, escenas, overlays
- **Características**: Transmisión en vivo, gestión de cámaras y audio
### ⚙️ Admin Panel (Puerto 3002)
- **Tech**: React 18 + Vite + Ant Design + Recharts
- **Función**: Panel SaaS (usuarios, suscripciones, analytics, facturación)
- **Características**: Dashboard, gestión usuarios, planes de pago
## 🚀 Instalación y Desarrollo
### Requisitos
- Node.js >= 20.0.0
- npm >= 10.0.0
- PostgreSQL 15
- Redis 7
### Instalación
```bash
# Instalar todas las dependencias del monorepo
npm install
```
### Desarrollo
```bash
# Todos los módulos simultáneamente
npm run dev
# Módulos individuales
npm run dev:landing # Landing page (3000)
npm run dev:api # Backend API (4000)
npm run dev:studio # Broadcast Studio (3001)
npm run dev:admin # Admin Panel (3002)
```
### Build
```bash
# Build completo
npm run build
# Build individual
npm run build:landing
npm run build:api
npm run build:studio
npm run build:admin
```
## 📦 Stack Tecnológico
### Frontend (Landing, Studio, Admin)
- React 18.2.0
- Vite 4.3.9
- TypeScript 5.2.2
- Tailwind CSS 3.4.16
- React Router v6
- Ant Design 5.x (Admin Panel)
- Zustand (Estado global)
### Backend API
- Node.js 20 LTS
- Express 4.18
- TypeScript 5.2.2
- Prisma ORM
- PostgreSQL 15
- Redis 7
- Socket.IO 4.6
- JWT + bcrypt
- Stripe (pagos)
### Integraciones
- YouTube Data API v3
- Facebook Graph API
- Twitch API
- LinkedIn API
- AWS S3 / MinIO (almacenamiento)
- FFmpeg (procesamiento video)
## 📚 Documentación Completa
Consulta `ARCHITECTURE.md` para:
- Diagramas de arquitectura
- Flujos de autenticación
- Estructura de base de datos
- API endpoints completos
- Variables de entorno
- Patrones de comunicación entre módulos
## 🔐 Configuración de Backend
1. Copia el archivo de ejemplo:
```bash
cp packages/backend-api/.env.example packages/backend-api/.env
```
2. Configura las variables de entorno (DATABASE_URL, JWT_SECRET, etc.)
3. Ejecuta migraciones de Prisma:
```bash
cd packages/backend-api
npm run prisma:migrate
```
## 📈 Roadmap MVP
- [x] Estructura monorepo
- [x] Landing page funcional
- [x] Backend API base
- [x] Broadcast Studio UI base
- [x] Admin Panel UI base
- [ ] Autenticación JWT completa
- [ ] Base de datos PostgreSQL + Prisma
- [ ] WebRTC streaming
- [ ] Multistream (YouTube, Facebook)
- [ ] Sistema de suscripciones Stripe
- [ ] Grabación en la nube
## 🤝 Contribución
1. Fork el proyecto
2. Crea una rama feature (`git checkout -b feature/AmazingFeature`)
3. Commit tus cambios (`git commit -m 'Add some AmazingFeature'`)
4. Push a la rama (`git push origin feature/AmazingFeature`)
5. Abre un Pull Request
## 📄 Licencia
Proyecto privado - Todos los derechos reservados

4019
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,34 @@
{ {
"name": "avanzacast-vite", "name": "avanzacast-monorepo",
"version": "0.1.0", "version": "1.0.0",
"private": true, "private": true,
"description": "AvanzaCast - Plataforma de Streaming Modular",
"workspaces": [
"packages/*",
"shared/*"
],
"scripts": { "scripts": {
"dev": "vite", "dev": "concurrently \"npm:dev:*\"",
"build": "vite build", "dev:landing": "npm run dev --workspace=packages/landing-page",
"preview": "vite preview" "dev:api": "npm run dev --workspace=packages/backend-api",
}, "dev:studio": "npm run dev --workspace=packages/broadcast-studio",
"dependencies": { "dev:admin": "npm run dev --workspace=packages/admin-panel",
"@heroicons/react": "^2.2.0", "build": "npm run build --workspaces",
"react": "18.2.0", "build:landing": "npm run build --workspace=packages/landing-page",
"react-dom": "18.2.0", "build:api": "npm run build --workspace=packages/backend-api",
"react-router-dom": "^6.30.1" "build:studio": "npm run build --workspace=packages/broadcast-studio",
"build:admin": "npm run build --workspace=packages/admin-panel",
"clean": "rm -rf packages/*/node_modules packages/*/dist shared/*/node_modules node_modules",
"typecheck": "npm run typecheck --workspaces",
"lint": "npm run lint --workspaces",
"test": "npm run test --workspaces"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/forms": "0.5.4", "concurrently": "^8.2.2",
"@tailwindcss/typography": "0.5.9", "typescript": "^5.2.2"
"@types/react": "18.0.28", },
"@types/react-dom": "18.0.11", "engines": {
"@vitejs/plugin-react": "4.0.3", "node": ">=20.0.0",
"autoprefixer": "10.4.14", "npm": ">=10.0.0"
"postcss": "8.4.23",
"tailwindcss": "3.4.16",
"typescript": "5.2.2",
"vite": "4.3.9"
} }
} }

28
package.json.vite-backup Normal file
View File

@ -0,0 +1,28 @@
{
"name": "avanzacast-vite",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@heroicons/react": "^2.2.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "^6.30.1"
},
"devDependencies": {
"@tailwindcss/forms": "0.5.4",
"@tailwindcss/typography": "0.5.9",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@vitejs/plugin-react": "4.0.3",
"autoprefixer": "10.4.14",
"postcss": "8.4.23",
"tailwindcss": "3.4.16",
"typescript": "5.2.2",
"vite": "4.3.9"
}
}

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AvanzaCast Admin - Panel de Control</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,33 @@
{
"name": "@avanzacast/admin-panel",
"version": "1.0.0",
"private": true,
"description": "AvanzaCast - Admin Panel",
"type": "module",
"scripts": {
"dev": "vite --port 3002",
"build": "vite build",
"preview": "vite preview --port 3002",
"typecheck": "tsc --noEmit",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"@ant-design/icons": "^5.2.6",
"antd": "^5.12.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.30.1",
"recharts": "^2.10.3",
"zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"tailwindcss": "^3.4.16",
"typescript": "^5.2.2",
"vite": "^4.3.9"
}
}

View File

@ -0,0 +1,90 @@
import React from 'react';
import { ConfigProvider, Layout, Menu, Typography, Card, Statistic, Row, Col } from 'antd';
import { UserOutlined, VideoCameraOutlined, DollarOutlined, SettingOutlined } from '@ant-design/icons';
const { Header, Sider, Content } = Layout;
const { Title } = Typography;
function App() {
return (
<ConfigProvider
theme={{
token: {
colorPrimary: '#6366f1',
},
}}
>
<Layout style={{ minHeight: '100vh' }}>
<Sider width={250} style={{ background: '#001529' }}>
<div style={{ padding: '16px', color: 'white', fontSize: '18px', fontWeight: 'bold' }}>
AvanzaCast Admin
</div>
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['1']}
items={[
{
key: '1',
icon: <UserOutlined />,
label: 'Usuarios',
},
{
key: '2',
icon: <VideoCameraOutlined />,
label: 'Transmisiones',
},
{
key: '3',
icon: <DollarOutlined />,
label: 'Suscripciones',
},
{
key: '4',
icon: <SettingOutlined />,
label: 'Configuración',
},
]}
/>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: '0 24px' }}>
<Title level={3} style={{ margin: '14px 0' }}>Panel de Control SaaS</Title>
</Header>
<Content style={{ margin: '24px' }}>
<Row gutter={16}>
<Col span={6}>
<Card>
<Statistic title="Usuarios Activos" value={1234} />
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic title="Transmisiones Hoy" value={89} />
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic title="Ingresos Mensuales" value={12450} prefix="$" />
</Card>
</Col>
<Col span={6}>
<Card>
<Statistic title="Suscripciones" value={856} />
</Card>
</Col>
</Row>
<Card style={{ marginTop: 24 }}>
<Title level={4}>Bienvenido al Panel de Administración</Title>
<p>
Gestiona usuarios, planes de pago, transmisiones y configuración de la plataforma AvanzaCast.
</p>
</Card>
</Content>
</Layout>
</Layout>
</ConfigProvider>
);
}
export default App;

View File

@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)

View File

@ -0,0 +1,7 @@
module.exports = {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,9 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3002,
},
})

View File

@ -0,0 +1,38 @@
# Server
PORT=4000
NODE_ENV=development
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/avanzacast?schema=public"
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# JWT
JWT_SECRET=your-super-secret-jwt-key-change-in-production
JWT_EXPIRES_IN=7d
# CORS
FRONTEND_URLS=http://localhost:3000,http://localhost:3001,http://localhost:3002
# External APIs
YOUTUBE_CLIENT_ID=
YOUTUBE_CLIENT_SECRET=
FACEBOOK_APP_ID=
FACEBOOK_APP_SECRET=
TWITCH_CLIENT_ID=
TWITCH_CLIENT_SECRET=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
# Stripe
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
# AWS S3 / MinIO
STORAGE_ENDPOINT=
STORAGE_ACCESS_KEY=
STORAGE_SECRET_KEY=
STORAGE_BUCKET=avanzacast-recordings

View File

@ -0,0 +1,42 @@
{
"name": "@avanzacast/backend-api",
"version": "1.0.0",
"private": true,
"description": "AvanzaCast - Backend API",
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"typecheck": "tsc --noEmit",
"lint": "eslint src --ext ts --report-unused-disable-directives --max-warnings 0",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:studio": "prisma studio"
},
"dependencies": {
"@prisma/client": "^5.7.0",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-rate-limit": "^7.1.5",
"helmet": "^7.1.0",
"ioredis": "^5.3.2",
"joi": "^17.11.0",
"jsonwebtoken": "^9.0.2",
"socket.io": "^4.6.2",
"stripe": "^14.9.0",
"winston": "^3.11.0"
},
"devDependencies": {
"@types/bcryptjs": "^2.4.6",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "^20.10.5",
"prisma": "^5.7.0",
"tsx": "^4.7.0",
"typescript": "^5.2.2"
}
}

View File

@ -0,0 +1,54 @@
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
const PORT = process.env.PORT || 4000;
// Middleware
app.use(helmet());
app.use(cors({
origin: process.env.FRONTEND_URLS?.split(',') || ['http://localhost:3000'],
credentials: true,
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// API Routes
app.get('/api/v1', (req, res) => {
res.json({
message: 'AvanzaCast Backend API',
version: '1.0.0',
endpoints: {
auth: '/api/v1/auth',
users: '/api/v1/users',
broadcasts: '/api/v1/broadcasts',
subscriptions: '/api/v1/subscriptions',
integrations: '/api/v1/integrations',
},
});
});
// 404 handler
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});
// Error handler
app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(PORT, () => {
console.log(`🚀 Backend API running on http://localhost:${PORT}`);
console.log(`📡 Environment: ${process.env.NODE_ENV}`);
});

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022"],
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"strict": true,
"resolveJsonModule": true,
"outDir": "./dist",
"rootDir": "./src",
"forceConsistentCasingInFileNames": true,
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AvanzaCast Studio - Streaming en Vivo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,33 @@
{
"name": "@avanzacast/broadcast-studio",
"version": "1.0.0",
"private": true,
"description": "AvanzaCast - Broadcast Studio",
"type": "module",
"scripts": {
"dev": "vite --port 3001",
"build": "vite build",
"preview": "vite preview --port 3001",
"typecheck": "tsc --noEmit",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"@heroicons/react": "^2.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.30.1",
"socket.io-client": "^4.6.2",
"zustand": "^4.4.7"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.4",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"tailwindcss": "^3.4.16",
"typescript": "^5.2.2",
"vite": "^4.3.9"
}
}

View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -0,0 +1,39 @@
import React from 'react';
function App() {
return (
<div className="min-h-screen bg-gray-900 text-white">
<header className="bg-gray-800 border-b border-gray-700 px-6 py-4">
<h1 className="text-2xl font-bold">AvanzaCast Studio</h1>
<p className="text-sm text-gray-400">Estudio de Transmisión en Vivo</p>
</header>
<main className="p-6">
<div className="max-w-7xl mx-auto">
<div className="bg-gray-800 rounded-lg p-8 text-center">
<h2 className="text-3xl font-bold mb-4">🎥 Estudio Virtual</h2>
<p className="text-gray-300 mb-6">
El módulo de broadcast studio estará disponible próximamente.
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-8">
<div className="bg-gray-700 p-4 rounded">
<h3 className="font-bold mb-2">📹 WebRTC</h3>
<p className="text-sm text-gray-400">Transmisión en tiempo real</p>
</div>
<div className="bg-gray-700 p-4 rounded">
<h3 className="font-bold mb-2">🎬 Escenas</h3>
<p className="text-sm text-gray-400">Control de overlays y cámaras</p>
</div>
<div className="bg-gray-700 p-4 rounded">
<h3 className="font-bold mb-2">📡 Multistream</h3>
<p className="text-sm text-gray-400">YouTube, Facebook, Twitch</p>
</div>
</div>
</div>
</div>
</main>
</div>
);
}
export default App;

View File

@ -0,0 +1,12 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)

View File

@ -0,0 +1,7 @@
module.exports = {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [require('@tailwindcss/forms')],
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,9 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3001,
},
})

View File

@ -0,0 +1,32 @@
{
"name": "@avanzacast/landing-page",
"version": "1.0.0",
"private": true,
"description": "AvanzaCast - Landing Page",
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"build": "vite build",
"preview": "vite preview --port 3000",
"typecheck": "tsc --noEmit",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"@heroicons/react": "^2.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.30.1"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.4",
"@tailwindcss/typography": "^0.5.9",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"tailwindcss": "^3.4.16",
"typescript": "^5.2.2",
"vite": "^4.3.9"
}
}

View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

Before

Width:  |  Height:  |  Size: 789 B

After

Width:  |  Height:  |  Size: 789 B

View File

Before

Width:  |  Height:  |  Size: 765 B

After

Width:  |  Height:  |  Size: 765 B

View File

Before

Width:  |  Height:  |  Size: 768 B

After

Width:  |  Height:  |  Size: 768 B

View File

Before

Width:  |  Height:  |  Size: 742 B

After

Width:  |  Height:  |  Size: 742 B

View File

Before

Width:  |  Height:  |  Size: 610 B

After

Width:  |  Height:  |  Size: 610 B

View File

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 633 B

View File

Before

Width:  |  Height:  |  Size: 776 B

After

Width:  |  Height:  |  Size: 776 B

View File

Before

Width:  |  Height:  |  Size: 736 B

After

Width:  |  Height:  |  Size: 736 B

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2021",
"useDefineForClassFields": true,
"lib": ["DOM", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}