Migrate backend from Python to Java Spring Boot

- Full Java 21 + Spring Boot 3.3 backend with Virtual Threads
- HikariCP connection pool for Oracle ADB
- JWT auth, Redis caching, OCI GenAI integration
- YouTube transcript extraction via API + Playwright browser fallback
- SSE streaming for bulk operations
- Scheduled daemon for channel scanning/video processing
- Mobile UI: collapse restaurant list to single row on selection
- Switch PM2 ecosystem config to Java backend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-03-09 20:26:32 +09:00
parent 161b1383be
commit 6d05be2331
50 changed files with 4644 additions and 23 deletions

View File

@@ -0,0 +1,82 @@
package com.tasteby.controller;
import com.tasteby.security.AuthUtil;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/daemon")
public class DaemonController {
private final NamedParameterJdbcTemplate jdbc;
public DaemonController(NamedParameterJdbcTemplate jdbc) {
this.jdbc = jdbc;
}
@GetMapping("/config")
public Map<String, Object> getConfig() {
String sql = """
SELECT scan_enabled, scan_interval_min, process_enabled, process_interval_min,
process_limit, last_scan_at, last_process_at, updated_at
FROM daemon_config WHERE id = 1
""";
var rows = jdbc.queryForList(sql, new MapSqlParameterSource());
if (rows.isEmpty()) return Map.of();
var row = rows.getFirst();
var result = new LinkedHashMap<String, Object>();
result.put("scan_enabled", toInt(row.get("SCAN_ENABLED")) == 1);
result.put("scan_interval_min", row.get("SCAN_INTERVAL_MIN"));
result.put("process_enabled", toInt(row.get("PROCESS_ENABLED")) == 1);
result.put("process_interval_min", row.get("PROCESS_INTERVAL_MIN"));
result.put("process_limit", row.get("PROCESS_LIMIT"));
result.put("last_scan_at", row.get("LAST_SCAN_AT") != null ? row.get("LAST_SCAN_AT").toString() : null);
result.put("last_process_at", row.get("LAST_PROCESS_AT") != null ? row.get("LAST_PROCESS_AT").toString() : null);
result.put("updated_at", row.get("UPDATED_AT") != null ? row.get("UPDATED_AT").toString() : null);
return result;
}
@PutMapping("/config")
public Map<String, Object> updateConfig(@RequestBody Map<String, Object> body) {
AuthUtil.requireAdmin();
var sets = new ArrayList<String>();
var params = new MapSqlParameterSource();
if (body.containsKey("scan_enabled")) {
sets.add("scan_enabled = :se");
params.addValue("se", Boolean.TRUE.equals(body.get("scan_enabled")) ? 1 : 0);
}
if (body.containsKey("scan_interval_min")) {
sets.add("scan_interval_min = :si");
params.addValue("si", ((Number) body.get("scan_interval_min")).intValue());
}
if (body.containsKey("process_enabled")) {
sets.add("process_enabled = :pe");
params.addValue("pe", Boolean.TRUE.equals(body.get("process_enabled")) ? 1 : 0);
}
if (body.containsKey("process_interval_min")) {
sets.add("process_interval_min = :pi");
params.addValue("pi", ((Number) body.get("process_interval_min")).intValue());
}
if (body.containsKey("process_limit")) {
sets.add("process_limit = :pl");
params.addValue("pl", ((Number) body.get("process_limit")).intValue());
}
if (!sets.isEmpty()) {
sets.add("updated_at = SYSTIMESTAMP");
String sql = "UPDATE daemon_config SET " + String.join(", ", sets) + " WHERE id = 1";
jdbc.update(sql, params);
}
return Map.of("ok", true);
}
private int toInt(Object val) {
if (val == null) return 0;
return ((Number) val).intValue();
}
}