diff --git a/backend/src/main/java/com/sshmanager/config/WebSocketThreadPoolConfig.java b/backend/src/main/java/com/sshmanager/config/WebSocketThreadPoolConfig.java
index a433e7a..607f039 100644
--- a/backend/src/main/java/com/sshmanager/config/WebSocketThreadPoolConfig.java
+++ b/backend/src/main/java/com/sshmanager/config/WebSocketThreadPoolConfig.java
@@ -5,9 +5,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -35,14 +33,4 @@ public class WebSocketThreadPoolConfig {
);
return executor;
}
-
- @Bean
- public ScheduledExecutorService websocketCleanupScheduler() {
- ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
- scheduler.scheduleAtFixedRate(this::cleanupIdleSessions, 30, 30, TimeUnit.MINUTES);
- return scheduler;
- }
-
- private void cleanupIdleSessions() {
- }
}
diff --git a/backend/src/main/java/com/sshmanager/controller/PortForwardController.java b/backend/src/main/java/com/sshmanager/controller/PortForwardController.java
new file mode 100644
index 0000000..07a4d68
--- /dev/null
+++ b/backend/src/main/java/com/sshmanager/controller/PortForwardController.java
@@ -0,0 +1,163 @@
+package com.sshmanager.controller;
+
+import com.sshmanager.entity.Connection;
+import com.sshmanager.entity.User;
+import com.sshmanager.exception.AccessDeniedException;
+import com.sshmanager.exception.NotFoundException;
+import com.sshmanager.repository.ConnectionRepository;
+import com.sshmanager.repository.UserRepository;
+import com.sshmanager.service.ConnectionService;
+import com.sshmanager.service.PortForwardRegistry;
+import com.sshmanager.service.PortForwardRegistry.TunnelEntry;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * REST API for managing in-memory SSH port-forwarding tunnels.
+ *
+ *
+ * - GET /api/port-forwards – list running tunnels for the current user
+ * - POST /api/port-forwards – create a new tunnel
+ * - DELETE /api/port-forwards/{id} – stop a tunnel
+ *
+ *
+ * All tunnels are ephemeral: they live only while the server is running.
+ */
+@RestController
+@RequestMapping("/api/port-forwards")
+public class PortForwardController {
+
+ private final PortForwardRegistry portForwardRegistry;
+ private final ConnectionRepository connectionRepository;
+ private final ConnectionService connectionService;
+ private final UserRepository userRepository;
+
+ public PortForwardController(PortForwardRegistry portForwardRegistry,
+ ConnectionRepository connectionRepository,
+ ConnectionService connectionService,
+ UserRepository userRepository) {
+ this.portForwardRegistry = portForwardRegistry;
+ this.connectionRepository = connectionRepository;
+ this.connectionService = connectionService;
+ this.userRepository = userRepository;
+ }
+
+ // ── helpers ───────────────────────────────────────────────────────────────
+
+ private Long getCurrentUserId(Authentication auth) {
+ User user = userRepository.findByUsername(auth.getName())
+ .orElseThrow(() -> new IllegalStateException("User not found"));
+ return user.getId();
+ }
+
+ private static Map toDto(TunnelEntry e) {
+ Map dto = new HashMap<>();
+ dto.put("id", e.getId());
+ dto.put("connectionId", e.getConnectionId());
+ dto.put("connectionName", e.getConnectionName());
+ dto.put("localPort", e.getLocalPort());
+ dto.put("remoteHost", e.getRemoteHost());
+ dto.put("remotePort", e.getRemotePort());
+ dto.put("status", e.getStatus().name().toLowerCase());
+ dto.put("createdAt", e.getCreatedAt().toString());
+ return dto;
+ }
+
+ // ── endpoints ─────────────────────────────────────────────────────────────
+
+ /** GET /api/port-forwards — list active tunnels for the authenticated user. */
+ @GetMapping
+ public ResponseEntity>> list(Authentication auth) {
+ Long userId = getCurrentUserId(auth);
+ List