turash/bugulma/backend/internal/handler/geospatial_handler.go
Damir Mukimov 000eab4740
Major repository reorganization and missing backend endpoints implementation
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools

Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
  * GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
  * GET /api/v1/users/me/organizations - User organizations
  * POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue

API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules

Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
2025-11-25 06:01:16 +01:00

107 lines
3.0 KiB
Go

package handler
import (
"bugulma/backend/internal/service"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
)
// GeospatialHandler handles geospatial queries
type GeospatialHandler struct {
service *service.GeospatialService
}
// NewGeospatialHandler creates a new geospatial handler
func NewGeospatialHandler(service *service.GeospatialService) *GeospatialHandler {
return &GeospatialHandler{service: service}
}
// FindNearbySites finds sites within a radius
// @Summary Find nearby sites
// @Tags geospatial
// @Produce json
// @Param lat query float64 true "Latitude"
// @Param lng query float64 true "Longitude"
// @Param radius query float64 false "Radius in kilometers" default(5.0)
// @Param limit query int false "Maximum results" default(50)
// @Success 200 {array} service.SpatialResult
// @Router /api/geospatial/nearby-sites [get]
func (h *GeospatialHandler) FindNearbySites(c *gin.Context) {
latStr := c.Query("lat")
lngStr := c.Query("lng")
radiusStr := c.DefaultQuery("radius", "5.0")
limitStr := c.DefaultQuery("limit", "50")
lat, err := strconv.ParseFloat(latStr, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid latitude"})
return
}
lng, err := strconv.ParseFloat(lngStr, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid longitude"})
return
}
radius, _ := strconv.ParseFloat(radiusStr, 64)
limit, _ := strconv.Atoi(limitStr)
query := service.SpatialQuery{
CenterLat: lat,
CenterLng: lng,
RadiusKm: radius,
MaxResults: limit,
}
results, err := h.service.FindNearbySites(c.Request.Context(), query)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, results)
}
// GetSpatialStatistics returns spatial statistics
// @Summary Get spatial statistics
// @Tags geospatial
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /api/geospatial/statistics [get]
func (h *GeospatialHandler) GetSpatialStatistics(c *gin.Context) {
stats, err := h.service.GetSpatialStatistics(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, stats)
}
// GetSpatialClusters finds spatial clusters of sites
// @Summary Get spatial clusters
// @Tags geospatial
// @Produce json
// @Param min_points query int false "Minimum points per cluster" default(3)
// @Param radius_km query float64 false "Cluster radius in km" default(1.0)
// @Success 200 {array} service.SpatialCluster
// @Router /api/geospatial/clusters [get]
func (h *GeospatialHandler) GetSpatialClusters(c *gin.Context) {
minPointsStr := c.DefaultQuery("min_points", "3")
radiusStr := c.DefaultQuery("radius_km", "1.0")
minPoints, _ := strconv.Atoi(minPointsStr)
radius, _ := strconv.ParseFloat(radiusStr, 64)
clusters, err := h.service.FindSpatialClusters(c.Request.Context(), minPoints, radius)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, clusters)
}