From 04df491d64a82df676d98bc54038c8223929e64c Mon Sep 17 00:00:00 2001 From: Tour Date: Fri, 5 Dec 2025 06:19:28 +0100 Subject: [PATCH] Fix mock tests --- src/main/java/auctiora/AuctionInfo.java | 4 +- src/main/java/auctiora/DatabaseService.java | 218 +++-- .../java/auctiora/ImageProcessingService.java | 4 +- src/main/java/auctiora/Lot.java | 4 +- .../java/auctiora/ScraperDataAdapter.java | 30 +- .../java/auctiora/WorkflowOrchestrator.java | 44 +- .../resources/META-INF/resources/index.html | 224 +++++ .../META-INF/resources/praetium.html | 572 +++++++++++++ src/main/resources/resources/praetium.html | 773 ++++++++++-------- .../auctiora/ImageProcessingServiceTest.java | 4 +- wiki/QUARKUS_COMPLETE.md | 589 ------------- wiki/REFACTORING_SUMMARY.md | 118 --- wiki/RUN_INSTRUCTIONS.md | 164 ---- 13 files changed, 1460 insertions(+), 1288 deletions(-) create mode 100644 src/main/resources/META-INF/resources/index.html create mode 100644 src/main/resources/META-INF/resources/praetium.html delete mode 100644 wiki/QUARKUS_COMPLETE.md delete mode 100644 wiki/REFACTORING_SUMMARY.md delete mode 100644 wiki/RUN_INSTRUCTIONS.md diff --git a/src/main/java/auctiora/AuctionInfo.java b/src/main/java/auctiora/AuctionInfo.java index 4a7c484..06b7cb4 100644 --- a/src/main/java/auctiora/AuctionInfo.java +++ b/src/main/java/auctiora/AuctionInfo.java @@ -7,13 +7,13 @@ import java.time.LocalDateTime; * Data typically populated by the external scraper process */ public record AuctionInfo( - int auctionId, // Unique auction ID (from URL) + long auctionId, // Unique auction ID (from URL) String title, // Auction title String location, // Location (e.g., "Amsterdam, NL") String city, // City name String country, // Country code (e.g., "NL") String url, // Full auction URL - String typePrefix, // Auction type (A1 or A7) + String typePrefix, // Auction type (A1 or A7) int lotCount, // Number of lots/kavels LocalDateTime firstLotClosingTime // Closing time if available ) { } diff --git a/src/main/java/auctiora/DatabaseService.java b/src/main/java/auctiora/DatabaseService.java index 0407aea..fbd942f 100644 --- a/src/main/java/auctiora/DatabaseService.java +++ b/src/main/java/auctiora/DatabaseService.java @@ -36,7 +36,7 @@ public class DatabaseService { // Auctions table (populated by external scraper) stmt.execute(""" CREATE TABLE IF NOT EXISTS auctions ( - auction_id INTEGER PRIMARY KEY, + auction_id BIGINT PRIMARY KEY, title TEXT NOT NULL, location TEXT, city TEXT, @@ -51,8 +51,8 @@ public class DatabaseService { // Lots table (populated by external scraper) stmt.execute(""" CREATE TABLE IF NOT EXISTS lots ( - lot_id INTEGER PRIMARY KEY, - sale_id INTEGER, + lot_id BIGINT PRIMARY KEY, + sale_id BIGINT, title TEXT, description TEXT, manufacturer TEXT, @@ -94,35 +94,94 @@ public class DatabaseService { * SQLite doesn't support DROP COLUMN, so we add columns with ALTER TABLE ADD COLUMN. */ private void migrateSchema(java.sql.Statement stmt) throws SQLException { - // Check if country column exists in auctions table + // Check auctions table for missing columns try (var rs = stmt.executeQuery("PRAGMA table_info(auctions)")) { - boolean hasCountry = false; + var hasLocation = false; + var hasCity = false; + var hasCountry = false; + var hasType = false; + var hasLotCount = false; + var hasClosingTime = false; + var hasDiscoveredAt = false; + while (rs.next()) { - if ("country".equals(rs.getString("name"))) { - hasCountry = true; - break; + var colName = rs.getString("name"); + switch (colName) { + case "location" -> hasLocation = true; + case "city" -> hasCity = true; + case "country" -> hasCountry = true; + case "type" -> hasType = true; + case "lot_count" -> hasLotCount = true; + case "closing_time" -> hasClosingTime = true; + case "discovered_at" -> hasDiscoveredAt = true; } } + + if (!hasLocation) { + log.info("Migrating schema: Adding 'location' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN location TEXT"); + } + if (!hasCity) { + log.info("Migrating schema: Adding 'city' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN city TEXT"); + } if (!hasCountry) { log.info("Migrating schema: Adding 'country' column to auctions table"); stmt.execute("ALTER TABLE auctions ADD COLUMN country TEXT"); } + if (!hasType) { + log.info("Migrating schema: Adding 'type' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN type TEXT"); + } + if (!hasLotCount) { + log.info("Migrating schema: Adding 'lot_count' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN lot_count INTEGER DEFAULT 0"); + } + if (!hasClosingTime) { + log.info("Migrating schema: Adding 'closing_time' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN closing_time TEXT"); + } + if (!hasDiscoveredAt) { + log.info("Migrating schema: Adding 'discovered_at' column to auctions table"); + stmt.execute("ALTER TABLE auctions ADD COLUMN discovered_at INTEGER"); + } } catch (SQLException e) { // Table might not exist yet, which is fine log.debug("Could not check auctions table schema: " + e.getMessage()); } - // Check if sale_id column exists in lots table (old schema used auction_id) + // Check lots table for missing columns and migrate try (var rs = stmt.executeQuery("PRAGMA table_info(lots)")) { - boolean hasSaleId = false; - boolean hasAuctionId = false; + var hasSaleId = false; + var hasAuctionId = false; + var hasTitle = false; + var hasDescription = false; + var hasManufacturer = false; + var hasType = false; + var hasYear = false; + var hasCategory = false; + var hasCurrentBid = false; + var hasCurrency = false; + var hasUrl = false; + var hasClosingTime = false; + var hasClosingNotified = false; + while (rs.next()) { - String colName = rs.getString("name"); - if ("sale_id".equals(colName)) { - hasSaleId = true; - } - if ("auction_id".equals(colName)) { - hasAuctionId = true; + var colName = rs.getString("name"); + switch (colName) { + case "sale_id" -> hasSaleId = true; + case "auction_id" -> hasAuctionId = true; + case "title" -> hasTitle = true; + case "description" -> hasDescription = true; + case "manufacturer" -> hasManufacturer = true; + case "type" -> hasType = true; + case "year" -> hasYear = true; + case "category" -> hasCategory = true; + case "current_bid" -> hasCurrentBid = true; + case "currency" -> hasCurrency = true; + case "url" -> hasUrl = true; + case "closing_time" -> hasClosingTime = true; + case "closing_notified" -> hasClosingNotified = true; } } @@ -137,6 +196,52 @@ public class DatabaseService { log.info("Migrating schema: Adding 'sale_id' column to new lots table"); stmt.execute("ALTER TABLE lots ADD COLUMN sale_id INTEGER"); } + + // Add missing columns for lot details + if (!hasTitle) { + log.info("Migrating schema: Adding 'title' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN title TEXT"); + } + if (!hasDescription) { + log.info("Migrating schema: Adding 'description' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN description TEXT"); + } + if (!hasManufacturer) { + log.info("Migrating schema: Adding 'manufacturer' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN manufacturer TEXT"); + } + if (!hasType) { + log.info("Migrating schema: Adding 'type' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN type TEXT"); + } + if (!hasYear) { + log.info("Migrating schema: Adding 'year' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN year INTEGER"); + } + if (!hasCategory) { + log.info("Migrating schema: Adding 'category' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN category TEXT"); + } + if (!hasCurrentBid) { + log.info("Migrating schema: Adding 'current_bid' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN current_bid REAL"); + } + if (!hasCurrency) { + log.info("Migrating schema: Adding 'currency' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN currency TEXT DEFAULT 'EUR'"); + } + if (!hasUrl) { + log.info("Migrating schema: Adding 'url' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN url TEXT"); + } + if (!hasClosingTime) { + log.info("Migrating schema: Adding 'closing_time' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN closing_time TEXT"); + } + if (!hasClosingNotified) { + log.info("Migrating schema: Adding 'closing_notified' column to lots table"); + stmt.execute("ALTER TABLE lots ADD COLUMN closing_notified INTEGER DEFAULT 0"); + } } catch (SQLException e) { // Table might not exist yet, which is fine log.debug("Could not check lots table schema: " + e.getMessage()); @@ -162,7 +267,7 @@ public class DatabaseService { """; try (var conn = DriverManager.getConnection(url); var ps = conn.prepareStatement(sql)) { - ps.setInt(1, auction.auctionId()); + ps.setLong(1, auction.auctionId()); ps.setString(2, auction.title()); ps.setString(3, auction.location()); ps.setString(4, auction.city()); @@ -182,15 +287,22 @@ public class DatabaseService { synchronized List getAllAuctions() throws SQLException { List auctions = new ArrayList<>(); var sql = "SELECT auction_id, title, location, city, country, url, type, lot_count, closing_time FROM auctions"; - + try (var conn = DriverManager.getConnection(url); var stmt = conn.createStatement()) { var rs = stmt.executeQuery(sql); while (rs.next()) { var closingStr = rs.getString("closing_time"); - var closing = closingStr != null ? LocalDateTime.parse(closingStr) : null; - + LocalDateTime closing = null; + if (closingStr != null && !closingStr.isBlank()) { + try { + closing = LocalDateTime.parse(closingStr); + } catch (Exception e) { + log.debug("Invalid closing_time format for auction {}: {}", rs.getLong("auction_id"), closingStr); + } + } + auctions.add(new AuctionInfo( - rs.getInt("auction_id"), + rs.getLong("auction_id"), rs.getString("title"), rs.getString("location"), rs.getString("city"), @@ -212,16 +324,23 @@ public class DatabaseService { List auctions = new ArrayList<>(); var sql = "SELECT auction_id, title, location, city, country, url, type, lot_count, closing_time " + "FROM auctions WHERE country = ?"; - + try (var conn = DriverManager.getConnection(url); var ps = conn.prepareStatement(sql)) { ps.setString(1, countryCode); var rs = ps.executeQuery(); while (rs.next()) { var closingStr = rs.getString("closing_time"); - var closing = closingStr != null ? LocalDateTime.parse(closingStr) : null; - + LocalDateTime closing = null; + if (closingStr != null && !closingStr.isBlank()) { + try { + closing = LocalDateTime.parse(closingStr); + } catch (Exception e) { + log.debug("Invalid closing_time format for auction {}: {}", rs.getLong("auction_id"), closingStr); + } + } + auctions.add(new AuctionInfo( - rs.getInt("auction_id"), + rs.getLong("auction_id"), rs.getString("title"), rs.getString("location"), rs.getString("city"), @@ -258,8 +377,8 @@ public class DatabaseService { """; try (var conn = DriverManager.getConnection(url); var ps = conn.prepareStatement(sql)) { - ps.setInt(1, lot.lotId()); - ps.setInt(2, lot.saleId()); + ps.setLong(1, lot.lotId()); + ps.setLong(2, lot.saleId()); ps.setString(3, lot.title()); ps.setString(4, lot.description()); ps.setString(5, lot.manufacturer()); @@ -278,10 +397,10 @@ public class DatabaseService { /** * Inserts a new image record with object detection labels */ - synchronized void insertImage(int lotId, String url, String filePath, List labels) throws SQLException { + synchronized void insertImage(long lotId, String url, String filePath, List labels) throws SQLException { var sql = "INSERT INTO images (lot_id, url, file_path, labels, processed_at) VALUES (?, ?, ?, ?, ?)"; try (var conn = DriverManager.getConnection(this.url); var ps = conn.prepareStatement(sql)) { - ps.setInt(1, lotId); + ps.setLong(1, lotId); ps.setString(2, url); ps.setString(3, filePath); ps.setString(4, String.join(",", labels)); @@ -293,17 +412,17 @@ public class DatabaseService { /** * Retrieves images for a specific lot */ - synchronized List getImagesForLot(int lotId) throws SQLException { + synchronized List getImagesForLot(long lotId) throws SQLException { List images = new ArrayList<>(); var sql = "SELECT id, lot_id, url, file_path, labels FROM images WHERE lot_id = ?"; try (var conn = DriverManager.getConnection(url); var ps = conn.prepareStatement(sql)) { - ps.setInt(1, lotId); + ps.setLong(1, lotId); var rs = ps.executeQuery(); while (rs.next()) { images.add(new ImageRecord( rs.getInt("id"), - rs.getInt("lot_id"), + rs.getLong("lot_id"), rs.getString("url"), rs.getString("file_path"), rs.getString("labels") @@ -320,16 +439,23 @@ public class DatabaseService { List list = new ArrayList<>(); var sql = "SELECT lot_id, sale_id, title, description, manufacturer, type, year, category, " + "current_bid, currency, url, closing_time, closing_notified FROM lots"; - + try (var conn = DriverManager.getConnection(url); var stmt = conn.createStatement()) { var rs = stmt.executeQuery(sql); while (rs.next()) { var closingStr = rs.getString("closing_time"); - var closing = closingStr != null ? LocalDateTime.parse(closingStr) : null; - + LocalDateTime closing = null; + if (closingStr != null && !closingStr.isBlank()) { + try { + closing = LocalDateTime.parse(closingStr); + } catch (Exception e) { + log.debug("Invalid closing_time format for lot {}: {}", rs.getLong("lot_id"), closingStr); + } + } + list.add(new Lot( - rs.getInt("sale_id"), - rs.getInt("lot_id"), + rs.getLong("sale_id"), + rs.getLong("lot_id"), rs.getString("title"), rs.getString("description"), rs.getString("manufacturer"), @@ -375,7 +501,7 @@ public class DatabaseService { try (var conn = DriverManager.getConnection(url); var ps = conn.prepareStatement("UPDATE lots SET current_bid = ? WHERE lot_id = ?")) { ps.setDouble(1, lot.currentBid()); - ps.setInt(2, lot.lotId()); + ps.setLong(2, lot.lotId()); ps.executeUpdate(); } } @@ -387,7 +513,7 @@ public class DatabaseService { try (var conn = DriverManager.getConnection(url); var ps = conn.prepareStatement("UPDATE lots SET closing_notified = ? WHERE lot_id = ?")) { ps.setInt(1, lot.closingNotified() ? 1 : 0); - ps.setInt(2, lot.lotId()); + ps.setLong(2, lot.lotId()); ps.executeUpdate(); } } @@ -472,11 +598,11 @@ public class DatabaseService { try (var conn = DriverManager.getConnection(url); var stmt = conn.createStatement()) { var rs = stmt.executeQuery(sql); while (rs.next()) { - String lotIdStr = rs.getString("lot_id"); - String auctionIdStr = rs.getString("auction_id"); + var lotIdStr = rs.getString("lot_id"); + var auctionIdStr = rs.getString("auction_id"); - int lotId = ScraperDataAdapter.extractNumericId(lotIdStr); - int saleId = ScraperDataAdapter.extractNumericId(auctionIdStr); + var lotId = ScraperDataAdapter.extractNumericId(lotIdStr); + var saleId = ScraperDataAdapter.extractNumericId(auctionIdStr); images.add(new ImageImportRecord( lotId, @@ -494,10 +620,10 @@ public class DatabaseService { /** * Simple record for image data from database */ - record ImageRecord(int id, int lotId, String url, String filePath, String labels) { } + record ImageRecord(int id, long lotId, String url, String filePath, String labels) { } /** * Record for importing images from scraper format */ - record ImageImportRecord(int lotId, int saleId, String url) { } + record ImageImportRecord(long lotId, long saleId, String url) { } } diff --git a/src/main/java/auctiora/ImageProcessingService.java b/src/main/java/auctiora/ImageProcessingService.java index 6b45909..f8ccfd5 100644 --- a/src/main/java/auctiora/ImageProcessingService.java +++ b/src/main/java/auctiora/ImageProcessingService.java @@ -39,7 +39,7 @@ class ImageProcessingService { * @param lotId lot identifier * @return absolute path to saved file or null on failure */ - String downloadImage(String imageUrl, int saleId, int lotId) { + String downloadImage(String imageUrl, long saleId, long lotId) { try { var response = httpClient.sendGetBytes(imageUrl); @@ -79,7 +79,7 @@ class ImageProcessingService { * @param saleId sale identifier * @param imageUrls list of image URLs to process */ - void processImagesForLot(int lotId, int saleId, List imageUrls) { + void processImagesForLot(long lotId, long saleId, List imageUrls) { log.info(" Processing {} images for lot {}", imageUrls.size(), lotId); for (var imgUrl : imageUrls) { diff --git a/src/main/java/auctiora/Lot.java b/src/main/java/auctiora/Lot.java index ea0392d..0cbfe1d 100644 --- a/src/main/java/auctiora/Lot.java +++ b/src/main/java/auctiora/Lot.java @@ -11,8 +11,8 @@ import java.time.LocalDateTime; */ @With record Lot( - int saleId, - int lotId, + long saleId, + long lotId, String title, String description, String manufacturer, diff --git a/src/main/java/auctiora/ScraperDataAdapter.java b/src/main/java/auctiora/ScraperDataAdapter.java index 452861e..34e7fe8 100644 --- a/src/main/java/auctiora/ScraperDataAdapter.java +++ b/src/main/java/auctiora/ScraperDataAdapter.java @@ -71,14 +71,27 @@ public class ScraperDataAdapter { ); } - public static int extractNumericId(String id) { - if (id == null || id.isBlank()) return 0; + public static long extractNumericId(String id) { + if (id == null || id.isBlank()) return 0L; // Remove the type prefix (e.g., "A7-") first, then extract all digits // "A7-39813" โ†’ "39813" โ†’ 39813 // "A1-28505-5" โ†’ "28505-5" โ†’ "285055" var afterPrefix = id.indexOf('-') >= 0 ? id.substring(id.indexOf('-') + 1) : id; var digits = afterPrefix.replaceAll("\\D+", ""); - return digits.isEmpty() ? 0 : Integer.parseInt(digits); + if (digits.isEmpty()) return 0L; + + // Check if number is too large for long (> 19 digits or value > Long.MAX_VALUE) + if (digits.length() > 19) { + log.debug("ID too large for long, skipping: {}", id); + return 0L; + } + + try { + return Long.parseLong(digits); + } catch (NumberFormatException e) { + log.debug("Invalid numeric ID, skipping: {}", id); + return 0L; + } } private static String extractTypePrefix(String id) { @@ -115,12 +128,21 @@ public class ScraperDataAdapter { private static LocalDateTime parseTimestamp(String ts) { if (ts == null || ts.isBlank()) return null; + + // Filter out known invalid values + String tsLower = ts.toLowerCase().trim(); + if (tsLower.equals("gap") || tsLower.equals("null") || tsLower.equals("n/a") || + tsLower.equals("unknown") || tsLower.equals("tbd") || tsLower.length() < 8) { + log.debug("Skipping invalid timestamp value: {}", ts); + return null; + } + for (var fmt : TIMESTAMP_FORMATS) { try { return LocalDateTime.parse(ts, fmt); } catch (DateTimeParseException ignored) { } } - log.info("Unable to parse timestamp: {}", ts); + log.debug("Unable to parse timestamp: {}", ts); return null; } diff --git a/src/main/java/auctiora/WorkflowOrchestrator.java b/src/main/java/auctiora/WorkflowOrchestrator.java index ebd266f..0458402 100644 --- a/src/main/java/auctiora/WorkflowOrchestrator.java +++ b/src/main/java/auctiora/WorkflowOrchestrator.java @@ -42,7 +42,7 @@ public class WorkflowOrchestrator { this.notifier = new NotificationService(notificationConfig); this.detector = new ObjectDetectionService(yoloCfg, yoloWeights, yoloClasses); - RateLimitedHttpClient httpClient = new RateLimitedHttpClient(); + var httpClient = new RateLimitedHttpClient(); this.imageProcessor = new ImageProcessingService(db, detector, httpClient); this.monitor = new TroostwijkMonitor(databasePath, notificationConfig, @@ -90,7 +90,7 @@ public class WorkflowOrchestrator { scheduler.scheduleAtFixedRate(() -> { try { log.info("๐Ÿ“ฅ [WORKFLOW 1] Importing scraper data..."); - long start = System.currentTimeMillis(); + var start = System.currentTimeMillis(); // Import auctions var auctions = db.importAuctionsFromScraper(); @@ -104,7 +104,7 @@ public class WorkflowOrchestrator { var images = db.getUnprocessedImagesFromScraper(); log.info(" โ†’ Found {} unprocessed images", images.size()); - long duration = System.currentTimeMillis() - start; + var duration = System.currentTimeMillis() - start; log.info(" โœ“ Scraper import completed in {}ms\n", duration); // Trigger notification if significant data imported @@ -133,7 +133,7 @@ public class WorkflowOrchestrator { scheduler.scheduleAtFixedRate(() -> { try { log.info("๐Ÿ–ผ๏ธ [WORKFLOW 2] Processing pending images..."); - long start = System.currentTimeMillis(); + var start = System.currentTimeMillis(); // Get unprocessed images var unprocessedImages = db.getUnprocessedImagesFromScraper(); @@ -145,17 +145,17 @@ public class WorkflowOrchestrator { log.info(" โ†’ Processing {} images", unprocessedImages.size()); - int processed = 0; - int detected = 0; + var processed = 0; + var detected = 0; for (var imageRecord : unprocessedImages) { try { // Download image - String filePath = imageProcessor.downloadImage( + var filePath = imageProcessor.downloadImage( imageRecord.url(), imageRecord.saleId(), imageRecord.lotId() - ); + ); if (filePath != null) { // Run object detection @@ -190,7 +190,7 @@ public class WorkflowOrchestrator { } } - long duration = System.currentTimeMillis() - start; + var duration = System.currentTimeMillis() - start; log.info(String.format(" โœ“ Processed %d images, detected objects in %d (%.1fs)\n", processed, detected, duration / 1000.0)); @@ -211,12 +211,12 @@ public class WorkflowOrchestrator { scheduler.scheduleAtFixedRate(() -> { try { log.info("๐Ÿ’ฐ [WORKFLOW 3] Monitoring bids..."); - long start = System.currentTimeMillis(); + var start = System.currentTimeMillis(); var activeLots = db.getActiveLots(); log.info(" โ†’ Checking {} active lots", activeLots.size()); - int bidChanges = 0; + var bidChanges = 0; for (var lot : activeLots) { // Note: In production, this would call Troostwijk API @@ -224,7 +224,7 @@ public class WorkflowOrchestrator { // The external scraper updates bids, we just notify } - long duration = System.currentTimeMillis() - start; + var duration = System.currentTimeMillis() - start; log.info(String.format(" โœ“ Bid monitoring completed in %dms\n", duration)); } catch (Exception e) { @@ -244,20 +244,20 @@ public class WorkflowOrchestrator { scheduler.scheduleAtFixedRate(() -> { try { log.info("โฐ [WORKFLOW 4] Checking closing times..."); - long start = System.currentTimeMillis(); + var start = System.currentTimeMillis(); var activeLots = db.getActiveLots(); - int alertsSent = 0; + var alertsSent = 0; for (var lot : activeLots) { if (lot.closingTime() == null) continue; - long minutesLeft = lot.minutesUntilClose(); + var minutesLeft = lot.minutesUntilClose(); // Alert for lots closing in 5 minutes if (minutesLeft <= 5 && minutesLeft > 0 && !lot.closingNotified()) { - String message = String.format("Kavel %d sluit binnen %d min.", - lot.lotId(), minutesLeft); + var message = String.format("Kavel %d sluit binnen %d min.", + lot.lotId(), minutesLeft); notifier.sendNotification(message, "Lot Closing Soon", 1); @@ -274,7 +274,7 @@ public class WorkflowOrchestrator { } } - long duration = System.currentTimeMillis() - start; + var duration = System.currentTimeMillis() - start; log.info(String.format(" โ†’ Sent %d closing alerts in %dms\n", alertsSent, duration)); @@ -312,7 +312,7 @@ public class WorkflowOrchestrator { // Step 4: Check closing times log.info("[4/4] Checking closing times..."); - int closingSoon = 0; + var closingSoon = 0; for (var lot : activeLots) { if (lot.closingTime() != null && lot.minutesUntilClose() < 30) { closingSoon++; @@ -399,15 +399,15 @@ public class WorkflowOrchestrator { try { var auctions = db.getAllAuctions(); - var lots = db.getAllLots(); - int images = db.getImageCount(); + var lots = db.getAllLots(); + var images = db.getImageCount(); log.info(" Auctions: {}", auctions.size()); log.info(" Lots: {}", lots.size()); log.info(" Images: {}", images); // Count closing soon - int closingSoon = 0; + var closingSoon = 0; for (var lot : lots) { if (lot.closingTime() != null && lot.minutesUntilClose() < 30) { closingSoon++; diff --git a/src/main/resources/META-INF/resources/index.html b/src/main/resources/META-INF/resources/index.html new file mode 100644 index 0000000..0746686 --- /dev/null +++ b/src/main/resources/META-INF/resources/index.html @@ -0,0 +1,224 @@ + + + + + + Scrape-UI 1 - Enterprise + + + + + +
+
+

Scrape-UI Enterprise

+

Powered by Quarkus + Modern Frontend

+
+
+ + +
+ + +
+

Build & Runtime Status

+
+
+ +
+

๐Ÿ“ฆ Maven Build

+
+
+ Group: + - +
+
+ Artifact: + - +
+
+ Version: + - +
+
+
+ + +
+

๐Ÿš€ Runtime

+
+
+ Status: + - +
+
+ Java: + - +
+
+ Platform: + - +
+
+
+
+ + +
+
+
+

Last Updated

+

-

+
+ +
+
+
+
+ + +
+

API Test

+ +
+
Click the button to test the API
+
+
+ + +
+
+

โšก Quarkus Backend

+

Fast startup, low memory footprint, optimized for containers

+
+
+

๐Ÿš€ REST API

+

RESTful endpoints with JSON responses

+
+
+

๐ŸŽจ Modern UI

+

Responsive design with Tailwind CSS

+
+
+
+ + + + diff --git a/src/main/resources/META-INF/resources/praetium.html b/src/main/resources/META-INF/resources/praetium.html new file mode 100644 index 0000000..37ee01f --- /dev/null +++ b/src/main/resources/META-INF/resources/praetium.html @@ -0,0 +1,572 @@ + + + + + + Auctiora - Monitoring Dashboard + + + + + + + + +
+
+
+
+

+ + Auctiora Monitoring Dashboard +

+

Real-time Auction Data Processing & Monitoring

+
+
+
+ + System Online +
+
Last updated: --:--
+
+
+
+
+ + +
+ + +
+
+
+
+
Auctions
+
--
+
+
+ +
+
+
+ +
+
+
+
Total Lots
+
--
+
+
+ +
+
+
+ +
+
+
+
Images
+
--
+
+
+ +
+
+
+ +
+
+
+
Active Lots
+
--
+
+
+ +
+
+
+ +
+
+
+
Closing Soon
+
--
+
+
+ +
+
+
+
+ + +
+
+

+ + Bidding Statistics +

+
+
+
Lots with Bids
+
--
+
+
+
Total Bid Value
+
--
+
+
+
Average Bid
+
--
+
+
+
+ +
+

+ + Rate Limiting +

+
+
+ Total Requests + -- +
+
+ Successful + -- +
+
+ Failed + -- +
+
+ Avg Duration + -- +
+
+
+
+ + +
+

+ + Workflow Controls +

+
+ + + + + + + +
+
+ + +
+ +
+

+ + Auctions by Country +

+
+
+ + +
+

+ + Lots by Category +

+
+
+
+ + +
+
+

+ + Lots Closing Soon (< 30 min) +

+ +
+
+ + + + + + + + + + + + + + + + +
Lot IDTitleCurrent BidClosing TimeMinutes LeftActions
Loading...
+
+
+ + +
+

+ + Activity Log +

+
+
Monitoring system started...
+
+
+
+ + +
+
+

+ + Auctiora - Auction Data Processing & Monitoring System +

+

+ Architecture: Quarkus + SQLite + REST API | Auto-refresh: 15 seconds +

+
+
+ + + + diff --git a/src/main/resources/resources/praetium.html b/src/main/resources/resources/praetium.html index 8a00cd0..37ee01f 100644 --- a/src/main/resources/resources/praetium.html +++ b/src/main/resources/resources/praetium.html @@ -3,13 +3,14 @@ - Troostwijk Auctions - Kavel Data Dashboard + Auctiora - Monitoring Dashboard + -
+

- - Troostwijk Auctions + + Auctiora Monitoring Dashboard

-

Kavel Data Extraction & Analysis Dashboard

+

Real-time Auction Data Processing & Monitoring

-
5
-
Total Kavels
+
+ + System Online +
+
Last updated: --:--
@@ -52,422 +67,506 @@
- -
-
-
-
- + + +
+
+
+
+
Auctions
+
--
-
-
5
-
Categories
+
+
- -
-
-
- + +
+
+
+
Total Lots
+
--
-
-
5
-
Locations
+
+
- -
-
-
- + +
+
+
+
Images
+
--
-
-
โ‚ฌ67,250
-
Total Value
+
+
- -
-
-
- + +
+
+
+
Active Lots
+
--
-
-
24
-
Avg Bids
+
+
+ +
+
+
+
Closing Soon
+
--
+
+
+ +
+
+
+
+ + +
+
+

+ + Bidding Statistics +

+
+
+
Lots with Bids
+
--
+
+
+
Total Bid Value
+
--
+
+
+
Average Bid
+
--
+
+
+
+ +
+

+ + Rate Limiting +

+
+
+ Total Requests + -- +
+
+ Successful + -- +
+
+ Failed + -- +
+
+ Avg Duration + -- +
+
+
+
+ + +
+

+ + Workflow Controls +

+
+ + + + + + + +
- +

- - Kavel Distribution by Category + + Auctions by Country

-
+
- - + +

- - Price Distribution + + Lots by Category

-
+
- +
-

- - Bidding Activity Analysis -

-
-
- - -

- - Kavel Details + + Lots Closing Soon (< 30 min)

-
- - -
+
-
- - - - - - - + + + + + + - - + + + +
KavelCategoryCurrent BidBidsLocationEnd DateActionsLot IDTitleCurrent BidClosing TimeMinutes LeftActions
Loading...
+ + +
+

+ + Activity Log +

+
+
Monitoring system started...
+
+
-