Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
## Objetivo del repositorio
Mantener y evolucionar una plataforma educativa que transforma libros en aventuras jugables via API web y frontend interactivo.

## Agentes de producto (enfoque mercado)
- `Student Agent`: prioriza engagement, claridad de juego y progresion pedagogica.
- `Teacher Agent`: prioriza evidencia, seguimiento por estudiante y exportabilidad.
- `Quality Agent`: protege coherencia narrativa y calidad de preguntas mediante benchmarks.
- `Delivery Agent`: mantiene GitFlow, CI verde y releases reproducibles.

## Convenciones de trabajo
- Base tecnica: backend Java 17 + Maven, frontend React + TypeScript.
- Pruebas: cobertura automatizada para cambios de comportamiento.
Expand All @@ -21,6 +27,7 @@ Mantener y evolucionar una plataforma educativa que transforma libros en aventur
- Frontend `npm run build` en verde.
- CI sin fallos.
- Documentacion actualizada para cambios de UX/arquitectura.
- Requisitos de mercado trazados en `docs/MARKET_VALUE_REQUIREMENTS.md`.

## Checklist de PR
- Cobertura de tests para comportamiento nuevo.
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,20 @@ npm run dev

Abrir: `http://localhost:5173`

## Persistencia (v3.4)
- Flyway ejecuta migraciones SQL en startup (`apps/backend/src/main/resources/db/migration`).
- Default local: H2 en archivo (`./.autobook-data/autobook-db`).
- Produccion: configurar PostgreSQL via `SPRING_DATASOURCE_URL`, `SPRING_DATASOURCE_USERNAME`, `SPRING_DATASOURCE_PASSWORD`.
- Si existe `teacher-workspace.json` legado, el backend migra su contenido a DB en el primer arranque y lo renombra a `teacher-workspace.migrated.json`.

## Uso con PDF real
1. En `1. Preparar partida`, usa `Importar libro` con ruta como `file:///C:/Users/<usuario>/Downloads/libro.pdf`.
2. Selecciona el libro importado y pulsa `2. Iniciar partida`.
3. En `3. Jugar`, avanza por escenas con `Dialogar`, `Explorar`, `Resolver reto` o `Usar item`.
4. Para continuar luego, usa `Cargar sesion` con el `sessionId` (tambien se recuerda automaticamente en el navegador).

## Release desktop
- Release publico actual: `v3.1.0`
- Release publico actual: `v3.4.0`
- Incluye `AutoBookQuest-win64.zip` (portable con `AutoBookQuest.exe`).
- Para instalador `.exe` tipo setup con `jpackage`, se requiere WiX v3 instalado.
- El workflow `release` publica tambien `latest.json` para auto-update.
Expand All @@ -59,6 +65,7 @@ Abrir: `http://localhost:5173`
- `docs/ROADMAP.md`
- `docs/NEXT_STEPS.md`
- `docs/LEARNING_TRACK_TODO.md`
- `docs/MARKET_VALUE_REQUIREMENTS.md`
- `docs/DESKTOP.md`
- `CONTRIBUTING.md`
- `CODE_OF_CONDUCT.md`
11 changes: 11 additions & 0 deletions apps/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ mvn spring-boot:run
- `GET /api/game/{sessionId}/graph`
- `POST /api/telemetry/events`
- `GET /api/telemetry/summary`
- `GET /api/teacher/classrooms`
- `POST /api/teacher/classrooms`
- `POST /api/teacher/classrooms/{classroomId}/students`
- `GET /api/teacher/classrooms/{classroomId}/students`
- `POST /api/teacher/classrooms/{classroomId}/assignments`
- `GET /api/teacher/classrooms/{classroomId}/assignments`
- `POST /api/teacher/attempts/link`
- `GET /api/teacher/classrooms/{classroomId}/dashboard`
- `GET /api/teacher/classrooms/{classroomId}/report.csv`

## Arquitectura
- `domain`: entidades de juego.
Expand All @@ -34,3 +43,5 @@ mvn spring-boot:run
- CORS permitido para `http://localhost:5173`.
- El frontend empaquetado se copia a `src/main/resources/static` solo durante build desktop.
- El pipeline narrativo incluye normalizacion de texto, memoria de entidades, grafo de relaciones y nivel cognitivo por escena.
- Persistencia docente sobre JDBC + Flyway (`classrooms`, `students`, `assignments`, `attempts`).
- Default local con H2 file DB; PostgreSQL habilitado por variables de entorno Spring datasource.
20 changes: 19 additions & 1 deletion apps/backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<groupId>com.juegodefinitivo</groupId>
<artifactId>autobook-adventure</artifactId>
<version>3.0.0</version>
<version>3.4.0</version>
<name>AutoBook Adventure Backend</name>
<description>API para aventuras jugables basadas en libros</description>

Expand All @@ -26,6 +26,24 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.juegodefinitivo.autobook.api;

import com.juegodefinitivo.autobook.api.dto.AssignmentView;
import com.juegodefinitivo.autobook.api.dto.ClassroomDashboardResponse;
import com.juegodefinitivo.autobook.api.dto.ClassroomView;
import com.juegodefinitivo.autobook.api.dto.CreateAssignmentRequest;
import com.juegodefinitivo.autobook.api.dto.CreateClassroomRequest;
import com.juegodefinitivo.autobook.api.dto.CreateStudentRequest;
import com.juegodefinitivo.autobook.api.dto.LinkAttemptRequest;
import com.juegodefinitivo.autobook.api.dto.StudentView;
import com.juegodefinitivo.autobook.service.TeacherWorkspaceService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.util.List;

@RestController
@RequestMapping("/api/teacher")
public class TeacherController {

private final TeacherWorkspaceService workspaceService;

public TeacherController(TeacherWorkspaceService workspaceService) {
this.workspaceService = workspaceService;
}

@GetMapping("/classrooms")
public List<ClassroomView> listClassrooms() {
return workspaceService.listClassrooms();
}

@PostMapping("/classrooms")
public ClassroomView createClassroom(@RequestBody CreateClassroomRequest request) {
return workspaceService.createClassroom(request.name(), request.teacherName());
}

@PostMapping("/classrooms/{classroomId}/students")
public StudentView addStudent(@PathVariable String classroomId, @RequestBody CreateStudentRequest request) {
return workspaceService.addStudent(classroomId, request.name());
}

@GetMapping("/classrooms/{classroomId}/students")
public List<StudentView> listStudents(@PathVariable String classroomId) {
return workspaceService.listStudents(classroomId);
}

@PostMapping("/classrooms/{classroomId}/assignments")
public AssignmentView createAssignment(@PathVariable String classroomId, @RequestBody CreateAssignmentRequest request) {
return workspaceService.createAssignment(classroomId, request.title(), request.bookPath());
}

@GetMapping("/classrooms/{classroomId}/assignments")
public List<AssignmentView> listAssignments(@PathVariable String classroomId) {
return workspaceService.listAssignments(classroomId);
}

@PostMapping("/attempts/link")
public void linkAttempt(@RequestBody LinkAttemptRequest request) {
workspaceService.linkAttempt(request.studentId(), request.assignmentId(), request.sessionId());
}

@GetMapping("/classrooms/{classroomId}/dashboard")
public ClassroomDashboardResponse getDashboard(@PathVariable String classroomId) {
return workspaceService.getDashboard(classroomId);
}

@GetMapping(value = "/classrooms/{classroomId}/report.csv", produces = "text/csv")
public ResponseEntity<byte[]> exportCsv(@PathVariable String classroomId) {
String csv = workspaceService.exportClassroomCsv(classroomId);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"classroom-" + classroomId + "-report.csv\"")
.contentType(new MediaType("text", "csv", StandardCharsets.UTF_8))
.body(csv.getBytes(StandardCharsets.UTF_8));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.juegodefinitivo.autobook.api.dto;

public record AssignmentView(String id, String classroomId, String title, String bookPath) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.juegodefinitivo.autobook.api.dto;

import java.util.List;

public record ClassroomDashboardResponse(
String classroomId,
String classroomName,
String teacherName,
int students,
int assignments,
List<StudentProgressView> studentProgress
) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.juegodefinitivo.autobook.api.dto;

public record ClassroomView(
String id,
String name,
String teacherName,
int students,
int assignments
) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.juegodefinitivo.autobook.api.dto;

public record CreateAssignmentRequest(String title, String bookPath) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.juegodefinitivo.autobook.api.dto;

public record CreateClassroomRequest(String name, String teacherName) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.juegodefinitivo.autobook.api.dto;

public record CreateStudentRequest(String name) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.juegodefinitivo.autobook.api.dto;

public record LinkAttemptRequest(String studentId, String assignmentId, String sessionId) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.juegodefinitivo.autobook.api.dto;

public record StudentProgressView(
String studentId,
String studentName,
int attempts,
int completedAttempts,
int averageScore,
int averageCorrectAnswers,
int averageProgressPercent,
String dominantDifficulty
) {
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.juegodefinitivo.autobook.api.dto;

public record StudentView(String id, String classroomId, String name) {
}

Loading