albert 55040b252c
Some checks failed
Build Docker Image / build (pull_request) Failing after 6s
fix build step
2025-07-30 12:12:49 +02:00
2025-07-30 12:12:49 +02:00
2025-07-29 12:47:22 +02:00
2025-07-29 12:12:15 +02:00
2025-07-30 11:55:00 +02:00
2025-07-28 08:00:04 +02:00
2025-07-30 11:55:00 +02:00

dailytrends

Tareas a realizar

  • [*] Crea un proyecto TypeScript con una arquitectura de ficheros que consideres apropiada.

  • [*] | Crea un modelo Feed y define sus atributos. | El origen de datos tiene que ser MongoDB, por lo que puedes usar algún ODM.

  • [*] | Define los diferentes endpoints para gestionar los servicios CRUD del modelo Feed. | Intenta desacoplar las capas del API lo máximo posible.

  • [*] | Crea un “servicio de lectura de feeds” que extraiga por web scraping (no lectura de fuentes RSS) | en cada uno de los periódicos sus noticias de portada y que las guarde como Feeds. | Esta es la parte donde más conceptos de orientación a objetos puedes usar y la más “compleja”, ponle especial atención.

Otros detalles

  • Representa en un dibujo la arquitectura y las capas de la aplicación.
  • Usa todas las buenas prácticas que conozcas.
  • Demuestra conocimientos en programación orientada a objetos:
    • abstracción, encapsulamiento, herencia y polimorfismo.
    • Haz los tests que consideres necesarios.

Changelog

  • Inicializamos proyecto:

    • Usando npm init, con la node@latest (v24.4.1)
  • First part: #1 PR : feat/project_structure

    • Crea un proyecto TypeScript con una arquitectura de ficheros que consideres apropiada.
      • Añadimos dependencias que voy a usar
      • Creo una estructura de directorio inicial
      • Añado un primer test (database.test.ts) para jest
  • Second part: #2 PR : feat/database_and_feed_model && #4 PR: feat/database_and_feed_model 2nd part

    • Crea un modelo Feed y define sus atributos. El origen de datos tiene que ser MongoDB, por lo que puedes usar algún ODM.
      • Añadimos moongose a las dependencias
      • Añado un docker-compose con mongo local (luego lo ampliaré para esta propia app)
      • Modificar el docker para tenerlo multistage y reducir el tamaño de las imagenes de contenedores
      • añadir documentación de Docker, docker-compose
      • añadir documentación de las capas de abstracción de "Feed"
      • añadir tests para la conexión con la base de datos con Mocks (el mocking aqui a veces se complica)
      • añadir primeras definiciones de Feed, empezaremos de lowerst a higher abstraction: tipo -> modelo -> repo -> servicio -> controller
      • añadir tests para FeedService & Feed.model
      • añadir funcionamiento de feed en las diferentes capas
  • Third part: #5 PR : feat/add_endpoints

    • Define los diferentes endpoints para gestionar los servicios CRUD del modelo Feed. Intenta desacoplar las capas del API lo máximo posible.
      • reemplazar index por server.ts
      • implement a basic server.ts in server.ts
      • implement endpoints and their tests
      • troubleshooting: update jest.config and tsconfig to allow test use dependencies
  • Fourth part: #6 PR : feat/scraper

    • Crea un “servicio de lectura de feeds” que extraiga por web scraping
      • we are going to be implementing a Factory for the scraper, since we are going to input values and then will build our custom class

Feed layer abstractions

From higher to lower:

  • Layer 1: HTTP/Controller (Highest Abstraction)

    • FeedController.ts : Handles HTTP requests/responses, API endpoints
  • Layer 2: Business Logic/Service

    • FeedService.ts : Implements business rules, validation, orchestration
  • Layer 3: Data Access/Repository

    • FeedRepository.ts : Abstracts database operations, CRUD methods
  • Layer 4: Data Model/Schema

    • Feed.ts : Mongoose schema, database validations, indexes
  • Layer 5: Type Definitions (Lowest Abstraction)

    • Feed.ts : TypeScript interfaces, enums, DTOs
    • config.ts : Configuration settings

Dockerfile simple to multistage

I rebuild the Dockerfile to be multistage, since the image was heavy because all the node_modules dependencies. The size of the image has been reduced from 717 Mb to 376 Mb.

dailytrends-app-legacy    latest    96a2dfe15361   3 minutes ago   717MB
dailytrends-app-light     latest    7436142e1301   3 seconds ago   376MB
legacy
FROM node:24-slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/index.js"]
light
FROM node:24-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM node:24-slim AS production
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]

Scraper OOP

Entrypoint

  • scraper.ts - Application entry point that initializes the scraping system

Core Services

  • ScrapingScheduler.ts - Orchestrates scraping cycles and timing
  • ContentScrapingService.ts - Handles web content scraping logic
  • FeedReaderService.ts - Manages newspaper extraction
  • ScrapingService.ts - Base scraping functionality

Utilities

  • WebScraper.ts - HTML parsing and data extraction utility
  • logger.ts - Logging utility

Extractors

  • BaseNewspaperExtractor.ts - clase Abstract Base
  • ElPaisExtractor.ts - especificación / extractor para El País
  • ElMundoExtractor.ts - especificación / extractor para El Mundo
  • NewspaperExtractorFactory.ts - clase Factory para crear extractors

Types & Interfaces

  • Feed.ts - tipos y interfaces
  • NewspaperTypes.ts - configuración de las interfaces
  • FeedRepository.ts - abstracción interfaz de la base de datos

Propiedades de OOP

  • He intentado seguir las propiedades de OOP. Ejemplo:
    • separación de responsabilidades: con las capas de abstracción, y servicios dedicados
    • Factory de los extractors en NewspaperExtractorFactory, básicamente, patrón de diseño que nos ayuda a crear objetos de una clase específica, basados en ciertos parámetros, y así lo adaptamos a nuestros periodicos favoritos.
    • Herencia, desde BaseNewspaperExtractor a los extractors.
    • Utils, para tener DRY y poder usarlo desde diferentes classes.
    • He intentando poner tests donde sea necesario, y de forma que tenga sentido.

Obviamente cualquier propuesta está siempre abierta a debate y a mejoras. En mi caso, y dentro de las limitaciones, he intentado seguir las instrucciones y ver como lo podemos adaptar. Seguramente con más tiempo se puede simplificar más sin perder funcionalidades.

Description
No description provided
Readme AGPL-3.0 347 KiB
Languages
TypeScript 99.7%
Dockerfile 0.3%