diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1ae123d..6fbd25a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog - project.linkedcorp.net
+## [4.8.0] - 2026-10-28
+### Added
+- Agenda médica: vista **Mes** tipo calendario (hasta 4 citas/bloqueos por día, clic abre el día) y
+ leyenda de colores por médico. Componente reutilizable `MonthGrid`.
+### Changed
+- Agenda médica: la vista **Semana** muestra las citas de todos los médicos filtrados (antes uno solo),
+ coloreadas por médico y en formato compacto. La vista elegida se recuerda.
+
## [4.7.0] - 2026-10-28
### Added
- Agenda médica para médicos y recepción: citas, pacientes, bloqueos recurrentes, horarios, tipos de cita, permisos por personal y disponibilidad.
diff --git a/ESTADO.md b/ESTADO.md
index fe4ce68..0254f72 100644
--- a/ESTADO.md
+++ b/ESTADO.md
@@ -6,6 +6,9 @@ autorregistro/aprobacion/SMTP.
## Agenda médica (v4.7.0, sin desplegar)
+- v4.8.0: vistas Mes (calendario) y Semana con todos los médicos filtrados, color por médico. Sin
+ migración. Revisado en dev con datos temporales (ya borrados), sin errores de consola.
+
- Módulo `clinic` con permisos por `clinic_staff` (`all` recepción, `own` médico), pacientes, horarios, tipos, citas y bloqueos recurrentes.
- Migración `036_clinic.sql` **aplicada en dev** (2026-10-28), no en producción (la aplica el actualizador).
- Probado en dev con usuarios/pacientes temporales (ya borrados), 29/29: configuración por admin que no es
diff --git a/SPEC.md b/SPEC.md
index 61d1c8d..a341172 100644
--- a/SPEC.md
+++ b/SPEC.md
@@ -100,7 +100,10 @@ tiene cada cosa — sin que cargar la información sea tedioso para quien lo usa
Los médicos conservan el resto de sus módulos y no se crea un rol del sistema.
- Admin/superadmin con acceso a `clinic` y fila de staff configuran personal, horarios por tramos
y tipos de cita desde la pestaña Configuración de agenda.
-- Día muestra columnas por médico; Semana muestra un médico; Lista muestra citas y bloqueos.
+- Vistas (v4.8.0, la elegida se recuerda): **Día** con una columna por médico; **Semana** como
+ calendario de 7 días con las citas de todos los médicos filtrados, coloreadas por médico; **Mes**
+ como calendario mensual (hasta 4 entradas por día + "N más"; clic en un día abre su vista Día);
+ **Lista** con citas y bloqueos. Leyenda de colores por médico en Semana y Mes.
Crear cita desde un hueco precarga médico/hora; el tipo fija la duración por defecto.
- Una cita no cancelada solo cabe si está completa dentro de un tramo de atención y no cruza
otra cita del médico, un bloqueo suyo (también recurrente) ni otra cita del paciente con
diff --git a/VERSION b/VERSION
index f6cdf40..88f1811 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.7.0
+4.8.0
diff --git a/backend/package-lock.json b/backend/package-lock.json
index ddef376..9e5c311 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "project-linkedcorp-backend",
- "version": "4.7.0",
+ "version": "4.8.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "project-linkedcorp-backend",
- "version": "4.7.0",
+ "version": "4.8.0",
"dependencies": {
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
diff --git a/backend/package.json b/backend/package.json
index c2054c2..2848dbe 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "project-linkedcorp-backend",
- "version": "4.7.0",
+ "version": "4.8.0",
"private": true,
"type": "module",
"main": "src/server.js",
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 39945df..3684c52 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "project-linkedcorp-frontend",
- "version": "4.7.0",
+ "version": "4.8.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "project-linkedcorp-frontend",
- "version": "4.7.0",
+ "version": "4.8.0",
"dependencies": {
"dompurify": "^3.4.16",
"highlight.js": "^11.12.0",
@@ -2748,7 +2748,7 @@
"license": "MIT"
},
"node_modules/@vitejs/plugin-react": {
- "version": "4.7.0",
+ "version": "4.8.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
"integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"dev": true,
diff --git a/frontend/package.json b/frontend/package.json
index ca68d73..ef5f122 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "project-linkedcorp-frontend",
"private": true,
- "version": "4.7.0",
+ "version": "4.8.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/MonthGrid.jsx b/frontend/src/components/MonthGrid.jsx
new file mode 100644
index 0000000..64f5c2a
--- /dev/null
+++ b/frontend/src/components/MonthGrid.jsx
@@ -0,0 +1,30 @@
+// Cuadricula mensual (lunes a domingo) con las clases .calendar-* de app.css. El contenido de cada
+// dia lo decide quien la usa (renderDay); clic en el dia -> onDayClick(YYYY-MM-DD).
+const pad = (n) => String(n).padStart(2, '0');
+const key = (d) => `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;
+
+// Primer lunes visible y los 35/42 dias que cubren el mes de `day` (YYYY-MM-DD).
+export function monthGridDays(day) {
+ const [y, m] = day.split('-').map(Number);
+ const first = new Date(Date.UTC(y, m - 1, 1));
+ const start = new Date(first.getTime() - ((first.getUTCDay() + 6) % 7) * 86400000);
+ const daysInMonth = new Date(Date.UTC(y, m, 0)).getUTCDate();
+ const cells = Math.ceil((((first.getUTCDay() + 6) % 7) + daysInMonth) / 7) * 7;
+ return Array.from({ length: cells }, (_, i) => key(new Date(start.getTime() + i * 86400000)));
+}
+
+export function MonthGrid({ day, weekLabels, todayKey, renderDay, onDayClick }) {
+ const month = day.slice(0, 7);
+ return (
+