toBlog es un motor de publicación editorial y plataforma de contenidos de alto rendimiento inspirado en el diseño y la experiencia de usuario de Medium. Está desarrollado sobre una arquitectura híbrida de Astro 7 (SSR) con Islas de React 19, utilizando una base de datos distribuida en el borde con Turso (LibSQL) y Drizzle ORM, autenticación segura con Lucia Auth y almacenamiento multimedia en Cloudflare R2.
Para evitar la inflación artificial de métricas por recarga consecutiva de página (
-
Seguridad HTTP-Only: Las cookies se emiten con la bandera
httpOnly: true, haciéndolas inaccesibles para scripts maliciosos en el cliente (XSS). -
Incremento Atómico en SQL: La actualización se ejecuta directamente en el motor de base de datos a través de una expresión atómica Drizzle
sql\${posts.viewCount} + 1``, garantizando consistencia ante peticiones concurrentes.
A diferencia de una simple vista, una Lectura (Read) mide la retención real del usuario. El sistema combina el monitoreo topológico del DOM con una restricción temporal mínima:
- Centinela en DOM: Se posiciona un elemento invisible (
#read-tracker-sentinel) al final del contenido del artículo. - IntersectionObserver API: Un observador asíncrono rastrea cuando el usuario ha desplazado la pantalla hasta el final del escrito.
- Disparo Silencioso: Cumplida la condición, el cliente envía un beacon vía
POST /api/posts/readque registra la lectura única y emite una cookie de bloqueo por 24 horas.
- Lucia Auth v3: Gestión de sesiones persistentes basadas en cookies respaldadas por la base de datos Turso SQLite.
- Cifrado de Contraseñas: Algoritmo Argon2id para el hashing seguro de credenciales de acceso.
- Flujo de Verificación Transaccional: Generación de tokens de un solo uso de 15 minutos enviados mediante Resend Email API.
- SSR Instantáneo (Server-Side Rendering): El servidor procesa el HTML inicial incluyendo metadatos SEO y datos primarios del Dashboard.
- Revalidación SWR en Cliente: La interfaz React del Studio utiliza la estrategia
Cache-First + Background Revalidationcon intervalos de deduplicación de 5000ms para mantener las métricas actualizadas sin parpadeos.
El repositorio está organizado de manera modular siguiendo las mejores prácticas de Astro y React:
toBlog/
├── db/ # Scripts extra-aplicación
│ └── seed.ts # Script de alimentación inicial de la BD (Admin + Posts)
├── public/ # Recursos estáticos globales (Favicon, imágenes estáticas)
├── scripts/ # Scripts de utilidades e inspección técnica (Ignorado en Git)
├── src/ # Código fuente de la aplicación
│ ├── actions/ # Acciones de servidor (Astro Actions)
│ │ ├── auth.ts # Lógica de registro, inicio de sesión y verificación de email
│ │ ├── index.ts # Exportador global de servidor
│ │ ├── interactions.ts # Lógica de likes (aplausos) y marcadores (bookmarks)
│ │ ├── posts.ts # CRUD de artículos, duplicación y consulta de métricas
│ │ ├── profile.ts # Actualización de perfil del autor
│ │ └── tools.ts # Herramientas auxiliares
│ ├── components/ # Componentes UI (Astro & React)
│ │ ├── blog/ # Componentes interactivos del artículo público
│ │ │ ├── BookmarkButton.tsx # Botón interactivo de guardado
│ │ │ ├── CommentsSection.tsx # Sección de comentarios e hilos de discusión
│ │ │ ├── LikeButton.tsx # Botón de aplausos acumulativos
│ │ │ └── ShareButton.tsx # Popover de compartir con centrado matemático
│ │ ├── common/ # Componentes comunes de interfaz
│ │ │ └── Header.astro # Barra de navegación principal pública
│ │ ├── editor/ # Componentes del editor enriquecido
│ │ │ ├── EditorWYSIWYG.tsx # Editor TipTap interactivo con subida a R2
│ │ │ └── Reader.tsx # Renderizador HTML seguro de contenidos
│ │ ├── studio/ # Componentes del panel de control
│ │ │ ├── DashboardList.tsx # Tabla elástica de artículos y resumen de métricas
│ │ │ ├── TagSelector.tsx # Selector dinámico de etiquetas
│ │ │ └── UserProfileDropdown.tsx # Menú desplegable de usuario autenticado
│ │ └── ui/ # Tarjetas y componentes visuales reutilizables
│ │ └── PostCard.astro # Tarjeta de artículo para feeds
│ ├── db/ # Capa de base de datos
│ │ ├── client.ts # Inicializador del cliente Turso / LibSQL
│ │ └── schema.ts # Esquema Drizzle (Users, Sessions, Posts, Bookmarks, Likes, Tags)
│ ├── layouts/ # Estructuras base de diseño HTML
│ │ ├── BaseLayout.astro # Layout del sitio público (Header + Footer + SEO)
│ │ └── StudioLayout.astro # Layout del panel de administración (Studio)
│ ├── lib/ # Clientes e integraciones externas
│ │ ├── aiConfig.ts # Configuración de herramientas asistidas
│ │ ├── lucia.ts # Instancia y adaptador de Lucia Auth v3
│ │ └── r2.ts # Cliente AWS S3 para Cloudflare R2
│ ├── pages/ # Enrutamiento de la aplicación (SSR)
│ │ ├── api/ # Endpoints API de servidor
│ │ │ ├── auth/ # Endpoints de sesión (/logout, /verify-email)
│ │ │ ├── posts/ # Endpoints de interacción (/read)
│ │ │ └── upload.ts # Receptor y procesador de imágenes hacia R2
│ │ ├── blog/ # Rutas de la sección del blog
│ │ │ ├── index.astro # Feed principal de publicaciones
│ │ │ └── [slug].astro # Vista detallada del artículo (Tracking de Vistas/Lecturas)
│ │ ├── studio/ # Rutas del panel de administración
│ │ │ ├── index.astro # Dashboard principal con conteo de métricas
│ │ │ └── escribir.astro # Creación y edición de artículos
│ │ ├── biblioteca.astro # Vista unificada de artículos guardados por el usuario
│ │ ├── index.astro # Página de aterrizaje / Inicio público
│ │ ├── login.astro # Formulario de inicio de sesión
│ │ ├── register.astro # Formulario de registro de usuarios
│ │ └── verify-notice.astro # Pantalla de aviso de verificación de correo
│ └── styles/ # Estilos globales
│ └── global.css # Importación de Tailwind CSS v4 y tokens de diseño
├── .env.example # Plantilla de variables de entorno requeridas
├── astro.config.mjs # Configuración principal de Astro (Integraciones React + Tailwind)
├── drizzle.config.ts # Configuración de Drizzle Kit para migraciones
├── package.json # Definición de dependencias y scripts del proyecto
└── README.md # Documentación del proyecto
- Node.js: Versión
>= 22.12.0 - Gestor de Paquetes:
pnpm(recomendado) onpm/yarn - Base de Datos: Cuenta activa en Turso (o SQLite local)
- Almacenamiento de Archivos: Bucket en Cloudflare R2 (Compatible con S3)
- Proveedor de Emails: Cuenta en Resend
git clone https://github.com/elisbanpaco/myBlog.git
cd myBlog
pnpm installCopia el archivo .env.example para generar tu configuración local .env:
cp .env.example .envConfigura tus credenciales en el archivo .env:
# Base de datos Turso (LibSQL)
TURSO_DATABASE_URL=libsql://<tu-base-de-datos>.turso.io
TURSO_AUTH_TOKEN=<tu-token-de-acceso>
# Cloudflare R2 / Almacenamiento S3
R2_ENDPOINT=https://<account_id>.r2.cloudflarestorage.com
R2_ACCESS_KEY_ID=<tu-access-key-id>
R2_SECRET_ACCESS_KEY=<tu-secret-access-key>
R2_BUCKET_NAME=toblog-media
R2_PUBLIC_URL=https://<tu-bucket-publico>.r2.dev
# Envíos de correo transaccionales con Resend
API_RESEND=re_<tu_api_key>Puedes levantar una base de datos local SQLite utilizando Drizzle Kit (se guardará en .astro/content.db):
# Crear las tablas en la base de datos local
pnpm db:push:local
# Insertar el usuario administrador y artículos de prueba iniciales
pnpm db:seed:localpnpm devEl servidor estará disponible en http://localhost:4321.
Nota para desarrollo: Para ejecutar el servidor en segundo plano puedes usar
astro dev --backgroundy gestionarlo medianteastro dev statusyastro dev logs.
Tras ejecutar el comando pnpm db:seed:local, podrás acceder al panel /studio con el usuario por defecto:
- Usuario:
admin - Contraseña:
admin1234
| Comando | Descripción |
|---|---|
pnpm dev |
Inicia el servidor de desarrollo local de Astro. |
pnpm build |
Compila la aplicación optimizada para producción en ./dist/. |
pnpm preview |
Previsualiza la compilación de producción en entorno local. |
pnpm lint |
Analiza el código en busca de problemas de formato con ESLint. |
pnpm lint:fix |
Corrige automáticamente los errores detectados por ESLint. |
pnpm db:push:local |
Sincroniza el esquema Drizzle con la base de datos local. |
pnpm db:push:remote |
Sincroniza el esquema Drizzle con la BD remota de Turso. |
pnpm db:seed:local |
Puebla la base de datos local con datos de prueba. |
pnpm db:seed:remote |
Puebla la BD remota de Turso con datos iniciales. |
pnpm db:studio |
Abre la consola web Drizzle Studio para inspeccionar las tablas. |
Este proyecto está distribuido bajo la Licencia MIT. Consulta el archivo LICENSE para más información.