diff --git a/examenes/1/1/clavebioid.dat b/examenes/1/1/clavebioid.dat
new file mode 100644
index 0000000..7b892e3
--- /dev/null
+++ b/examenes/1/1/clavebioid.dat
@@ -0,0 +1,6 @@
+227000001001011026001   5310 #0001    N 074151P           
+227000002001011026001   5310 #0001    N 074153Q           
+227000003001011026001   5310 #0001    N 074148R           
+227000004001011026001   5310 #0001    N 074147S           
+227000005001011026001   5310 #0001    N 074154T           
+
\ No newline at end of file
diff --git a/examenes/1/1/clavebioresp.dat b/examenes/1/1/clavebioresp.dat
new file mode 100644
index 0000000..d0a1ac5
--- /dev/null
+++ b/examenes/1/1/clavebioresp.dat
@@ -0,0 +1,6 @@
+228000001001011026001   5310 #0001    N 074151BDBDCEDACCCBDDAADCDEACEBBEDDDBEEAADCECAADBADBABCDDCAEEEEBCBA                              
+228000002001011026001   5310 #0001    N 074153ACBADAEAABDECECACBEDEDBCADDCEDDDCADDDBCDBBAAADBADBEBCBDABACB                              
+228000003001011026001   5310 #0001    N 074148AAADBBCACBDEEEBCCDEAADADADDABAAABDDCCAECCCCBCCEDADDACDCDACDE                              
+228000004001011026001   5310 #0001    N 074147BBDCDBDDCBACDBAAEBBCBEABECACACECDCEBDBBBBDDECAABACEEDECDCEEA                              
+228000005001011026001   5310 #0001    N 074154CEDBBAAAABECDDEBEDCABACBEECCEACCCCDAEABCAAAAEEDCDCCDEBECDDEE                              
+
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/controller/CarpetaExamenController.java b/src/main/java/com/service/ingresantes/controller/CarpetaExamenController.java
new file mode 100644
index 0000000..fc9157c
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/controller/CarpetaExamenController.java
@@ -0,0 +1,44 @@
+package com.service.ingresantes.controller;
+
+import com.service.ingresantes.service.CarpetaExamenService;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping("/api/examen")
+@CrossOrigin("*")
+public class CarpetaExamenController {
+
+    private final CarpetaExamenService carpetaService;
+
+    public CarpetaExamenController(CarpetaExamenService carpetaService) {
+        this.carpetaService = carpetaService;
+    }
+
+    @PostMapping("/upload")
+    public ResponseEntity<?> subirArchivo(
+            @RequestParam("file") MultipartFile file,
+            @RequestParam("tipo") String tipo,
+            @RequestParam("procesoId") Long procesoId,
+            @RequestParam("areaId") Long areaId) {
+
+        try {
+
+            if (file.isEmpty()) {
+                return ResponseEntity.badRequest().body("Archivo vacío");
+            }
+
+            carpetaService.subirArchivo(file, tipo, procesoId, areaId);
+
+            return ResponseEntity.ok("Archivo .dat subido correctamente");
+
+        } catch (Exception e) {
+
+            return ResponseEntity
+                    .badRequest()
+                    .body("Error al subir archivo: " + e.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/controller/ClaveExamenController.java b/src/main/java/com/service/ingresantes/controller/ClaveExamenController.java
new file mode 100644
index 0000000..dd62313
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/controller/ClaveExamenController.java
@@ -0,0 +1,34 @@
+package com.service.ingresantes.controller;
+
+import com.service.ingresantes.service.ClaveExamenService;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/api/claves")
+@CrossOrigin("*")
+public class ClaveExamenController {
+
+    private final ClaveExamenService claveService;
+
+    public ClaveExamenController(ClaveExamenService claveService) {
+        this.claveService = claveService;
+    }
+
+    @PostMapping("/procesar")
+    public ResponseEntity<?> procesarClaves(
+            @RequestParam("procesoId") Long procesoId,
+            @RequestParam("areaId") Long areaId) {
+
+        try {
+            int guardadas = claveService.procesarClaves(procesoId, areaId);
+            return ResponseEntity.ok("Claves procesadas y guardadas correctamente: " + guardadas);
+        } catch (Exception e) {
+            return ResponseEntity
+                    .badRequest()
+                    .body("Error al procesar claves: " + e.getMessage());
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java b/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java
new file mode 100644
index 0000000..89ccf2e
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/controller/ExcelResultadoController.java
@@ -0,0 +1,40 @@
+package com.service.ingresantes.controller;
+
+import com.service.ingresantes.service.ExcelResultadoService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping("/api/excel")
+@CrossOrigin("*")
+public class ExcelResultadoController {
+
+    private final ExcelResultadoService excelResultadoService;
+
+    public ExcelResultadoController(ExcelResultadoService excelResultadoService) {
+        this.excelResultadoService = excelResultadoService;
+    }
+
+    @PostMapping("/upload-resultados")
+    public ResponseEntity<String> uploadResultados(
+            @RequestParam("file") MultipartFile file) {
+
+        if (file.isEmpty()) {
+            return ResponseEntity.badRequest().body("El archivo está vacío");
+        }
+
+        try {
+
+            excelResultadoService.importarExcelResultados(file);
+
+            return ResponseEntity.ok("Archivo de resultados procesado correctamente");
+
+        } catch (Exception e) {
+
+            return ResponseEntity
+                    .badRequest()
+                    .body("Error al procesar el archivo: " + e.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/controller/ResultadoController.java b/src/main/java/com/service/ingresantes/controller/ResultadoController.java
new file mode 100644
index 0000000..94d5a2c
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/controller/ResultadoController.java
@@ -0,0 +1,51 @@
+package com.service.ingresantes.controller;
+
+import com.service.ingresantes.entity.ResultadoExamen;
+import com.service.ingresantes.service.ResultadoService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+
+@RestController
+@RequestMapping("/api/resultados")
+@CrossOrigin("*")
+public class ResultadoController {
+
+    private final ResultadoService resultadoService;
+
+    public ResultadoController(ResultadoService resultadoService) {
+        this.resultadoService = resultadoService;
+    }
+
+    // Buscar resultado por DNI y proceso
+    @GetMapping("/{dni}/{procesoId}")
+    public ResponseEntity<?> obtenerResultado(
+            @PathVariable String dni,
+            @PathVariable Long procesoId) {
+
+        Optional<ResultadoExamen> resultado =
+                resultadoService.obtenerResultado(dni, procesoId);
+
+        if (resultado.isEmpty()) {
+
+            return ResponseEntity
+                    .badRequest()
+                    .body("No se encontró resultado para ese DNI y proceso");
+        }
+
+        return ResponseEntity.ok(resultado.get());
+    }
+
+    // Ranking del proceso
+    @GetMapping("/ranking/{procesoId}")
+    public ResponseEntity<List<ResultadoExamen>> ranking(
+            @PathVariable Long procesoId) {
+
+        List<ResultadoExamen> ranking =
+                resultadoService.obtenerRanking(procesoId);
+
+        return ResponseEntity.ok(ranking);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/entity/ClaveExamen.java b/src/main/java/com/service/ingresantes/entity/ClaveExamen.java
new file mode 100644
index 0000000..1c9176b
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/entity/ClaveExamen.java
@@ -0,0 +1,33 @@
+package com.service.ingresantes.entity;
+
+import jakarta.persistence.*;
+import lombok.*;
+
+@Entity
+@Table(name = "clave_examen")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ClaveExamen {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "id_examen")
+    private String idExamen;
+
+    private String tipo;
+
+    @Column(columnDefinition = "TEXT")
+    private String clave;
+
+    @ManyToOne
+    @JoinColumn(name = "proceso_id")
+    private Proceso proceso;
+
+    @ManyToOne
+    @JoinColumn(name = "area_id")
+    private Area area;
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java b/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java
index b763ec2..b44477d 100644
--- a/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java
+++ b/src/main/java/com/service/ingresantes/entity/ResultadoExamen.java
@@ -5,21 +5,30 @@ import lombok.Data;
 
 @Data
 @Entity
-@Table(name = "resultado_examen")
+@Table(
+    name = "resultado_examen",
+    uniqueConstraints = {
+        @UniqueConstraint(columnNames = {"inscripcion_id"})
+    }
+)
 public class ResultadoExamen {
 
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    // RELACION CON INSCRIPCION
     @OneToOne
     @JoinColumn(name = "inscripcion_id", nullable = false)
     private Inscripcion inscripcion;
 
+    @ManyToOne
+    @JoinColumn(name = "proceso_id", nullable = false)
+    private Proceso proceso;
+
     private Double puntaje;
 
-    private Boolean apto;
+    @Column(length = 2)
+    private String apto;   // SI / NO / CL
 
     private String obs;
 
diff --git a/src/main/java/com/service/ingresantes/repository/CarpetaExamenRepository.java b/src/main/java/com/service/ingresantes/repository/CarpetaExamenRepository.java
index 3648c7b..a716411 100644
--- a/src/main/java/com/service/ingresantes/repository/CarpetaExamenRepository.java
+++ b/src/main/java/com/service/ingresantes/repository/CarpetaExamenRepository.java
@@ -2,10 +2,18 @@ package com.service.ingresantes.repository;
 
 import com.service.ingresantes.entity.CarpetaExamen;
 import org.springframework.data.jpa.repository.JpaRepository;
+
 import java.util.List;
+import java.util.Optional;
 
 public interface CarpetaExamenRepository extends JpaRepository<CarpetaExamen, Long> {
 
     List<CarpetaExamen> findByProcesoIdAndAreaId(Long procesoId, Long areaId);
 
+    Optional<CarpetaExamen> findByProcesoIdAndAreaIdAndTipo(
+            Long procesoId,
+            Long areaId,
+            String tipo
+    );
+
 }
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java b/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java
new file mode 100644
index 0000000..c4d5b6d
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/repository/ClaveExamenRepository.java
@@ -0,0 +1,15 @@
+package com.service.ingresantes.repository;
+
+import com.service.ingresantes.entity.ClaveExamen;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface ClaveExamenRepository extends JpaRepository<ClaveExamen, Long> {
+
+    // Busca una clave por proceso, área e idExamen
+    Optional<ClaveExamen> findByProcesoIdAndAreaIdAndIdExamen(Long procesoId, Long areaId, String idExamen);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/repository/InscripcionRepository.java b/src/main/java/com/service/ingresantes/repository/InscripcionRepository.java
index 1e5201b..8854560 100644
--- a/src/main/java/com/service/ingresantes/repository/InscripcionRepository.java
+++ b/src/main/java/com/service/ingresantes/repository/InscripcionRepository.java
@@ -5,9 +5,17 @@ import com.service.ingresantes.entity.Postulante;
 import com.service.ingresantes.entity.Proceso;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.Optional;
+
 public interface InscripcionRepository extends JpaRepository<Inscripcion, Long> {
 
-    // Método para verificar si existe una inscripción de un postulante a un proceso
+    // Verifica si ya existe inscripción de un postulante a un proceso
     boolean existsByPostulanteAndProceso(Postulante postulante, Proceso proceso);
 
+    // Buscar inscripción por postulante y proceso
+    Optional<Inscripcion> findByPostulanteAndProceso(Postulante postulante, Proceso proceso);
+
+    // Buscar inscripción directamente por DNI y proceso
+    Optional<Inscripcion> findByPostulanteDniAndProcesoId(String dni, Long procesoId);
+
 }
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java b/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java
index b1b5419..e4c5d79 100644
--- a/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java
+++ b/src/main/java/com/service/ingresantes/repository/ResultadoExamenRepository.java
@@ -2,10 +2,32 @@ package com.service.ingresantes.repository;
 
 import com.service.ingresantes.entity.ResultadoExamen;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
 import java.util.Optional;
 
 public interface ResultadoExamenRepository extends JpaRepository<ResultadoExamen, Long> {
 
-    Optional<ResultadoExamen> findByInscripcionId(Long inscripcionId);
+    boolean existsByInscripcionId(Long inscripcionId);
+
+    // Buscar resultado por DNI y proceso
+    @Query("""
+        SELECT r FROM ResultadoExamen r
+        JOIN r.inscripcion i
+        JOIN i.postulante p
+        WHERE p.dni = :dni
+        AND i.proceso.id = :procesoId
+    """)
+    Optional<ResultadoExamen> findByDniAndProceso(String dni, Long procesoId);
+
 
+    // Ranking por proceso
+    @Query("""
+        SELECT r FROM ResultadoExamen r
+        JOIN r.inscripcion i
+        WHERE i.proceso.id = :procesoId
+        ORDER BY r.puntaje DESC
+    """)
+    List<ResultadoExamen> findRankingByProceso(Long procesoId);
 }
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/service/CarpetaExamenService.java b/src/main/java/com/service/ingresantes/service/CarpetaExamenService.java
new file mode 100644
index 0000000..3f8f38e
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/service/CarpetaExamenService.java
@@ -0,0 +1,68 @@
+package com.service.ingresantes.service;
+
+import com.service.ingresantes.entity.Area;
+import com.service.ingresantes.entity.CarpetaExamen;
+import com.service.ingresantes.entity.Proceso;
+import com.service.ingresantes.repository.AreaRepository;
+import com.service.ingresantes.repository.CarpetaExamenRepository;
+import com.service.ingresantes.repository.ProcesoRepository;
+
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+
+@Service
+public class CarpetaExamenService {
+
+    private final CarpetaExamenRepository carpetaRepo;
+    private final ProcesoRepository procesoRepo;
+    private final AreaRepository areaRepo;
+
+    public CarpetaExamenService(
+            CarpetaExamenRepository carpetaRepo,
+            ProcesoRepository procesoRepo,
+            AreaRepository areaRepo) {
+
+        this.carpetaRepo = carpetaRepo;
+        this.procesoRepo = procesoRepo;
+        this.areaRepo = areaRepo;
+    }
+
+        public void subirArchivo(
+            MultipartFile file,
+            String tipo,
+            Long procesoId,
+            Long areaId) throws Exception {
+
+        Proceso proceso = procesoRepo.findById(procesoId)
+                .orElseThrow(() -> new RuntimeException("Proceso no existe"));
+
+        Area area = areaRepo.findById(areaId)
+                .orElseThrow(() -> new RuntimeException("Area no existe"));
+
+        String rutaBase = System.getProperty("user.dir") +
+                "/examenes/" + procesoId + "/" + areaId + "/";
+
+        File carpeta = new File(rutaBase);
+
+        if (!carpeta.exists()) {
+            carpeta.mkdirs();
+        }
+
+        String nombreArchivo = file.getOriginalFilename();
+
+        File destino = new File(rutaBase + nombreArchivo);
+
+        file.transferTo(destino);
+
+        CarpetaExamen carpetaExamen = CarpetaExamen.builder()
+                .tipo(tipo)
+                .ruta(destino.getAbsolutePath())
+                .proceso(proceso)
+                .area(area)
+                .build();
+
+        carpetaRepo.save(carpetaExamen);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/service/ClaveExamenService.java b/src/main/java/com/service/ingresantes/service/ClaveExamenService.java
new file mode 100644
index 0000000..642f1f8
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/service/ClaveExamenService.java
@@ -0,0 +1,98 @@
+package com.service.ingresantes.service;
+
+import com.service.ingresantes.entity.CarpetaExamen;
+import com.service.ingresantes.entity.ClaveExamen;
+import com.service.ingresantes.entity.Proceso;
+import com.service.ingresantes.entity.Area;
+import com.service.ingresantes.repository.CarpetaExamenRepository;
+import com.service.ingresantes.repository.ClaveExamenRepository;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+
+@Service
+public class ClaveExamenService {
+
+    private final CarpetaExamenRepository carpetaRepo;
+    private final ClaveExamenRepository claveRepo;
+
+    public ClaveExamenService(
+            CarpetaExamenRepository carpetaRepo,
+            ClaveExamenRepository claveRepo) {
+        this.carpetaRepo = carpetaRepo;
+        this.claveRepo = claveRepo;
+    }
+
+    @Transactional
+    public int procesarClaves(Long procesoId, Long areaId) throws Exception {
+
+        // 1️⃣ Buscar archivos
+        CarpetaExamen archivoClaveId = carpetaRepo
+                .findByProcesoIdAndAreaIdAndTipo(procesoId, areaId, "claves_id")
+                .orElseThrow(() -> new RuntimeException("No existe archivo clave_id"));
+
+        CarpetaExamen archivoClaves = carpetaRepo
+                .findByProcesoIdAndAreaIdAndTipo(procesoId, areaId, "claves")
+                .orElseThrow(() -> new RuntimeException("No existe archivo claves"));
+
+        // 2️⃣ Leer archivo claves_id → idExamen + tipo
+        Map<String, String> tipoMap = new HashMap<>();
+        List<String> lineasId = Files.readAllLines(Paths.get(archivoClaveId.getRuta()));
+        for (String linea : lineasId) {
+            linea = linea.trim();
+            if (linea.length() < 7) continue;
+
+            String ultimos7 = linea.substring(linea.length() - 7);
+            String idExamen = ultimos7.substring(0, 6);
+            String tipo = ultimos7.substring(6, 7);
+            tipoMap.put(idExamen, tipo);
+        }
+
+        // 3️⃣ Leer archivo claves
+        List<String> lineasClaves = Files.readAllLines(Paths.get(archivoClaves.getRuta()));
+        List<ClaveExamen> listaGuardar = new ArrayList<>();
+
+        Proceso proceso = new Proceso();
+        proceso.setId(procesoId);
+        Area area = new Area();
+        area.setId(areaId);
+
+        for (String linea : lineasClaves) {
+            linea = linea.trim();
+            if (linea.length() < 7) continue;
+
+            int posId = linea.indexOf("074"); // buscar inicio del idExamen
+            if (posId == -1 || linea.length() < posId + 6) continue;
+
+            String idExamen = linea.substring(posId, posId + 6);
+            String clave = linea.substring(posId + 6); // todo lo demás
+
+            String tipo = tipoMap.get(idExamen);
+            if (tipo == null) continue;
+
+            // ❌ Solo guardar si no existe en la base de datos
+            boolean existe = claveRepo.findByProcesoIdAndAreaIdAndIdExamen(procesoId, areaId, idExamen).isPresent();
+            if (existe) continue;
+
+            ClaveExamen c = ClaveExamen.builder()
+                    .idExamen(idExamen)
+                    .tipo(tipo)
+                    .clave(clave)
+                    .proceso(proceso)
+                    .area(area)
+                    .build();
+
+            listaGuardar.add(c);
+        }
+
+        // 4️⃣ Guardar en DB
+        claveRepo.saveAll(listaGuardar);
+
+        System.out.println("Claves procesadas y guardadas: " + listaGuardar.size());
+        return listaGuardar.size();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/service/ClaveExamenServiceBloque.java b/src/main/java/com/service/ingresantes/service/ClaveExamenServiceBloque.java
new file mode 100644
index 0000000..c0c91c6
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/service/ClaveExamenServiceBloque.java
@@ -0,0 +1,122 @@
+package com.service.ingresantes.service;
+
+import com.service.ingresantes.entity.CarpetaExamen;
+import com.service.ingresantes.entity.ClaveExamen;
+import com.service.ingresantes.entity.Proceso;
+import com.service.ingresantes.entity.Area;
+import com.service.ingresantes.repository.CarpetaExamenRepository;
+import com.service.ingresantes.repository.ClaveExamenRepository;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+
+@Service
+public class ClaveExamenServiceBloque {
+
+    private final CarpetaExamenRepository carpetaRepo;
+    private final ClaveExamenRepository claveRepo;
+
+    public ClaveExamenServiceBloque(
+            CarpetaExamenRepository carpetaRepo,
+            ClaveExamenRepository claveRepo) {
+        this.carpetaRepo = carpetaRepo;
+        this.claveRepo = claveRepo;
+    }
+
+    @Transactional
+    public int procesarClaves(Long procesoId, Long areaId) throws Exception {
+
+        // 1️⃣ Buscar archivos en CarpetaExamen
+        CarpetaExamen archivoClaveId = carpetaRepo
+                .findByProcesoIdAndAreaIdAndTipo(procesoId, areaId, "claves_id")
+                .orElseThrow(() -> new RuntimeException("No existe archivo clave_id"));
+
+        CarpetaExamen archivoClaves = carpetaRepo
+                .findByProcesoIdAndAreaIdAndTipo(procesoId, areaId, "claves")
+                .orElseThrow(() -> new RuntimeException("No existe archivo claves"));
+
+        // 2️⃣ Map para idExamen -> tipo
+        Map<String, String> tipoMap = new HashMap<>();
+        List<String> lineasId = Files.readAllLines(Paths.get(archivoClaveId.getRuta()));
+
+        for (String linea : lineasId) {
+            linea = linea.trim();
+            if (linea.length() < 7) continue;
+
+            // Tomamos los últimos 7 caracteres de la línea
+            String ultimos7 = linea.substring(linea.length() - 7);
+            String idExamen = ultimos7.substring(0, 6);
+            String tipo = ultimos7.substring(6, 7);
+            tipoMap.put(idExamen, tipo);
+        }
+
+        // 3️⃣ Leer archivo claves
+        List<String> lineasClaves = Files.readAllLines(Paths.get(archivoClaves.getRuta()));
+        List<ClaveExamen> listaGuardar = new ArrayList<>();
+
+        Proceso proceso = new Proceso();
+        proceso.setId(procesoId);
+        Area area = new Area();
+        area.setId(areaId);
+
+        int descartadas = 0;
+
+        for (String linea : lineasClaves) {
+            linea = linea.trim();
+            if (linea.length() < 7) {
+                descartadas++;
+                continue;
+            }
+
+            // Buscar idExamen dentro de la línea: 6 dígitos seguidos de letra
+            // Regex simple: 6 dígitos + 1 letra
+            String idExamen = null;
+            String clave = null;
+
+            for (int i = 0; i < linea.length() - 6; i++) {
+                String candidato = linea.substring(i, i + 7);
+                if (candidato.matches("\\d{6}[A-Z]")) { // 6 números + 1 letra
+                    idExamen = candidato.substring(0, 6);
+                    // Clave = todo lo que sigue después de idExamen + tipo
+                    clave = linea.substring(i + 7);
+                    break;
+                }
+            }
+
+            if (idExamen == null || clave == null) {
+                descartadas++;
+                continue;
+            }
+
+            String tipo = tipoMap.get(idExamen);
+            if (tipo == null) {
+                descartadas++;
+                continue;
+            }
+
+            ClaveExamen c = ClaveExamen.builder()
+                    .idExamen(idExamen)
+                    .tipo(tipo)
+                    .clave(clave)
+                    .proceso(proceso)
+                    .area(area)
+                    .build();
+
+            listaGuardar.add(c);
+        }
+
+        // 4️⃣ Guardar en DB
+        claveRepo.saveAll(listaGuardar);
+
+        // 5️⃣ Reporte
+        System.out.println("Total líneas leídas: " + lineasClaves.size());
+        System.out.println("Claves procesadas y guardadas: " + listaGuardar.size());
+        System.out.println("Claves descartadas: " + descartadas);
+
+        return listaGuardar.size();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java b/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java
new file mode 100644
index 0000000..d58548c
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/service/ExcelResultadoService.java
@@ -0,0 +1,162 @@
+package com.service.ingresantes.service;
+
+import com.service.ingresantes.entity.Inscripcion;
+import com.service.ingresantes.entity.ResultadoExamen;
+import com.service.ingresantes.repository.InscripcionRepository;
+import com.service.ingresantes.repository.ResultadoExamenRepository;
+
+import org.apache.poi.ss.usermodel.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import jakarta.transaction.Transactional;
+import java.io.InputStream;
+import java.util.Optional;
+
+@Service
+public class ExcelResultadoService {
+
+    private final InscripcionRepository inscripcionRepo;
+    private final ResultadoExamenRepository resultadoRepo;
+
+    public ExcelResultadoService(
+            InscripcionRepository inscripcionRepo,
+            ResultadoExamenRepository resultadoRepo) {
+
+        this.inscripcionRepo = inscripcionRepo;
+        this.resultadoRepo = resultadoRepo;
+    }
+
+    private String getCellString(Cell cell) {
+
+        if (cell == null) return "";
+
+        switch (cell.getCellType()) {
+
+            case STRING:
+                return cell.getStringCellValue().trim();
+
+            case NUMERIC:
+                return String.valueOf((long) cell.getNumericCellValue());
+
+            default:
+                return "";
+        }
+    }
+
+    private Double getCellDouble(Cell cell) {
+
+        if (cell == null) return null;
+
+        if (cell.getCellType() == CellType.NUMERIC) {
+            return cell.getNumericCellValue();
+        }
+
+        if (cell.getCellType() == CellType.STRING) {
+            return Double.parseDouble(cell.getStringCellValue());
+        }
+
+        return null;
+    }
+
+    private Integer getCellInteger(Cell cell) {
+
+        if (cell == null) return null;
+
+        if (cell.getCellType() == CellType.NUMERIC) {
+            return (int) cell.getNumericCellValue();
+        }
+
+        if (cell.getCellType() == CellType.STRING) {
+            return Integer.parseInt(cell.getStringCellValue());
+        }
+
+        return null;
+    }
+
+    @Transactional
+    public void importarExcelResultados(MultipartFile file) throws Exception {
+
+        InputStream is = file.getInputStream();
+        Workbook workbook = WorkbookFactory.create(is);
+        Sheet sheet = workbook.getSheetAt(0);
+
+        for (Row row : sheet) {
+
+            if (row.getRowNum() == 0) continue;
+
+            try {
+
+                String dni = getCellString(row.getCell(0));
+                String procesoStr = getCellString(row.getCell(1));
+
+                if (dni.isEmpty() || procesoStr.isEmpty()) {
+                    continue;
+                }
+
+                Long procesoId = Long.parseLong(procesoStr);
+
+                Optional<Inscripcion> inscripcionOpt =
+                        inscripcionRepo.findByPostulanteDniAndProcesoId(dni, procesoId);
+
+                if (inscripcionOpt.isEmpty()) {
+
+                    System.out.println("No existe inscripción -> DNI " + dni);
+                    continue;
+                }
+
+                Inscripcion inscripcion = inscripcionOpt.get();
+
+                if (resultadoRepo.existsByInscripcionId(inscripcion.getId())) {
+
+                    System.out.println("Resultado ya existe -> DNI " + dni);
+                    continue;
+                }
+
+                Double puntaje = getCellDouble(row.getCell(2));
+                String apto = getCellString(row.getCell(3));
+                String obs = getCellString(row.getCell(4));
+
+                String idExamen = getCellString(row.getCell(5));
+                String litho = getCellString(row.getCell(6));
+                String numLectura = getCellString(row.getCell(7));
+                String tipo = getCellString(row.getCell(8));
+                String calificar = getCellString(row.getCell(9));
+                String aula = getCellString(row.getCell(10));
+                String respuestas = getCellString(row.getCell(11));
+
+                Integer puesto = getCellInteger(row.getCell(12));
+
+                ResultadoExamen resultado = new ResultadoExamen();
+
+                resultado.setInscripcion(inscripcion);
+                resultado.setProceso(inscripcion.getProceso());
+
+                resultado.setPuntaje(puntaje);
+                resultado.setApto(apto);
+                resultado.setObs(obs);
+
+                resultado.setIdExamen(idExamen);
+                resultado.setLitho(litho);
+                resultado.setNumLectura(numLectura);
+                resultado.setTipo(tipo);
+                resultado.setCalificar(calificar);
+                resultado.setAula(aula);
+                resultado.setRespuestas(respuestas);
+
+                resultado.setPuesto(puesto);
+
+                resultadoRepo.save(resultado);
+
+                System.out.println("Resultado guardado -> DNI " + dni);
+
+            } catch (Exception e) {
+
+                System.out.println("Error fila " + row.getRowNum() + " -> " + e.getMessage());
+            }
+        }
+
+        workbook.close();
+        is.close();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/service/ingresantes/service/ResultadoService.java b/src/main/java/com/service/ingresantes/service/ResultadoService.java
new file mode 100644
index 0000000..d127b53
--- /dev/null
+++ b/src/main/java/com/service/ingresantes/service/ResultadoService.java
@@ -0,0 +1,30 @@
+package com.service.ingresantes.service;
+
+import com.service.ingresantes.entity.ResultadoExamen;
+import com.service.ingresantes.repository.ResultadoExamenRepository;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class ResultadoService {
+
+    private final ResultadoExamenRepository resultadoRepo;
+
+    public ResultadoService(ResultadoExamenRepository resultadoRepo) {
+        this.resultadoRepo = resultadoRepo;
+    }
+
+    // Buscar resultado por DNI y proceso
+    public Optional<ResultadoExamen> obtenerResultado(String dni, Long procesoId) {
+
+        return resultadoRepo.findByDniAndProceso(dni, procesoId);
+    }
+
+    // Ranking por proceso
+    public List<ResultadoExamen> obtenerRanking(Long procesoId) {
+
+        return resultadoRepo.findRankingByProceso(procesoId);
+    }
+}
\ No newline at end of file
