Update refactor to modules all
296
ARCHITECTURE.md
Normal 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
@ -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
48
package.json
@ -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
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
13
packages/admin-panel/index.html
Normal 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>
|
||||||
33
packages/admin-panel/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
90
packages/admin-panel/src/App.tsx
Normal 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;
|
||||||
9
packages/admin-panel/src/main.tsx
Normal 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>,
|
||||||
|
)
|
||||||
7
packages/admin-panel/tailwind.config.cjs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
25
packages/admin-panel/tsconfig.json
Normal 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" }]
|
||||||
|
}
|
||||||
10
packages/admin-panel/tsconfig.node.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
9
packages/admin-panel/vite.config.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
port: 3002,
|
||||||
|
},
|
||||||
|
})
|
||||||
38
packages/backend-api/.env.example
Normal 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
|
||||||
42
packages/backend-api/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
54
packages/backend-api/src/index.ts
Normal 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}`);
|
||||||
|
});
|
||||||
18
packages/backend-api/tsconfig.json
Normal 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"]
|
||||||
|
}
|
||||||
13
packages/broadcast-studio/index.html
Normal 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>
|
||||||
33
packages/broadcast-studio/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
packages/broadcast-studio/postcss.config.cjs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
39
packages/broadcast-studio/src/App.tsx
Normal 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;
|
||||||
12
packages/broadcast-studio/src/index.css
Normal 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;
|
||||||
|
}
|
||||||
10
packages/broadcast-studio/src/main.tsx
Normal 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>,
|
||||||
|
)
|
||||||
7
packages/broadcast-studio/tailwind.config.cjs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [require('@tailwindcss/forms')],
|
||||||
|
}
|
||||||
25
packages/broadcast-studio/tsconfig.json
Normal 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" }]
|
||||||
|
}
|
||||||
10
packages/broadcast-studio/tsconfig.node.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
9
packages/broadcast-studio/vite.config.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
port: 3001,
|
||||||
|
},
|
||||||
|
})
|
||||||
32
packages/landing-page/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
packages/landing-page/postcss.config.cjs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 789 B After Width: | Height: | Size: 789 B |
|
Before Width: | Height: | Size: 765 B After Width: | Height: | Size: 765 B |
|
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 768 B |
|
Before Width: | Height: | Size: 742 B After Width: | Height: | Size: 742 B |
|
Before Width: | Height: | Size: 610 B After Width: | Height: | Size: 610 B |
|
Before Width: | Height: | Size: 633 B After Width: | Height: | Size: 633 B |
|
Before Width: | Height: | Size: 776 B After Width: | Height: | Size: 776 B |
|
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 736 B |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
20
packages/landing-page/tsconfig.json
Normal 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"]
|
||||||
|
}
|
||||||