Plataforma web colaborativa de reseñas literarias, estilo Reddit. Los usuarios descubren libros, publican reseñas, votan, comentan y reciben recomendaciones personalizadas según sus intereses.
- Backend: Python 3.10+, FastAPI, SQLAlchemy 2.0, PostgreSQL (Neon)
- Frontend: React 19, TypeScript, Vite 8, TailwindCSS v4
- Despliegue: Render (backend) · Vercel (frontend)
- Registro e inicio de sesión con JWT
- Onboarding de 2 pasos al registrarse: selección de géneros favoritos (máx. 3) y libros ya leídos (máx. 5)
- Edición de perfil (usuario, email, contraseña, avatar)
- Sección "Tus intereses" en el perfil — visualiza géneros y etiquetas con los que el sistema te recomienda
- Feed global con ordenamiento (más votadas, más recientes, mayor calificación ★)
- Feed personalizado de usuarios seguidos
- Sección Trending semanal en el home
- Recomendaciones personalizadas ("Para ti") con motivos transparentes — cada libro muestra POR QUÉ fue recomendado (ej. "Por Ficción", "#realismo mágico")
- Página de descubrimiento por etiqueta (
/etiqueta/:id) — todos los libros con una etiqueta dada - Libros relacionados en la página de cada libro, basados en etiquetas y género compartidos
- Búsqueda de libros, reseñas y usuarios con filtro por género
- Página de detalle con portada, sinopsis (descripción), género, año, etiquetas y calificación promedio
- Importación desde Open Library
- Subida de portada
- Lista de lectura por estado (Quiero leer / Leyendo / Ya leí)
- Publicar, editar, eliminar y compartir reseñas con calificación de estrellas (1–5)
- Votos (+1 / -1) con sistema de puntos
- Comentarios anidados (hasta 4 niveles de profundidad)
- Seguir y dejar de seguir a otros usuarios
- Notificaciones (comentarios, votos, nuevos seguidores)
- Algoritmo basado en pesos de intereses:
género × 0.7 + etiqueta × 0.3 + popularidad × 0.2 - Caché de 24 h por usuario en
recommendation_cache - Tracking de actividad (
view_book,vote,comment,add_to_list,search, etc.) para alimentar el sistema - Intereses inferidos: al agregar un libro a tu lista o votar +1 una reseña, el peso del género en tu perfil sube automáticamente
- Modo oscuro en todo el panel
- Toasts de feedback (éxito/error) al ejecutar acciones
- Gestión de libros, reseñas, comentarios, géneros, etiquetas y usuarios
- Importación masiva desde Open Library con asignación de género al vuelo
- Edición inline de etiquetas por libro
- Dashboard con stats: usuarios/libros/reseñas/comentarios, top reseñas, top usuarios, géneros con más libros (gráfico de barras) y libros más guardados en listas de lectura
- Python 3.10+
- Node.js 18+
- npm 9+
cd backend
python -m venv venv
.\venv\Scripts\activate
pip install -r requirements.txtCrea el archivo .env en backend/ con las siguientes variables:
DATABASE_URL=postgresql://usuario:contraseña@host.neon.tech/dbname
JWT_SECRET_KEY=una-clave-larga-y-segura
JWT_ALGORITHM=HS256
JWT_EXPIRATION_MINUTES=60
CORS_ORIGINS=http://localhost:5173cd frontend
npm installCrea el archivo .env en frontend/ con:
VITE_API_URL=http://localhost:8000Abre dos terminales desde la raíz del proyecto.
cd backend
.\venv\Scripts\activate
uvicorn main:app --reloadDisponible en http://localhost:8000.
Documentación interactiva en http://localhost:8000/docs.
cd frontend
npm run devDisponible en http://localhost:5173.
Las migraciones son scripts manuales en backend/. Ejecutar en orden:
cd backend
.\venv\Scripts\activate
python migrate_<nombre>.pyScripts disponibles:
migrate_add_rating.py— calificación en reseñasmigrate_add_reading_list.py— lista de lectura por usuariomigrate_add_follow.py— sistema de seguidoresmigrate_add_notification.py— notificacionesmigrate_recommendation_system.py— tablas de recomendaciones, etiquetas, intereses, actividad y gruposmigrate_add_book_description.py— columnadescriptionenbook
seed_db.py puebla la base con:
- 10 géneros
- 16 etiquetas
- 35 libros clásicos con descripciones
- 8 usuarios de prueba (contraseña:
lectura123) - 36 reseñas
- 51 entradas de lista de lectura
- Intereses preasignados (
user_interest) por usuario para que las recomendaciones funcionen al primer login
cd backend
.\venv\Scripts\activate
python seed_db.pyEl script es idempotente — se puede ejecutar varias veces sin duplicar nada y actualiza descripciones vacías en libros existentes.
Usuarios de prueba (contraseña: lectura123):
| Usuario | Gustos principales |
|---|---|
ana_lectora |
Ficción, fantasía, terror |
carlos_books |
Ficción, fantasía, ciencia ficción |
sofia_lee |
Ciencia ficción, romance, no ficción |
lucia_mendez |
Romance, clásicos |
david_reads |
Ciencia ficción, fantasía, ciberpunk |
marta_lit |
Thriller, terror, misterio |
pablo_books |
Ficción, historia, no ficción |
elena_pages |
No ficción, ensayo |
Los emails siguen el patrón {usuario}@readit.com.
- Inicia sesión con cualquier usuario del seed (ej.
david_reads/lectura123). - En la página de inicio, la sección "Para ti" muestra hasta 6 libros recomendados, cada uno con un chip naranja que explica el motivo del match (
Por Ciencia ficción,#ciberpunk,Popular, etc.). - Visita el perfil del usuario para ver la sección "Tus intereses" con géneros y etiquetas en chips naranja (
onboarding) o gris con etiqueta "inferido" (los que el sistema dedujo de la actividad). - En la página de cualquier libro, al final hay "Si te gustó esto, también te puede gustar": libros relacionados ordenados por etiquetas compartidas (+2 puntos por etiqueta) y género igual (+1 punto).
- Haz clic en cualquier etiqueta (#realismo mágico, #ciberpunk, etc.) y aterrizarás en una página de descubrimiento con todos los libros de esa etiqueta.
- Agrega un libro a tu lista de lectura o vota +1 una reseña — el peso del género correspondiente en
user_interestsube automáticamente (consource='inferred').
El caché de recomendaciones (recommendation_cache) dura 24 horas por usuario. Para invalidarlo manualmente, basta con borrar las filas de ese usuario en la tabla.
- Constraint
chk_ui_weight: el peso enuser_interestestá limitado por base de datos. Todos los routers limitan incrementos a 1.0 (min(weight + delta, 1.0)). - Eliminar libros desde admin elimina manualmente sus dependencias en cascada (notificaciones de sus reseñas, votos, comentarios, reseñas y entradas de lista de lectura) porque las FKs originales no tienen
ON DELETE CASCADE. - Onboarding step 2 ordena los libros por relevancia según los géneros elegidos en step 1 (los libros del género seleccionado aparecen primero).
- Toasts en admin: feedback visual (éxito/error) en todas las acciones de
BooksPagecon auto-dismiss en 3.5 s. - Schemas Pydantic:
BookDetailse construye manualmente enget_bookpara evitar quefrom_attributes=Trueintente validar la relaciónbook.tags(que devuelveBookTag, noTagSimple).
readit/
├── backend/
│ ├── main.py # Entry point FastAPI
│ ├── database.py
│ ├── auth.py # JWT, bcrypt, get_current_user
│ ├── seed_db.py # Datos de ejemplo
│ ├── requirements.txt
│ ├── migrate_*.py # Migraciones manuales
│ ├── models/
│ │ ├── user.py
│ │ ├── book.py # incluye campo description
│ │ ├── review.py
│ │ ├── comment.py # con parent_comment_id (anidados)
│ │ ├── vote.py
│ │ ├── genre.py
│ │ ├── reading_list.py
│ │ ├── follow.py
│ │ ├── notification.py
│ │ ├── tag.py # Tag + BookTag
│ │ ├── user_interest.py
│ │ ├── user_activity.py
│ │ ├── user_group.py # UserGroup + Membership + Affinity
│ │ └── recommendation_cache.py
│ ├── schemas/
│ │ ├── user.py
│ │ ├── book.py
│ │ ├── review.py
│ │ ├── comment.py
│ │ ├── genre.py
│ │ ├── reading_list.py
│ │ ├── tag.py
│ │ └── recommendation.py
│ └── routers/
│ ├── auth.py
│ ├── books.py # incluye /related para libros similares
│ ├── reviews.py # incluye edición de reseña
│ ├── comments.py # crea, edita, borra comentarios anidados
│ ├── genres.py
│ ├── users.py # incluye /me/interests
│ ├── admin.py # stats + CRUD de admin
│ ├── search.py
│ ├── reading_list.py # actualiza intereses inferidos
│ ├── feed.py
│ ├── notifications.py
│ ├── tags.py # incluye /tags/{id}/books
│ ├── onboarding.py # /options y /complete
│ ├── activity.py # log de actividad
│ └── recommendations.py # con caché de 24 h
└── frontend/
└── src/
├── App.tsx
├── pages/
│ ├── HomePage.tsx # con "Para ti", trending, feed
│ ├── BookPage.tsx # con sinopsis y libros relacionados
│ ├── TagPage.tsx # descubrimiento por etiqueta
│ ├── ReviewDetailPage.tsx # con edición y comentarios anidados
│ ├── CreateReviewPage.tsx
│ ├── ExplorePage.tsx
│ ├── ProfilePage.tsx # con sección "Tus intereses"
│ ├── SearchPage.tsx
│ ├── OnboardingPage.tsx # 2 pasos: géneros + libros leídos
│ ├── LoginPage.tsx
│ ├── RegisterPage.tsx
│ ├── NotFoundPage.tsx
│ └── admin/
│ ├── DashboardPage.tsx # con gráfico de géneros y top libros
│ ├── BooksPage.tsx # con edición de descripción y toasts
│ ├── UsersPage.tsx
│ ├── ReviewsPage.tsx
│ ├── CommentsPage.tsx
│ ├── GenresPage.tsx
│ └── TagsPage.tsx
├── components/
│ ├── Navbar.tsx
│ ├── ReviewCard.tsx
│ ├── CommentThread.tsx # comentarios anidados con tracking
│ ├── BookCover.tsx
│ ├── SearchBar.tsx
│ ├── StarRating.tsx
│ ├── StarPicker.tsx
│ ├── UserAvatar.tsx
│ ├── Highlight.tsx
│ ├── AdminLayout.tsx # sidebar + dark mode toggle
│ └── AdminRoute.tsx
├── hooks/
│ ├── useAuth.tsx
│ ├── useActivity.ts # registro de actividad fire-and-forget
│ └── useTheme.ts # dark mode
├── lib/
│ └── api.ts
└── types/
├── auth.ts
├── book.ts
├── review.ts
├── reading_list.ts
├── recommendation.ts
├── comment.ts
└── user.ts
- Root directory:
backend - Build command:
pip install -r requirements.txt - Start command:
uvicorn main:app --host 0.0.0.0 --port $PORT - Variables de entorno:
DATABASE_URL,JWT_SECRET_KEY,JWT_ALGORITHM,JWT_EXPIRATION_MINUTES,CORS_ORIGINS
- Root directory:
frontend - Variable de entorno:
VITE_API_URL=https://tu-backend.onrender.com
Leonardo Chapal Díaz — ParqueSoftTI, Cohorte 37