Radio Programs Module
📋 Resumo
Modelo completo para programas de rádio e horários, permitindo sugerir programas em emissão no momento certo.
🗄️ Schema RadioProgram
{
id: ObjectId, // Gerado automaticamente
dedupe_key: string, // Chave de deduplicação (única; gerada)
radio_id: ObjectId, // FK para Radio (obrigatório)
name: string, // Nome do programa (obrigatório)
description?: string, // Descrição (opcional)
days_of_week: DayOfWeek[], // Dias da semana (obrigatório)
start_time: string, // Hora início HH:MM (obrigatório)
end_time: string, // Hora fim HH:MM (obrigatório)
createdAt: Date, // Automático
updatedAt: Date // Automático
}
`dedupe_key`
Para evitar duplicados criados por sincronizações concorrentes (ex.: jobs de schedule scraping), cada programa usa uma chave derivada de:
radio_idnamenormalizado (trim + lowercase + strip diacríticos + apenas alfanuméricos/espacos)
Formato atual:
radio=<radioId>|name=<normalizedName>
Enum DayOfWeek
enum DayOfWeek {
MONDAY = 'monday',
TUESDAY = 'tuesday',
WEDNESDAY = 'wednesday',
THURSDAY = 'thursday',
FRIDAY = 'friday',
SATURDAY = 'saturday',
SUNDAY = 'sunday',
}
Índices
radio_id: queries de programas por rádiodays_of_week: filtros por dia da semanaradio_id + days_of_week: índice compostostart_time + end_time: queries por horáriodedupe_key(unique, sparse): garante idempotência e previne duplicados
🔗 Relação Radio → RadioPrograms
Tipo: One-to-Many
- 1 Radio pode ter N RadioPrograms
- 1 RadioProgram pertence a 1 Radio
Validação: Ao criar um RadioProgram, verifica se o Radio existe.
Nota de idempotência: POST /radio-programs faz upsert por dedupe_key (em vez de criar sempre um novo documento) e faz merge de days_of_week.
🛠️ Endpoints
Criar Programa
POST /radio-programs
Só para admins com escrita (adminRole: admin); um utilizador ou um viewer recebe 403.
Body:
{
"radio_id": "507f1f77bcf86cd799439011",
"name": "Morning Show",
"description": "O melhor para começar o dia",
"days_of_week": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start_time": "06:00",
"end_time": "10:00"
}
Listar Programas
GET /radio-programs
Query params opcionais:
radio_id: filtrar por rádioday_of_week: filtrar por dia da semana
Listar Programas de uma Rádio
GET /radio-programs/radio/:radioId
Programas Atuais
GET /radio-programs/current?day=monday&time=09:00
Retorna programas em emissão para o dia e hora especificados.
Obter Programa por ID
GET /radio-programs/:id
Atualizar Programa
PUT /radio-programs/:id
Só para admins com escrita (adminRole: admin); um utilizador ou um viewer recebe 403.
Eliminar Programa
DELETE /radio-programs/:id
Só para admins com escrita (adminRole: admin); um utilizador ou um viewer recebe 403.
🌱 Seed de Dados
Endpoint de Seed
POST /seed/radios
Só para admins com escrita (adminRole: admin), como as outras escritas de rádios; um utilizador ou um viewer recebe 403.
Cria:
- 3 rádios (RFM, Comercial, TSF)
- 7 programas distribuídos pelas rádios
- Horários realistas de programação
Como Usar
- Fazer login (com uma conta de admin):
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password"}'
- Criar dados de exemplo:
curl -X POST http://localhost:3000/seed/radios \
-H "Authorization: Bearer TOKEN_DE_ADMIN"
📝 Exemplos de Uso
Criar Programa
# Token de um admin com escrita (adminRole: admin); outro recebe 403.
curl -X POST http://localhost:3000/radio-programs \
-H "Authorization: Bearer TOKEN_DE_ADMIN" \
-H "Content-Type: application/json" \
-d '{
"radio_id": "RADIO_ID",
"name": "Programa da Tarde",
"description": "Música e entretenimento",
"days_of_week": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start_time": "14:00",
"end_time": "17:00"
}'
Listar Programas de uma Rádio
curl http://localhost:3000/radio-programs/radio/RADIO_ID
Ver Programas em Emissão
# Segunda-feira às 09:00
curl "http://localhost:3000/radio-programs/current?day=monday&time=09:00"
Listar Programas de Segunda-feira
curl "http://localhost:3000/radio-programs?day_of_week=monday"
🧪 Testes
Todos os testes passam (90/90):
radio-programs.service.spec.ts- Testes do serviceradio-programs.controller.spec.ts- Testes do controller
npx nx test api
📂 Estrutura de Ficheiros
apps/api/src/app/radios/
├── schemas/
│ ├── radio.schema.ts
│ └── radio-program.schema.ts # Schema RadioProgram
├── dto/
│ ├── create-radio-program.dto.ts # DTO criação
│ └── radio-program-response.dto.ts # DTO resposta
├── radio-programs.service.ts # Service
├── radio-programs.controller.ts # Controller
├── radios-seed.controller.ts # Seed controller
├── radios.module.ts # Módulo
└── *.spec.ts # Testes
✅ Critérios de Aceitação
- Schema RadioProgram com todos os campos solicitados
- Relação Radio → RadioPrograms bem definida (FK via ObjectId)
- Possível criar programas via seed/script
- Suporta múltiplos programas por rádio
- Validações de horário (formato HH:MM)
- Endpoint para encontrar programas em emissão
- Índices otimizados para queries
- Testes completos
🎯 Funcionalidades Adicionais
- findCurrentPrograms: Encontra programas em emissão num momento específico
- Validação de formato: Horários validados como HH:MM (formato 24h)
- Enum DayOfWeek: Garante consistência nos dias da semana
- Ordenação: Programas ordenados por hora de início
- Filtros múltiplos: Por rádio e por dia da semana
💡 Casos de Uso
Sugestão de Programa Atual
// Segunda-feira às 09:00
const programs = await radioProgramsService.findCurrentPrograms(DayOfWeek.MONDAY, '09:00');
Grade de Programação
// Todos os programas de uma rádio
const schedule = await radioProgramsService.findByRadioId(radioId);
Programas do Dia
// Todos os programas de segunda-feira
const mondayPrograms = await radioProgramsService.findAll({
day_of_week: DayOfWeek.MONDAY,
});
🚀 Próximos Passos Sugeridos
- Adicionar campo
host(apresentador do programa) - Implementar recorrência (programas temporários vs permanentes)
- Adicionar exceções (feriados, substituições)
- Notificações quando programa começa
- Histórico de programas emitidos
- Integração com metadata de streams