initial project setup

This commit is contained in:
glenn schrooyen
2025-09-11 22:08:12 +02:00
parent 8cc588dc92
commit 21e4972ab1
46 changed files with 2755 additions and 1 deletions

View File

@@ -0,0 +1,11 @@
package com.labfusion;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LabFusionApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(LabFusionApiGatewayApplication.class, args);
}
}

View File

@@ -0,0 +1,68 @@
package com.labfusion.controller;
import com.labfusion.model.Dashboard;
import com.labfusion.model.User;
import com.labfusion.service.DashboardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/dashboards")
@CrossOrigin(origins = "*")
public class DashboardController {
@Autowired
private DashboardService dashboardService;
@GetMapping
public ResponseEntity<List<Dashboard>> getDashboards(@AuthenticationPrincipal User user) {
List<Dashboard> dashboards = dashboardService.getDashboardsByUser(user);
return ResponseEntity.ok(dashboards);
}
@GetMapping("/{id}")
public ResponseEntity<Dashboard> getDashboard(@PathVariable Long id, @AuthenticationPrincipal User user) {
Optional<Dashboard> dashboard = dashboardService.getDashboardById(id);
if (dashboard.isPresent()) {
// Check if user owns the dashboard
if (dashboard.get().getUser().getId().equals(user.getId())) {
return ResponseEntity.ok(dashboard.get());
} else {
return ResponseEntity.forbidden().build();
}
}
return ResponseEntity.notFound().build();
}
@PostMapping
public ResponseEntity<Dashboard> createDashboard(@RequestBody Dashboard dashboard, @AuthenticationPrincipal User user) {
dashboard.setUser(user);
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard);
return ResponseEntity.ok(savedDashboard);
}
@PutMapping("/{id}")
public ResponseEntity<Dashboard> updateDashboard(@PathVariable Long id, @RequestBody Dashboard dashboard, @AuthenticationPrincipal User user) {
try {
Dashboard updatedDashboard = dashboardService.updateDashboard(id, dashboard);
return ResponseEntity.ok(updatedDashboard);
} catch (RuntimeException e) {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteDashboard(@PathVariable Long id, @AuthenticationPrincipal User user) {
Optional<Dashboard> dashboard = dashboardService.getDashboardById(id);
if (dashboard.isPresent() && dashboard.get().getUser().getId().equals(user.getId())) {
dashboardService.deleteDashboard(id);
return ResponseEntity.ok().build();
}
return ResponseEntity.forbidden().build();
}
}

View File

@@ -0,0 +1,71 @@
package com.labfusion.controller;
import com.labfusion.model.DeviceState;
import com.labfusion.model.Event;
import com.labfusion.repository.DeviceStateRepository;
import com.labfusion.repository.EventRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
@RestController
@RequestMapping("/api/system")
@CrossOrigin(origins = "*")
public class SystemController {
@Autowired
private EventRepository eventRepository;
@Autowired
private DeviceStateRepository deviceStateRepository;
@GetMapping("/events")
public ResponseEntity<List<Event>> getEvents(
@RequestParam(required = false) String service,
@RequestParam(required = false) String eventType,
@RequestParam(required = false) Integer hours) {
List<Event> events;
if (service != null && hours != null) {
LocalDateTime since = LocalDateTime.now().minusHours(hours);
events = eventRepository.findRecentEventsByService(service, since);
} else if (service != null) {
events = eventRepository.findByService(service);
} else if (eventType != null) {
events = eventRepository.findByEventType(eventType);
} else {
events = eventRepository.findAll();
}
return ResponseEntity.ok(events);
}
@GetMapping("/device-states")
public ResponseEntity<List<DeviceState>> getDeviceStates(
@RequestParam(required = false) String entityId,
@RequestParam(required = false) String service) {
List<DeviceState> states;
if (entityId != null) {
states = deviceStateRepository.findByEntityId(entityId);
} else if (service != null) {
states = deviceStateRepository.findByService(service);
} else {
states = deviceStateRepository.findAll();
}
return ResponseEntity.ok(states);
}
@GetMapping("/metrics")
public ResponseEntity<Object> getSystemMetrics() {
// This would integrate with actual system monitoring
// For now, return a placeholder response
return ResponseEntity.ok().body("System metrics endpoint - to be implemented");
}
}

View File

@@ -0,0 +1,81 @@
package com.labfusion.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "dashboards")
public class Dashboard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(columnDefinition = "TEXT")
private String description;
@Column(columnDefinition = "JSONB")
private String layout;
@OneToMany(mappedBy = "dashboard", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Widget> widgets;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
// Constructors
public Dashboard() {}
public Dashboard(String name, String description, String layout, User user) {
this.name = name;
this.description = description;
this.layout = layout;
this.user = user;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getLayout() { return layout; }
public void setLayout(String layout) { this.layout = layout; }
public List<Widget> getWidgets() { return widgets; }
public void setWidgets(List<Widget> widgets) { this.widgets = widgets; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

View File

@@ -0,0 +1,64 @@
package com.labfusion.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "device_states")
public class DeviceState {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "timestamp", nullable = false)
private LocalDateTime timestamp;
@Column(name = "entity_id", nullable = false)
private String entityId;
@Column(name = "value", columnDefinition = "TEXT")
private String value;
@Column(name = "service", nullable = false)
private String service;
@Column(name = "created_at")
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
if (timestamp == null) {
timestamp = LocalDateTime.now();
}
}
// Constructors
public DeviceState() {}
public DeviceState(String entityId, String value, String service) {
this.entityId = entityId;
this.value = value;
this.service = service;
this.timestamp = LocalDateTime.now();
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
public String getEntityId() { return entityId; }
public void setEntityId(String entityId) { this.entityId = entityId; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
public String getService() { return service; }
public void setService(String service) { this.service = service; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}

View File

@@ -0,0 +1,64 @@
package com.labfusion.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "events")
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "timestamp", nullable = false)
private LocalDateTime timestamp;
@Column(name = "service", nullable = false)
private String service;
@Column(name = "event_type", nullable = false)
private String eventType;
@Column(columnDefinition = "JSONB")
private String metadata;
@Column(name = "created_at")
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
if (timestamp == null) {
timestamp = LocalDateTime.now();
}
}
// Constructors
public Event() {}
public Event(String service, String eventType, String metadata) {
this.service = service;
this.eventType = eventType;
this.metadata = metadata;
this.timestamp = LocalDateTime.now();
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
public String getService() { return service; }
public void setService(String service) { this.service = service; }
public String getEventType() { return eventType; }
public void setEventType(String eventType) { this.eventType = eventType; }
public String getMetadata() { return metadata; }
public void setMetadata(String metadata) { this.metadata = metadata; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}

View File

@@ -0,0 +1,7 @@
package com.labfusion.model;
public enum Role {
ADMIN,
USER,
VIEWER
}

View File

@@ -0,0 +1,75 @@
package com.labfusion.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.Set;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
@Column(unique = true, nullable = false)
private String email;
@ElementCollection(fetch = FetchType.EAGER)
@Enumerated(EnumType.STRING)
private Set<Role> roles;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
// Constructors
public User() {}
public User(String username, String password, String email, Set<Role> roles) {
this.username = username;
this.password = password;
this.email = email;
this.roles = roles;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Set<Role> getRoles() { return roles; }
public void setRoles(Set<Role> roles) { this.roles = roles; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

View File

@@ -0,0 +1,75 @@
package com.labfusion.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "widgets")
public class Widget {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private WidgetType type;
@Column(columnDefinition = "JSONB")
private String config;
@Column(name = "service_binding")
private String serviceBinding;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "dashboard_id", nullable = false)
private Dashboard dashboard;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
// Constructors
public Widget() {}
public Widget(WidgetType type, String config, String serviceBinding, Dashboard dashboard) {
this.type = type;
this.config = config;
this.serviceBinding = serviceBinding;
this.dashboard = dashboard;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public WidgetType getType() { return type; }
public void setType(WidgetType type) { this.type = type; }
public String getConfig() { return config; }
public void setConfig(String config) { this.config = config; }
public String getServiceBinding() { return serviceBinding; }
public void setServiceBinding(String serviceBinding) { this.serviceBinding = serviceBinding; }
public Dashboard getDashboard() { return dashboard; }
public void setDashboard(Dashboard dashboard) { this.dashboard = dashboard; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

View File

@@ -0,0 +1,11 @@
package com.labfusion.model;
public enum WidgetType {
CHART,
TABLE,
CARD,
LOGS,
METRIC,
STATUS,
TIMELINE
}

View File

@@ -0,0 +1,14 @@
package com.labfusion.repository;
import com.labfusion.model.Dashboard;
import com.labfusion.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface DashboardRepository extends JpaRepository<Dashboard, Long> {
List<Dashboard> findByUser(User user);
List<Dashboard> findByUserId(Long userId);
}

View File

@@ -0,0 +1,20 @@
package com.labfusion.repository;
import com.labfusion.model.DeviceState;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
@Repository
public interface DeviceStateRepository extends JpaRepository<DeviceState, Long> {
List<DeviceState> findByEntityId(String entityId);
List<DeviceState> findByService(String service);
List<DeviceState> findByTimestampBetween(LocalDateTime start, LocalDateTime end);
@Query("SELECT ds FROM DeviceState ds WHERE ds.entityId = :entityId ORDER BY ds.timestamp DESC")
List<DeviceState> findLatestStatesByEntityId(@Param("entityId") String entityId);
}

View File

@@ -0,0 +1,20 @@
package com.labfusion.repository;
import com.labfusion.model.Event;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
@Repository
public interface EventRepository extends JpaRepository<Event, Long> {
List<Event> findByService(String service);
List<Event> findByEventType(String eventType);
List<Event> findByTimestampBetween(LocalDateTime start, LocalDateTime end);
@Query("SELECT e FROM Event e WHERE e.service = :service AND e.timestamp >= :since ORDER BY e.timestamp DESC")
List<Event> findRecentEventsByService(@Param("service") String service, @Param("since") LocalDateTime since);
}

View File

@@ -0,0 +1,15 @@
package com.labfusion.repository;
import com.labfusion.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
boolean existsByUsername(String username);
boolean existsByEmail(String email);
}

View File

@@ -0,0 +1,48 @@
package com.labfusion.service;
import com.labfusion.model.Dashboard;
import com.labfusion.model.User;
import com.labfusion.repository.DashboardRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class DashboardService {
@Autowired
private DashboardRepository dashboardRepository;
public List<Dashboard> getDashboardsByUser(User user) {
return dashboardRepository.findByUser(user);
}
public List<Dashboard> getDashboardsByUserId(Long userId) {
return dashboardRepository.findByUserId(userId);
}
public Optional<Dashboard> getDashboardById(Long id) {
return dashboardRepository.findById(id);
}
public Dashboard saveDashboard(Dashboard dashboard) {
return dashboardRepository.save(dashboard);
}
public void deleteDashboard(Long id) {
dashboardRepository.deleteById(id);
}
public Dashboard updateDashboard(Long id, Dashboard updatedDashboard) {
return dashboardRepository.findById(id)
.map(dashboard -> {
dashboard.setName(updatedDashboard.getName());
dashboard.setDescription(updatedDashboard.getDescription());
dashboard.setLayout(updatedDashboard.getLayout());
return dashboardRepository.save(dashboard);
})
.orElseThrow(() -> new RuntimeException("Dashboard not found with id: " + id));
}
}

View File

@@ -0,0 +1,46 @@
spring:
application:
name: labfusion-api-gateway
datasource:
url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/labfusion}
username: ${SPRING_DATASOURCE_USERNAME:labfusion}
password: ${SPRING_DATASOURCE_PASSWORD:labfusion_password}
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
timeout: 2000ms
security:
user:
name: admin
password: admin
server:
port: ${API_GATEWAY_PORT:8080}
logging:
level:
com.labfusion: DEBUG
org.springframework.security: DEBUG
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always