Arquitectura — Somos 10⁷ Landing

Diagrama de la landing page estática en somos10e7/. La aplicación es un sitio HTML/CSS/JS puro, sin build, sin backend propio, servido por GitHub Pages. Todo el “runtime” ocurre en el navegador del visitante.


1. Vista de despliegue y servicios externos

flowchart LR
    subgraph Repo["📁 Repo asosab.github.io (origen)"]
        direction TB
        J["_config.yml<br/>(Jekyll, plugins whitelist)"]
        SP["somos10e7/<br/>(subdir estático,<br/>no procesado por Jekyll)"]
        SP --> SPHTML["index.html"]
        SP --> SPLOC["es_VE.txt<br/>es_BO.txt<br/>(JSON con ext .txt)"]
        SP --> SPIMG["imagen/<br/>*.png, *.jpg"]
        SP --> SPBACK["back/<br/>(borradores)"]
        SP --> SPJS["js/youtube_videos.mjs<br/>(offline)"]
        SP --> SPOC["opencode.jsonc<br/>(config OpenCode local)"]
    end

    GH["GitHub Pages<br/>CDN + TLS + Jekyll build"]:::infra
    BR["🌐 Navegador del visitante"]:::client

    GF["Google Fonts<br/>(Playfair, Barlow)"]:::ext
    YT["YouTube<br/>i/embed + thumbnails"]:::ext
    FORMS["Google Forms<br/>(Páginas Blancas)"]:::ext
    YTAPI["YouTube Data API v3<br/>(solo script offline)"]:::ext

    Repo -- "git push" --> GH
    GH -- "HTTPS GET<br/>asosab.github.io/somos10e7/" --> BR
    BR -- "fetch CSS woff2" --> GF
    BR -- "iframe + img.youtube.com" --> YT
    BR -- "link a forms.gle" --> FORMS
    SPJS -. "node script<br/>(no se ejecuta en deploy)" .-> YTAPI
    YTAPI -. "videosData.json" .-> SPJS

    classDef infra fill:#e8f0ff,stroke:#1A3A6B,color:#0D1B2A
    classDef client fill:#fff3d6,stroke:#F4B400,color:#0D1B2A
    classDef ext fill:#ffe6e6,stroke:#CF2F35,color:#0D1B2A

Notas:

  • El repo raíz usa Jekyll (_config.yml), pero somos10e7/ es un subdirectorio sin front matter: GitHub Pages lo sirve tal cual.
  • back/ y opencode.jsonc no se sirven en producción: están en .gitignore lógico (no se listan en el HTML generado) y no se referencian desde la página.
  • El script youtube_videos.mjs no forma parte del runtime; es una utilidad local para regenerar videosData.json, que no se consume por la landing.

2. Flujo de carga de la página (runtime del visitante)

sequenceDiagram
    autonumber
    actor U as Visitante
    participant B as Navegador
    participant GH as GitHub Pages
    participant GF as Google Fonts
    participant YT as YouTube

    U->>B: Pega https://asosab.github.io/somos10e7/
    B->>GH: GET /somos10e7/
    GH-->>B: 200 index.html (HTML + CSS + JS inline)
    B->>B: Parsea HTML, descubre recursos
    B->>GF: GET CSS de Playfair, Barlow (woff2)
    GF-->>B: fuentes

    B->>YT: GET iframe embed + thumbnails img.youtube.com
    YT-->>B: HTML del reproductor + JPEGs

    Note over B: IntersectionObserver.attach
    B->>B: Scroll → fade-in de .fade-up
    B->>B: Scroll → scroll-spy resalta link activo del nav
    U->>B: Click en sección
    B->>B: navLinks.classList.toggle si es mobile

(Sin i18n — textos estáticos en tuteo venezolano)


3. Componentes dentro de index.html

flowchart TB
    subgraph HEAD["&lt;head&gt;"]
        META["Meta SEO + Open Graph + Twitter Card"]
        JSONLD["JSON-LD Schema.org<br/>PodcastSeries"]
        FONTS["&lt;link&gt; Google Fonts"]
        CSS["&lt;style&gt;<br/>Variables, layout, animaciones<br/>(~1000 líneas embebidas)"]
    end

    subgraph BODY["&lt;body&gt;"]
        NAV["#navbar<br/>nav fijo + mobile toggle"]
        HERO["#hero<br/>título + CTAs + anillos orbitales"]
        ULT["#ultimo<br/>iframe del último episodio"]
        EPI["#episodios<br/>grid de episode-cards"]
        ENT["#entrevistas<br/>grid de entrevista-cards"]
        MIC["#micros<br/>(placeholder, vacío)"]
        EQ["#equipo<br/>4 cards del equipo"]
        RED["#redes<br/>8 plataformas"]
        PB["#paginas-blancas<br/>CTA a Google Forms"]
        FOOT["footer<br/>secciones + contacto"]
    end

    subgraph SCRIPTS["&lt;script&gt; al final del body"]
        NAVJS["navToggle handler"]
        IO["IntersectionObserver<br/>fade-in + scroll-spy"]
    end

    NAV --> NAVJS
    BODY --> IO
    CSS -. "anima" .-> IO

    classDef head fill:#1A3A6B,stroke:#0D1B2A,color:#FAF5E9
    classDef body fill:#FAF5E9,stroke:#0D1B2A,color:#0D1B2A
    classDef js fill:#F4B400,stroke:#0D1B2A,color:#0D1B2A
    class HEAD head
    class BODY body
    class SCRIPTS js

Observaciones:

  • #micros está declarado en el nav y en el footer pero la sección está vacía (placeholder) en el HTML actual.
  • No hay bundler ni módulo ES: todo el JS es <script> clásico con defer o al final del <body>.
  • El CSS está embebido en <style>, no en assets/. Para temas/variables hay que editar el bloque :root dentro de index.html.

4. Pipeline offline: regenerar videosData.json

flowchart LR
    DEV["👨‍💻 Desarrollador<br/>(Node 18+)"]:::dev
    SCRIPT["node youtube_videos.mjs"]:::tool
    YTAPI["YouTube Data API v3"]:::ext
    JSON["js/videosData.json<br/>(output, no se deploya)"]:::tool

    DEV -- "npm install node-fetch<br/>(primera vez)" --> SCRIPT
    DEV -- "node youtube_videos.mjs" --> SCRIPT
    SCRIPT -- "channels.list<br/>playlists.list<br/>playlistItems.list (paginado)" --> YTAPI
    YTAPI -- "JSON" --> SCRIPT
    SCRIPT -- "cruza videos ↔ playlists<br/>preserva claves extra" --> JSON

    JSON -. "no se referencia en index.html<br/>(workflow manual independiente)" .-> X[("❌ No consumido")]

    classDef dev fill:#fff3d6,stroke:#F4B400,color:#0D1B2A
    classDef tool fill:#e8f0ff,stroke:#1A3A6B,color:#0D1B2A
    classDef ext fill:#ffe6e6,stroke:#CF2F35,color:#0D1B2A

Por qué este pipeline existe pero no se usa:

El script podría listar todos los videos del canal @somos10e7, pero los episodios visibles en la landing se editan a mano dentro de index.html (orden, títulos traducidos, portadas personalizadas). El JSON queda en disco solo como referencia editorial.


Resumen de límites del sistema

Frontera Adentro Afuera
Build Nada (HTML/CSS/JS estático) Jekyll (solo en el resto del repo)
Runtime Navegador del visitante GitHub Pages (solo hosting)
Estado — (sin estado persistente) Cookies, sesión, base de datos
Datos dinámicos YouTube embeds, Google Forms Backend propio (no existe)
Configuración opencode.jsonc (solo OpenCode) Variables de entorno, secretos
Secretos API_KEY de YT, CONTEXT7_API_KEY ⚠️ Commiteados en el repo