refactor: remove dead code (api_manager.go, unused templates)
CLN-01: Deleted archived api_manager.go (~789 LOC, build-tag ignore) and dev-environment/templates/ (~806 LOC, never used by generator).
This commit is contained in:
parent
763aea15cb
commit
834fa1f979
10 changed files with 0 additions and 1596 deletions
|
|
@ -150,7 +150,6 @@ ci_cd:
|
|||
tools:
|
||||
generators:
|
||||
enabled: true
|
||||
templates_path: "dev-environment/templates"
|
||||
|
||||
validators:
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/gin-gonic/gin"
|
||||
"veza-backend-api/internal/types"
|
||||
"veza-backend-api/internal/models"
|
||||
)
|
||||
|
||||
// {{HANDLER_NAME}}Handlers handles HTTP requests for {{DOMAIN}}
|
||||
type {{HANDLER_NAME}}Handlers struct {
|
||||
{{SERVICE_LOWER}}Service types.{{SERVICE_INTERFACE}}
|
||||
}
|
||||
|
||||
// New{{HANDLER_NAME}}Handlers creates a new {{HANDLER_NAME}}Handlers instance
|
||||
func New{{HANDLER_NAME}}Handlers(
|
||||
{{SERVICE_LOWER}}Service types.{{SERVICE_INTERFACE}},
|
||||
) *{{HANDLER_NAME}}Handlers {
|
||||
return &{{HANDLER_NAME}}Handlers{
|
||||
{{SERVICE_LOWER}}Service: {{SERVICE_LOWER}}Service,
|
||||
}
|
||||
}
|
||||
|
||||
// Create{{ENTITY}} handles POST /api/v1/{{RESOURCE_PATH}}
|
||||
func (h *{{HANDLER_NAME}}Handlers) Create{{ENTITY}}(c *gin.Context) {
|
||||
var req Create{{ENTITY}}Request
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "invalid request",
|
||||
"details": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
{{ENTITY_LOWER}}, err := h.{{SERVICE_LOWER}}Service.Create{{ENTITY}}(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
handleError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{
|
||||
"data": {{ENTITY_LOWER}},
|
||||
})
|
||||
}
|
||||
|
||||
// Get{{ENTITY}} handles GET /api/v1/{{RESOURCE_PATH}}/:id
|
||||
func (h *{{HANDLER_NAME}}Handlers) Get{{ENTITY}}(c *gin.Context) {
|
||||
idParam := c.Param("id")
|
||||
id, err := uuid.Parse(idParam)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "invalid id format",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
{{ENTITY_LOWER}}, err := h.{{SERVICE_LOWER}}Service.Get{{ENTITY}}ByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
handleError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": {{ENTITY_LOWER}},
|
||||
})
|
||||
}
|
||||
|
||||
// handleError handles errors in a consistent way
|
||||
func handleError(c *gin.Context, err error) {
|
||||
// TODO: Implement error handling logic
|
||||
// Check error type and return appropriate status code
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "internal server error",
|
||||
})
|
||||
}
|
||||
|
||||
// Create{{ENTITY}}Request represents the request body for creating a {{ENTITY}}
|
||||
type Create{{ENTITY}}Request struct {
|
||||
// TODO: Add request fields with JSON tags
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"veza-backend-api/internal/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// {{REPOSITORY_NAME}}Repository implements persistence for {{ENTITY}}
|
||||
type {{REPOSITORY_NAME}}Repository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// New{{REPOSITORY_NAME}}Repository creates a new {{REPOSITORY_NAME}}Repository instance
|
||||
func New{{REPOSITORY_NAME}}Repository(db *gorm.DB) *{{REPOSITORY_NAME}}Repository {
|
||||
return &{{REPOSITORY_NAME}}Repository{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates a new {{ENTITY}} in the database
|
||||
func (r *{{REPOSITORY_NAME}}Repository) Create(
|
||||
ctx context.Context,
|
||||
{{ENTITY_LOWER}} *models.{{ENTITY}},
|
||||
) error {
|
||||
if err := r.db.WithContext(ctx).Create({{ENTITY_LOWER}}).Error; err != nil {
|
||||
return fmt.Errorf("failed to create {{ENTITY_LOWER}}: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindByID finds a {{ENTITY}} by ID
|
||||
func (r *{{REPOSITORY_NAME}}Repository) FindByID(
|
||||
ctx context.Context,
|
||||
id uuid.UUID,
|
||||
) (*models.{{ENTITY}}, error) {
|
||||
var {{ENTITY_LOWER}} models.{{ENTITY}}
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("id = ?", id).
|
||||
First(&{{ENTITY_LOWER}}).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, types.ErrNotFound("{{ENTITY_LOWER}} not found")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to find {{ENTITY_LOWER}}: %w", err)
|
||||
}
|
||||
return &{{ENTITY_LOWER}}, nil
|
||||
}
|
||||
|
||||
// Update updates an existing {{ENTITY}}
|
||||
func (r *{{REPOSITORY_NAME}}Repository) Update(
|
||||
ctx context.Context,
|
||||
{{ENTITY_LOWER}} *models.{{ENTITY}},
|
||||
) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Save({{ENTITY_LOWER}}).Error; err != nil {
|
||||
return fmt.Errorf("failed to update {{ENTITY_LOWER}}: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes a {{ENTITY}} by ID
|
||||
func (r *{{REPOSITORY_NAME}}Repository) Delete(
|
||||
ctx context.Context,
|
||||
id uuid.UUID,
|
||||
) error {
|
||||
if err := r.db.WithContext(ctx).
|
||||
Delete(&models.{{ENTITY}}{}, "id = ?", id).Error; err != nil {
|
||||
return fmt.Errorf("failed to delete {{ENTITY_LOWER}}: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"veza-backend-api/internal/types"
|
||||
"veza-backend-api/internal/models"
|
||||
)
|
||||
|
||||
// {{SERVICE_NAME}}Service provides business logic for {{DOMAIN}}
|
||||
type {{SERVICE_NAME}}Service struct {
|
||||
repo types.{{REPOSITORY_INTERFACE}}
|
||||
logger types.Logger
|
||||
}
|
||||
|
||||
// New{{SERVICE_NAME}}Service creates a new {{SERVICE_NAME}}Service instance
|
||||
func New{{SERVICE_NAME}}Service(
|
||||
repo types.{{REPOSITORY_INTERFACE}},
|
||||
logger types.Logger,
|
||||
) *{{SERVICE_NAME}}Service {
|
||||
return &{{SERVICE_NAME}}Service{
|
||||
repo: repo,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create{{ENTITY}} creates a new {{ENTITY}}
|
||||
func (s *{{SERVICE_NAME}}Service) Create{{ENTITY}}(
|
||||
ctx context.Context,
|
||||
req *Create{{ENTITY}}Request,
|
||||
) (*models.{{ENTITY}}, error) {
|
||||
// Validation
|
||||
if err := s.validateCreateRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Business logic
|
||||
{{ENTITY_LOWER}} := &models.{{ENTITY}}{
|
||||
// TODO: Map request fields to model
|
||||
}
|
||||
|
||||
// Persistence
|
||||
if err := s.repo.Create(ctx, {{ENTITY_LOWER}}); err != nil {
|
||||
return nil, fmt.Errorf("failed to create {{ENTITY_LOWER}}: %w", err)
|
||||
}
|
||||
|
||||
s.logger.Info("{{ENTITY_LOWER}} created", "id", {{ENTITY_LOWER}}.ID)
|
||||
|
||||
return {{ENTITY_LOWER}}, nil
|
||||
}
|
||||
|
||||
// Get{{ENTITY}}ByID retrieves a {{ENTITY}} by ID
|
||||
func (s *{{SERVICE_NAME}}Service) Get{{ENTITY}}ByID(
|
||||
ctx context.Context,
|
||||
id uuid.UUID,
|
||||
) (*models.{{ENTITY}}, error) {
|
||||
{{ENTITY_LOWER}}, err := s.repo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get {{ENTITY_LOWER}}: %w", err)
|
||||
}
|
||||
|
||||
return {{ENTITY_LOWER}}, nil
|
||||
}
|
||||
|
||||
// validateCreateRequest validates the create request
|
||||
func (s *{{SERVICE_NAME}}Service) validateCreateRequest(req *Create{{ENTITY}}Request) error {
|
||||
// TODO: Add validation logic
|
||||
if req == nil {
|
||||
return types.ErrValidation("request is required")
|
||||
}
|
||||
|
||||
// Example validation
|
||||
// if req.Field == "" {
|
||||
// return types.ErrValidation("field is required")
|
||||
// }
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create{{ENTITY}}Request represents a request to create a {{ENTITY}}
|
||||
type Create{{ENTITY}}Request struct {
|
||||
// TODO: Add request fields
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
import type { {{ENTITY}} } from '@/types';
|
||||
import { use{{ENTITY}} } from '@/hooks/use{{ENTITY}}';
|
||||
import { Spinner } from '@/components/ui/Spinner';
|
||||
import { ErrorMessage } from '@/components/ui/ErrorMessage';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface {{COMPONENT_NAME}}Props {
|
||||
{{ENTITY_LOWER}}Id: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* {{COMPONENT_NAME}} component
|
||||
*
|
||||
* @description Displays {{ENTITY_LOWER}} information
|
||||
* @example
|
||||
* ```tsx
|
||||
* <{{COMPONENT_NAME}} {{ENTITY_LOWER}}Id="123" />
|
||||
* ```
|
||||
*/
|
||||
export const {{COMPONENT_NAME}}: React.FC<{{COMPONENT_NAME}}Props> = ({
|
||||
{{ENTITY_LOWER}}Id,
|
||||
className,
|
||||
}) => {
|
||||
// Custom hook handles business logic
|
||||
const { data: {{ENTITY_LOWER}}, isLoading, error } = use{{ENTITY}}({{ENTITY_LOWER}}Id);
|
||||
|
||||
// Loading state
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={cn('flex items-center justify-center p-4', className)}>
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Error state
|
||||
if (error) {
|
||||
return (
|
||||
<div className={cn('p-4', className)}>
|
||||
<ErrorMessage error={error} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Not found state
|
||||
if (!{{ENTITY_LOWER}}) {
|
||||
return (
|
||||
<div className={cn('p-4', className)}>
|
||||
<p>{{ENTITY}} not found</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Success state - render component
|
||||
return (
|
||||
<div className={cn('p-4', className)}>
|
||||
{/* TODO: Add component content */}
|
||||
<h2>{/* {{ENTITY_LOWER}}.field */}</h2>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { {{ENTITY_LOWER}}Service } from '@/services/{{ENTITY_LOWER}}';
|
||||
import type { {{ENTITY}}, Create{{ENTITY}}Request } from '@/types';
|
||||
|
||||
/**
|
||||
* Hook to fetch a {{ENTITY_LOWER}} by ID
|
||||
*
|
||||
* @param {{ENTITY_LOWER}}Id - The ID of the {{ENTITY_LOWER}} to fetch
|
||||
* @returns Query result with {{ENTITY_LOWER}} data
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const { data: {{ENTITY_LOWER}}, isLoading, error } = use{{ENTITY}}('123');
|
||||
* ```
|
||||
*/
|
||||
export function use{{ENTITY}}({{ENTITY_LOWER}}Id: string) {
|
||||
return useQuery({
|
||||
queryKey: ['{{ENTITY_LOWER}}', {{ENTITY_LOWER}}Id],
|
||||
queryFn: () => {{ENTITY_LOWER}}Service.get{{ENTITY}}({{ENTITY_LOWER}}Id),
|
||||
enabled: !!{{ENTITY_LOWER}}Id,
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to create a new {{ENTITY_LOWER}}
|
||||
*
|
||||
* @returns Mutation function to create {{ENTITY_LOWER}}
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const create{{ENTITY}} = useCreate{{ENTITY}}();
|
||||
*
|
||||
* const handleCreate = async () => {
|
||||
* await create{{ENTITY}}.mutateAsync({
|
||||
* // ... request data
|
||||
* });
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export function useCreate{{ENTITY}}() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (request: Create{{ENTITY}}Request) =>
|
||||
{{ENTITY_LOWER}}Service.create{{ENTITY}}(request),
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch {{ENTITY_LOWER}} list
|
||||
queryClient.invalidateQueries({ queryKey: ['{{ENTITY_LOWER}}s'] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to update a {{ENTITY_LOWER}}
|
||||
*
|
||||
* @returns Mutation function to update {{ENTITY_LOWER}}
|
||||
*/
|
||||
export function useUpdate{{ENTITY}}() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({ id, data }: { id: string; data: Partial<{{ENTITY}}> }) =>
|
||||
{{ENTITY_LOWER}}Service.update{{ENTITY}}(id, data),
|
||||
onSuccess: (_, variables) => {
|
||||
// Invalidate specific {{ENTITY_LOWER}} and list
|
||||
queryClient.invalidateQueries({ queryKey: ['{{ENTITY_LOWER}}', variables.id] });
|
||||
queryClient.invalidateQueries({ queryKey: ['{{ENTITY_LOWER}}s'] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to delete a {{ENTITY_LOWER}}
|
||||
*
|
||||
* @returns Mutation function to delete {{ENTITY_LOWER}}
|
||||
*/
|
||||
export function useDelete{{ENTITY}}() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => {{ENTITY_LOWER}}Service.delete{{ENTITY}}(id),
|
||||
onSuccess: () => {
|
||||
// Invalidate {{ENTITY_LOWER}} list
|
||||
queryClient.invalidateQueries({ queryKey: ['{{ENTITY_LOWER}}s'] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// {{.ServiceName}}Service gère les fonctionnalités de {{.ServiceName}}
|
||||
type {{.ServiceName}}Service struct {
|
||||
logger *zap.Logger
|
||||
// Ajoutez vos dépendances ici
|
||||
}
|
||||
|
||||
// New{{.ServiceName}}Service crée une nouvelle instance du service
|
||||
func New{{.ServiceName}}Service(logger *zap.Logger) *{{.ServiceName}}Service {
|
||||
return &{{.ServiceName}}Service{
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Exemple de méthode - remplacez par vos méthodes
|
||||
func (s *{{.ServiceName}}Service) Process{{.ServiceName}}(ctx context.Context, input string) (string, error) {
|
||||
s.logger.Info("Processing {{.ServiceName}}", zap.String("input", input))
|
||||
|
||||
// Implémentation de votre logique métier
|
||||
result := fmt.Sprintf("Processed: %s", input)
|
||||
|
||||
s.logger.Info("{{.ServiceName}} processed successfully", zap.String("result", result))
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Health check pour le service
|
||||
func (s *{{.ServiceName}}Service) HealthCheck() error {
|
||||
s.logger.Debug("{{.ServiceName}} health check")
|
||||
// Implémentation du health check
|
||||
return nil
|
||||
}
|
||||
|
||||
// {{.ServiceName}}Handler gère les endpoints HTTP pour {{.ServiceName}}
|
||||
type {{.ServiceName}}Handler struct {
|
||||
service *{{.ServiceName}}Service
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// New{{.ServiceName}}Handler crée un nouveau handler
|
||||
func New{{.ServiceName}}Handler(service *{{.ServiceName}}Service, logger *zap.Logger) *{{.ServiceName}}Handler {
|
||||
return &{{.ServiceName}}Handler{
|
||||
service: service,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// SetupRoutes configure les routes pour ce service
|
||||
func (h *{{.ServiceName}}Handler) SetupRoutes(r *gin.RouterGroup) {
|
||||
r.GET("/{{.ServiceName}}", h.Get{{.ServiceName}})
|
||||
r.POST("/{{.ServiceName}}", h.Create{{.ServiceName}})
|
||||
r.PUT("/{{.ServiceName}}/:id", h.Update{{.ServiceName}})
|
||||
r.DELETE("/{{.ServiceName}}/:id", h.Delete{{.ServiceName}})
|
||||
}
|
||||
|
||||
// Get{{.ServiceName}} récupère les données de {{.ServiceName}}
|
||||
func (h *{{.ServiceName}}Handler) Get{{.ServiceName}}(c *gin.Context) {
|
||||
h.logger.Info("Get {{.ServiceName}} request")
|
||||
|
||||
// Implémentation
|
||||
c.JSON(200, gin.H{
|
||||
"message": "Get {{.ServiceName}} endpoint",
|
||||
"timestamp": time.Now(),
|
||||
})
|
||||
}
|
||||
|
||||
// Create{{.ServiceName}} crée une nouvelle entrée
|
||||
func (h *{{.ServiceName}}Handler) Create{{.ServiceName}}(c *gin.Context) {
|
||||
h.logger.Info("Create {{.ServiceName}} request")
|
||||
|
||||
// Implémentation
|
||||
c.JSON(201, gin.H{
|
||||
"message": "Create {{.ServiceName}} endpoint",
|
||||
"timestamp": time.Now(),
|
||||
})
|
||||
}
|
||||
|
||||
// Update{{.ServiceName}} met à jour une entrée existante
|
||||
func (h *{{.ServiceName}}Handler) Update{{.ServiceName}}(c *gin.Context) {
|
||||
h.logger.Info("Update {{.ServiceName}} request")
|
||||
|
||||
// Implémentation
|
||||
c.JSON(200, gin.H{
|
||||
"message": "Update {{.ServiceName}} endpoint",
|
||||
"timestamp": time.Now(),
|
||||
})
|
||||
}
|
||||
|
||||
// Delete{{.ServiceName}} supprime une entrée
|
||||
func (h *{{.ServiceName}}Handler) Delete{{.ServiceName}}(c *gin.Context) {
|
||||
h.logger.Info("Delete {{.ServiceName}} request")
|
||||
|
||||
// Implémentation
|
||||
c.JSON(200, gin.H{
|
||||
"message": "Delete {{.ServiceName}} endpoint",
|
||||
"timestamp": time.Now(),
|
||||
})
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
use anyhow::{Result, Context};
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// {{SERVICE_NAME}}Service provides business logic for {{DOMAIN}}
|
||||
pub struct {{SERVICE_NAME}}Service {
|
||||
pool: PgPool,
|
||||
}
|
||||
|
||||
impl {{SERVICE_NAME}}Service {
|
||||
/// Creates a new {{SERVICE_NAME}}Service instance
|
||||
pub fn new(pool: PgPool) -> Self {
|
||||
Self { pool }
|
||||
}
|
||||
|
||||
/// Creates a new {{ENTITY}}
|
||||
pub async fn create_{{ENTITY_LOWER}}(
|
||||
&self,
|
||||
request: Create{{ENTITY}}Request,
|
||||
) -> Result<{{ENTITY}}> {
|
||||
// Validation
|
||||
request.validate()?;
|
||||
|
||||
// Business logic
|
||||
let {{ENTITY_LOWER}} = sqlx::query_as!(
|
||||
{{ENTITY}},
|
||||
r#"
|
||||
INSERT INTO {{TABLE_NAME}} (id, /* TODO: add fields */)
|
||||
VALUES ($1, /* TODO: add values */)
|
||||
RETURNING id, /* TODO: add fields */
|
||||
"#,
|
||||
Uuid::new_v4(),
|
||||
// TODO: add request fields
|
||||
)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
.context("Failed to create {{ENTITY_LOWER}}")?;
|
||||
|
||||
Ok({{ENTITY_LOWER}})
|
||||
}
|
||||
|
||||
/// Gets a {{ENTITY}} by ID
|
||||
pub async fn get_{{ENTITY_LOWER}}_by_id(
|
||||
&self,
|
||||
id: Uuid,
|
||||
) -> Result<{{ENTITY}}> {
|
||||
let {{ENTITY_LOWER}} = sqlx::query_as!(
|
||||
{{ENTITY}},
|
||||
r#"
|
||||
SELECT id, /* TODO: add fields */
|
||||
FROM {{TABLE_NAME}}
|
||||
WHERE id = $1
|
||||
"#,
|
||||
id
|
||||
)
|
||||
.fetch_optional(&self.pool)
|
||||
.await
|
||||
.context("Failed to fetch {{ENTITY_LOWER}}")?
|
||||
.ok_or_else(|| anyhow::anyhow!("{{ENTITY}} not found"))?;
|
||||
|
||||
Ok({{ENTITY_LOWER}})
|
||||
}
|
||||
}
|
||||
|
||||
/// Request to create a {{ENTITY}}
|
||||
#[derive(Debug)]
|
||||
pub struct Create{{ENTITY}}Request {
|
||||
// TODO: Add request fields
|
||||
}
|
||||
|
||||
impl Create{{ENTITY}}Request {
|
||||
/// Validates the request
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
// TODO: Add validation logic
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// {{ENTITY}} model
|
||||
#[derive(Debug)]
|
||||
pub struct {{ENTITY}} {
|
||||
pub id: Uuid,
|
||||
// TODO: Add entity fields
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{info, warn, error, debug};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// {{.ServiceName}}Service gère les fonctionnalités de {{.ServiceName}}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct {{.ServiceName}}Service {
|
||||
// Ajoutez vos dépendances ici
|
||||
data: Arc<RwLock<HashMap<String, {{.ServiceName}}Data>>>,
|
||||
}
|
||||
|
||||
/// Données pour {{.ServiceName}}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct {{.ServiceName}}Data {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
pub updated_at: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
/// Erreurs pour {{.ServiceName}}
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum {{.ServiceName}}Error {
|
||||
#[error("{{.ServiceName}} not found")]
|
||||
NotFound,
|
||||
|
||||
#[error("Invalid input: {0}")]
|
||||
InvalidInput(String),
|
||||
|
||||
#[error("Database error: {0}")]
|
||||
DatabaseError(String),
|
||||
|
||||
#[error("Internal error: {0}")]
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
impl {{.ServiceName}}Service {
|
||||
/// Crée une nouvelle instance du service
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Arc::new(RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Traite les données de {{.ServiceName}}
|
||||
pub async fn process_{{.ServiceName}}(&self, input: String) -> Result<String, {{.ServiceName}}Error> {
|
||||
info!("Processing {{.ServiceName}} with input: {}", input);
|
||||
|
||||
// Implémentation de votre logique métier
|
||||
let result = format!("Processed: {}", input);
|
||||
|
||||
info!("{{.ServiceName}} processed successfully: {}", result);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Crée une nouvelle entrée
|
||||
pub async fn create(&self, name: String) -> Result<{{.ServiceName}}Data, {{.ServiceName}}Error> {
|
||||
info!("Creating {{.ServiceName}} with name: {}", name);
|
||||
|
||||
let id = Uuid::new_v4().to_string();
|
||||
let now = chrono::Utc::now();
|
||||
|
||||
let data = {{.ServiceName}}Data {
|
||||
id: id.clone(),
|
||||
name,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
};
|
||||
|
||||
let mut store = self.data.write().await;
|
||||
store.insert(id, data.clone());
|
||||
|
||||
info!("{{.ServiceName}} created successfully: {}", data.id);
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
/// Récupère une entrée par ID
|
||||
pub async fn get_by_id(&self, id: &str) -> Result<{{.ServiceName}}Data, {{.ServiceName}}Error> {
|
||||
debug!("Getting {{.ServiceName}} by ID: {}", id);
|
||||
|
||||
let store = self.data.read().await;
|
||||
store.get(id)
|
||||
.cloned()
|
||||
.ok_or({{.ServiceName}}Error::NotFound)
|
||||
}
|
||||
|
||||
/// Met à jour une entrée existante
|
||||
pub async fn update(&self, id: &str, name: String) -> Result<{{.ServiceName}}Data, {{.ServiceName}}Error> {
|
||||
info!("Updating {{.ServiceName}} with ID: {}", id);
|
||||
|
||||
let mut store = self.data.write().await;
|
||||
if let Some(data) = store.get_mut(id) {
|
||||
data.name = name;
|
||||
data.updated_at = chrono::Utc::now();
|
||||
info!("{{.ServiceName}} updated successfully: {}", id);
|
||||
Ok(data.clone())
|
||||
} else {
|
||||
Err({{.ServiceName}}Error::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/// Supprime une entrée
|
||||
pub async fn delete(&self, id: &str) -> Result<(), {{.ServiceName}}Error> {
|
||||
info!("Deleting {{.ServiceName}} with ID: {}", id);
|
||||
|
||||
let mut store = self.data.write().await;
|
||||
if store.remove(id).is_some() {
|
||||
info!("{{.ServiceName}} deleted successfully: {}", id);
|
||||
Ok(())
|
||||
} else {
|
||||
Err({{.ServiceName}}Error::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/// Liste toutes les entrées
|
||||
pub async fn list_all(&self) -> Result<Vec<{{.ServiceName}}Data>, {{.ServiceName}}Error> {
|
||||
debug!("Listing all {{.ServiceName}} entries");
|
||||
|
||||
let store = self.data.read().await;
|
||||
Ok(store.values().cloned().collect())
|
||||
}
|
||||
|
||||
/// Health check pour le service
|
||||
pub async fn health_check(&self) -> Result<(), {{.ServiceName}}Error> {
|
||||
debug!("{{.ServiceName}} health check");
|
||||
// Implémentation du health check
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_{{.ServiceName}}() {
|
||||
let service = {{.ServiceName}}Service::new();
|
||||
let result = service.create("Test {{.ServiceName}}".to_string()).await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
let data = result.unwrap();
|
||||
assert_eq!(data.name, "Test {{.ServiceName}}");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_{{.ServiceName}}_by_id() {
|
||||
let service = {{.ServiceName}}Service::new();
|
||||
let created = service.create("Test {{.ServiceName}}".to_string()).await.unwrap();
|
||||
|
||||
let result = service.get_by_id(&created.id).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let data = result.unwrap();
|
||||
assert_eq!(data.id, created.id);
|
||||
assert_eq!(data.name, "Test {{.ServiceName}}");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_update_{{.ServiceName}}() {
|
||||
let service = {{.ServiceName}}Service::new();
|
||||
let created = service.create("Test {{.ServiceName}}".to_string()).await.unwrap();
|
||||
|
||||
let result = service.update(&created.id, "Updated {{.ServiceName}}".to_string()).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let updated = result.unwrap();
|
||||
assert_eq!(updated.name, "Updated {{.ServiceName}}");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_{{.ServiceName}}() {
|
||||
let service = {{.ServiceName}}Service::new();
|
||||
let created = service.create("Test {{.ServiceName}}".to_string()).await.unwrap();
|
||||
|
||||
let result = service.delete(&created.id).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
let get_result = service.get_by_id(&created.id).await;
|
||||
assert!(get_result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_health_check() {
|
||||
let service = {{.ServiceName}}Service::new();
|
||||
let result = service.health_check().await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,789 +0,0 @@
|
|||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
// TODO: Réactiver api_manager.go après stabilisation du noyau et alignement des services (graphql, grpc, websocket, features)
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"veza-backend-api/internal/api/graphql"
|
||||
"veza-backend-api/internal/api/grpc"
|
||||
"veza-backend-api/internal/api/websocket"
|
||||
"veza-backend-api/internal/config"
|
||||
"veza-backend-api/internal/database"
|
||||
"veza-backend-api/internal/features"
|
||||
"veza-backend-api/internal/middleware"
|
||||
)
|
||||
|
||||
// APIManager manages all API protocols (REST, GraphQL, gRPC, WebSocket)
|
||||
type APIManager struct {
|
||||
config *config.Config
|
||||
db *database.DB
|
||||
|
||||
// API Servers
|
||||
restRouter *gin.Engine
|
||||
graphqlServer *graphql.GraphQLServer
|
||||
grpcServer *grpc.GRPCServer
|
||||
websocketManager *websocket.WebSocketManager
|
||||
|
||||
// Feature integration
|
||||
featureManager *features.FeatureManager
|
||||
|
||||
// HTTP Server
|
||||
httpServer *http.Server
|
||||
|
||||
isRunning bool
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// APIConfig contains configuration for all API protocols
|
||||
type APIConfig struct {
|
||||
REST RESTConfig `yaml:"rest"`
|
||||
GraphQL graphql.GraphQLConfig `yaml:"graphql"`
|
||||
GRPC grpc.GRPCConfig `yaml:"grpc"`
|
||||
WebSocket websocket.WebSocketConfig `yaml:"websocket"`
|
||||
Global GlobalAPIConfig `yaml:"global"`
|
||||
}
|
||||
|
||||
// RESTConfig contains REST API configuration
|
||||
type RESTConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Mode string `yaml:"mode"` // debug, release, test
|
||||
TrustedProxies []string `yaml:"trusted_proxies"`
|
||||
MaxMultipartMemory int64 `yaml:"max_multipart_memory"`
|
||||
}
|
||||
|
||||
// GlobalAPIConfig contains global API settings
|
||||
type GlobalAPIConfig struct {
|
||||
Timeout time.Duration `yaml:"timeout"`
|
||||
ReadTimeout time.Duration `yaml:"read_timeout"`
|
||||
WriteTimeout time.Duration `yaml:"write_timeout"`
|
||||
IdleTimeout time.Duration `yaml:"idle_timeout"`
|
||||
ShutdownTimeout time.Duration `yaml:"shutdown_timeout"`
|
||||
CORS CORSConfig `yaml:"cors"`
|
||||
RateLimit RateLimitConfig `yaml:"rate_limit"`
|
||||
Security SecurityConfig `yaml:"security"`
|
||||
}
|
||||
|
||||
// CORSConfig contains CORS configuration
|
||||
type CORSConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
AllowOrigins []string `yaml:"allow_origins"`
|
||||
AllowMethods []string `yaml:"allow_methods"`
|
||||
AllowHeaders []string `yaml:"allow_headers"`
|
||||
ExposeHeaders []string `yaml:"expose_headers"`
|
||||
AllowCredentials bool `yaml:"allow_credentials"`
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
|
||||
// RateLimitConfig contains rate limiting configuration
|
||||
type RateLimitConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
RPS int `yaml:"rps"`
|
||||
Burst int `yaml:"burst"`
|
||||
Window time.Duration `yaml:"window"`
|
||||
KeyFunc string `yaml:"key_func"` // ip, user, api_key
|
||||
SkipPaths []string `yaml:"skip_paths"`
|
||||
}
|
||||
|
||||
// SecurityConfig contains security configuration
|
||||
type SecurityConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
JWTSecret string `yaml:"jwt_secret"`
|
||||
APIKeyHeader string `yaml:"api_key_header"`
|
||||
AllowedUserAgents []string `yaml:"allowed_user_agents"`
|
||||
CSRFProtection bool `yaml:"csrf_protection"`
|
||||
HTTPSOnly bool `yaml:"https_only"`
|
||||
}
|
||||
|
||||
// NewAPIManager creates a new API manager instance
|
||||
func NewAPIManager(config *config.Config, db *database.DB, featureManager *features.FeatureManager) *APIManager {
|
||||
return &APIManager{
|
||||
config: config,
|
||||
db: db,
|
||||
featureManager: featureManager,
|
||||
isRunning: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize sets up all API protocols
|
||||
func (am *APIManager) Initialize(apiConfig APIConfig) error {
|
||||
am.mu.Lock()
|
||||
defer am.mu.Unlock()
|
||||
|
||||
// Initialize REST API (Gin)
|
||||
if err := am.initializeREST(apiConfig.REST, apiConfig.Global); err != nil {
|
||||
return fmt.Errorf("failed to initialize REST API: %w", err)
|
||||
}
|
||||
|
||||
// Initialize GraphQL server
|
||||
if apiConfig.GraphQL.Enabled {
|
||||
if err := am.initializeGraphQL(apiConfig.GraphQL); err != nil {
|
||||
return fmt.Errorf("failed to initialize GraphQL: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize gRPC server
|
||||
if apiConfig.GRPC.Enabled {
|
||||
if err := am.initializeGRPC(apiConfig.GRPC); err != nil {
|
||||
return fmt.Errorf("failed to initialize gRPC: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize WebSocket manager
|
||||
if apiConfig.WebSocket.Enabled {
|
||||
if err := am.initializeWebSocket(apiConfig.WebSocket); err != nil {
|
||||
return fmt.Errorf("failed to initialize WebSocket: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup HTTP server
|
||||
am.setupHTTPServer(apiConfig)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeREST sets up the REST API with Gin
|
||||
func (am *APIManager) initializeREST(restConfig RESTConfig, globalConfig GlobalAPIConfig) error {
|
||||
if !restConfig.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set Gin mode
|
||||
gin.SetMode(restConfig.Mode)
|
||||
|
||||
// Create Gin engine
|
||||
am.restRouter = gin.New()
|
||||
|
||||
// Setup global middleware
|
||||
am.setupGlobalMiddleware(globalConfig)
|
||||
|
||||
// Setup existing REST routes (from router.go)
|
||||
am.setupExistingRESTRoutes()
|
||||
|
||||
// Setup feature-specific routes
|
||||
am.setupFeatureRoutes()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeGraphQL sets up the GraphQL server
|
||||
func (am *APIManager) initializeGraphQL(graphqlConfig graphql.GraphQLConfig) error {
|
||||
am.graphqlServer = graphql.NewGraphQLServer(am.config, am.db, nil) // logger would be added
|
||||
am.graphqlServer.Configure(graphqlConfig)
|
||||
am.graphqlServer.SetupRoutes(am.restRouter, graphqlConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeGRPC sets up the gRPC server
|
||||
func (am *APIManager) initializeGRPC(grpcConfig grpc.GRPCConfig) error {
|
||||
am.grpcServer = grpc.NewGRPCServer(am.config, am.db)
|
||||
return am.grpcServer.Initialize(grpcConfig)
|
||||
}
|
||||
|
||||
// initializeWebSocket sets up the WebSocket manager
|
||||
func (am *APIManager) initializeWebSocket(wsConfig websocket.WebSocketConfig) error {
|
||||
am.websocketManager = websocket.NewWebSocketManager(am.config, am.db)
|
||||
if err := am.websocketManager.Initialize(wsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
am.websocketManager.SetupRoutes(am.restRouter, wsConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupGlobalMiddleware configures global middleware for REST API
|
||||
func (am *APIManager) setupGlobalMiddleware(globalConfig GlobalAPIConfig) {
|
||||
// Recovery middleware
|
||||
am.restRouter.Use(gin.Recovery())
|
||||
|
||||
// FIX #7: Logger middleware dupliqué supprimé
|
||||
// Le middleware.Logger() non structuré a été supprimé
|
||||
// Utiliser RequestLogger() à la place si ce fichier est réactivé
|
||||
// Note: Ce fichier est actuellement ignoré (//go:build ignore)
|
||||
// am.restRouter.Use(middleware.RequestLogger(logger))
|
||||
|
||||
// CORS middleware
|
||||
if globalConfig.CORS.Enabled {
|
||||
am.restRouter.Use(middleware.CORS())
|
||||
}
|
||||
|
||||
// Rate limiting middleware
|
||||
if globalConfig.RateLimit.Enabled {
|
||||
am.restRouter.Use(middleware.RateLimiter(globalConfig.RateLimit.RPS, globalConfig.RateLimit.Window))
|
||||
}
|
||||
|
||||
// Security middleware
|
||||
if globalConfig.Security.Enabled {
|
||||
am.restRouter.Use(middleware.Security())
|
||||
}
|
||||
|
||||
// Request ID middleware
|
||||
am.restRouter.Use(middleware.RequestID())
|
||||
|
||||
// Timeout middleware
|
||||
am.restRouter.Use(middleware.Timeout(globalConfig.Timeout))
|
||||
}
|
||||
|
||||
// setupExistingRESTRoutes sets up the existing REST routes
|
||||
func (am *APIManager) setupExistingRESTRoutes() {
|
||||
// Use the existing APIRouter setup
|
||||
SetupRoutes(am.restRouter, am.db, am.config)
|
||||
}
|
||||
|
||||
// setupFeatureRoutes sets up feature-specific API routes
|
||||
func (am *APIManager) setupFeatureRoutes() {
|
||||
if am.featureManager == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// API v2 group for new feature-based endpoints
|
||||
v2 := am.restRouter.Group("/api/v2")
|
||||
{
|
||||
// User domain features
|
||||
am.setupUserDomainRoutes(v2)
|
||||
|
||||
// Communication domain features
|
||||
am.setupCommunicationDomainRoutes(v2)
|
||||
|
||||
// Media domain features
|
||||
am.setupMediaDomainRoutes(v2)
|
||||
|
||||
// AI domain features
|
||||
am.setupAIDomainRoutes(v2)
|
||||
|
||||
// Analytics domain features
|
||||
am.setupAnalyticsDomainRoutes(v2)
|
||||
|
||||
// Integration domain features
|
||||
am.setupIntegrationDomainRoutes(v2)
|
||||
}
|
||||
|
||||
// Feature management endpoints
|
||||
admin := am.restRouter.Group("/api/admin")
|
||||
{
|
||||
admin.GET("/features", am.handleGetFeatures)
|
||||
admin.GET("/features/:id", am.handleGetFeature)
|
||||
admin.POST("/features/:id/start", am.handleStartFeature)
|
||||
admin.POST("/features/:id/stop", am.handleStopFeature)
|
||||
admin.GET("/features/health", am.handleFeaturesHealth)
|
||||
admin.GET("/features/metrics", am.handleFeaturesMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// setupUserDomainRoutes sets up user domain feature routes
|
||||
func (am *APIManager) setupUserDomainRoutes(router *gin.RouterGroup) {
|
||||
userGroup := router.Group("/user")
|
||||
{
|
||||
// User Profiles Feature endpoints
|
||||
userGroup.GET("/profiles/:id", am.handleGetUserProfile)
|
||||
userGroup.PUT("/profiles/:id", am.handleUpdateUserProfile)
|
||||
|
||||
// Social Graph Feature endpoints
|
||||
userGroup.POST("/follow/:id", am.handleFollowUser)
|
||||
userGroup.DELETE("/follow/:id", am.handleUnfollowUser)
|
||||
userGroup.GET("/followers/:id", am.handleGetFollowers)
|
||||
userGroup.GET("/following/:id", am.handleGetFollowing)
|
||||
|
||||
// Achievements endpoints
|
||||
userGroup.GET("/achievements/:id", am.handleGetAchievements)
|
||||
userGroup.GET("/leaderboard", am.handleGetLeaderboard)
|
||||
userGroup.POST("/achievements/:id/claim", am.handleClaimAchievement)
|
||||
|
||||
// User Verification Feature endpoints
|
||||
userGroup.POST("/verify", am.handleStartVerification)
|
||||
userGroup.GET("/verify/status", am.handleGetVerificationStatus)
|
||||
userGroup.GET("/trust-score/:id", am.handleGetTrustScore)
|
||||
}
|
||||
}
|
||||
|
||||
// setupCommunicationDomainRoutes sets up communication domain feature routes
|
||||
func (am *APIManager) setupCommunicationDomainRoutes(router *gin.RouterGroup) {
|
||||
commGroup := router.Group("/communication")
|
||||
{
|
||||
// Chat Rooms Feature endpoints
|
||||
commGroup.GET("/rooms", am.handleGetRooms)
|
||||
commGroup.POST("/rooms", am.handleCreateRoom)
|
||||
commGroup.GET("/rooms/:id", am.handleGetRoom)
|
||||
commGroup.POST("/rooms/:id/join", am.handleJoinRoom)
|
||||
commGroup.POST("/rooms/:id/leave", am.handleLeaveRoom)
|
||||
|
||||
// Voice Chat Feature endpoints
|
||||
commGroup.POST("/voice/start", am.handleStartVoiceChat)
|
||||
commGroup.POST("/voice/stop", am.handleStopVoiceChat)
|
||||
commGroup.GET("/voice/status", am.handleGetVoiceStatus)
|
||||
|
||||
// Video Streaming Feature endpoints
|
||||
commGroup.POST("/video/start", am.handleStartVideoStream)
|
||||
commGroup.POST("/video/stop", am.handleStopVideoStream)
|
||||
commGroup.GET("/video/streams", am.handleGetVideoStreams)
|
||||
}
|
||||
}
|
||||
|
||||
// setupMediaDomainRoutes sets up media domain feature routes
|
||||
func (am *APIManager) setupMediaDomainRoutes(router *gin.RouterGroup) {
|
||||
mediaGroup := router.Group("/media")
|
||||
{
|
||||
// Audio Streaming Feature endpoints
|
||||
mediaGroup.POST("/audio/upload", am.handleUploadAudio)
|
||||
mediaGroup.GET("/audio/:id/stream", am.handleStreamAudio)
|
||||
mediaGroup.GET("/audio/:id/metadata", am.handleGetAudioMetadata)
|
||||
|
||||
// Smart Playlists Feature endpoints
|
||||
mediaGroup.GET("/playlists/smart", am.handleGetSmartPlaylists)
|
||||
mediaGroup.POST("/playlists/smart", am.handleCreateSmartPlaylist)
|
||||
mediaGroup.GET("/playlists/smart/:id", am.handleGetSmartPlaylist)
|
||||
|
||||
// Content Discovery Feature endpoints
|
||||
mediaGroup.GET("/discover", am.handleDiscoverContent)
|
||||
mediaGroup.GET("/trending", am.handleGetTrending)
|
||||
mediaGroup.GET("/similar/:id", am.handleGetSimilarContent)
|
||||
}
|
||||
}
|
||||
|
||||
// setupAIDomainRoutes sets up AI domain feature routes
|
||||
func (am *APIManager) setupAIDomainRoutes(router *gin.RouterGroup) {
|
||||
aiGroup := router.Group("/ai")
|
||||
{
|
||||
// Smart Recommendations Feature endpoints
|
||||
aiGroup.GET("/recommendations", am.handleGetRecommendations)
|
||||
aiGroup.POST("/recommendations/feedback", am.handleRecommendationFeedback)
|
||||
|
||||
// Content Moderation Feature endpoints
|
||||
aiGroup.POST("/moderate", am.handleModerateContent)
|
||||
aiGroup.GET("/moderation/history", am.handleGetModerationHistory)
|
||||
|
||||
// Sentiment Analysis Feature endpoints
|
||||
aiGroup.POST("/sentiment", am.handleAnalyzeSentiment)
|
||||
aiGroup.GET("/sentiment/trends", am.handleGetSentimentTrends)
|
||||
}
|
||||
}
|
||||
|
||||
// setupAnalyticsDomainRoutes sets up analytics domain feature routes
|
||||
func (am *APIManager) setupAnalyticsDomainRoutes(router *gin.RouterGroup) {
|
||||
analyticsGroup := router.Group("/analytics")
|
||||
{
|
||||
// Realtime Dashboards Feature endpoints
|
||||
analyticsGroup.GET("/dashboard", am.handleGetDashboard)
|
||||
analyticsGroup.GET("/metrics/realtime", am.handleGetRealtimeMetrics)
|
||||
|
||||
// User Behavior Analytics Feature endpoints
|
||||
analyticsGroup.GET("/behavior/:id", am.handleGetUserBehavior)
|
||||
analyticsGroup.GET("/engagement", am.handleGetEngagementMetrics)
|
||||
|
||||
// Business Analytics Feature endpoints
|
||||
analyticsGroup.GET("/business/revenue", am.handleGetRevenueAnalytics)
|
||||
analyticsGroup.GET("/business/conversion", am.handleGetConversionMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// setupIntegrationDomainRoutes sets up integration domain feature routes
|
||||
func (am *APIManager) setupIntegrationDomainRoutes(router *gin.RouterGroup) {
|
||||
integrationGroup := router.Group("/integration")
|
||||
{
|
||||
// External API Gateway Feature endpoints
|
||||
integrationGroup.POST("/external/request", am.handleExternalAPIRequest)
|
||||
integrationGroup.GET("/external/status", am.handleGetExternalAPIStatus)
|
||||
|
||||
// Webhook System Feature endpoints
|
||||
integrationGroup.POST("/webhooks", am.handleCreateWebhook)
|
||||
integrationGroup.GET("/webhooks", am.handleGetWebhooks)
|
||||
integrationGroup.DELETE("/webhooks/:id", am.handleDeleteWebhook)
|
||||
|
||||
// Payment Gateways Feature endpoints
|
||||
integrationGroup.POST("/payments/process", am.handleProcessPayment)
|
||||
integrationGroup.GET("/payments/methods", am.handleGetPaymentMethods)
|
||||
integrationGroup.GET("/payments/history", am.handleGetPaymentHistory)
|
||||
}
|
||||
}
|
||||
|
||||
// setupHTTPServer configures the HTTP server
|
||||
func (am *APIManager) setupHTTPServer(apiConfig APIConfig) {
|
||||
addr := fmt.Sprintf("%s:%d", apiConfig.REST.Host, apiConfig.REST.Port)
|
||||
|
||||
am.httpServer = &http.Server{
|
||||
Addr: addr,
|
||||
Handler: am.restRouter,
|
||||
ReadTimeout: apiConfig.Global.ReadTimeout,
|
||||
WriteTimeout: apiConfig.Global.WriteTimeout,
|
||||
IdleTimeout: apiConfig.Global.IdleTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts all API servers
|
||||
func (am *APIManager) Start(ctx context.Context) error {
|
||||
am.mu.Lock()
|
||||
defer am.mu.Unlock()
|
||||
|
||||
if am.isRunning {
|
||||
return fmt.Errorf("API manager is already running")
|
||||
}
|
||||
|
||||
// Start gRPC server if enabled
|
||||
if am.grpcServer != nil {
|
||||
if err := am.grpcServer.Start(ctx); err != nil {
|
||||
return fmt.Errorf("failed to start gRPC server: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start WebSocket manager if enabled
|
||||
if am.websocketManager != nil {
|
||||
if err := am.websocketManager.Start(ctx); err != nil {
|
||||
return fmt.Errorf("failed to start WebSocket manager: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start HTTP server (REST + GraphQL)
|
||||
go func() {
|
||||
if err := am.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
// Handle error
|
||||
}
|
||||
}()
|
||||
|
||||
am.isRunning = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops all API servers
|
||||
func (am *APIManager) Stop(ctx context.Context) error {
|
||||
am.mu.Lock()
|
||||
defer am.mu.Unlock()
|
||||
|
||||
if !am.isRunning {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop HTTP server
|
||||
if am.httpServer != nil {
|
||||
if err := am.httpServer.Shutdown(ctx); err != nil {
|
||||
return fmt.Errorf("failed to stop HTTP server: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop WebSocket manager
|
||||
if am.websocketManager != nil {
|
||||
if err := am.websocketManager.Stop(ctx); err != nil {
|
||||
return fmt.Errorf("failed to stop WebSocket manager: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop gRPC server
|
||||
if am.grpcServer != nil {
|
||||
if err := am.grpcServer.Stop(ctx); err != nil {
|
||||
return fmt.Errorf("failed to stop gRPC server: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop GraphQL server
|
||||
if am.graphqlServer != nil {
|
||||
if err := am.graphqlServer.Shutdown(ctx); err != nil {
|
||||
return fmt.Errorf("failed to stop GraphQL server: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
am.isRunning = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsHealthy checks if all API servers are healthy
|
||||
func (am *APIManager) IsHealthy() bool {
|
||||
am.mu.RLock()
|
||||
defer am.mu.RUnlock()
|
||||
|
||||
if !am.isRunning {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check each server's health
|
||||
if am.grpcServer != nil && !am.grpcServer.IsHealthy() {
|
||||
return false
|
||||
}
|
||||
|
||||
if am.websocketManager != nil && !am.websocketManager.IsHealthy() {
|
||||
return false
|
||||
}
|
||||
|
||||
if am.graphqlServer != nil && !am.graphqlServer.IsHealthy() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetAPIStatus returns comprehensive API status
|
||||
func (am *APIManager) GetAPIStatus() map[string]interface{} {
|
||||
am.mu.RLock()
|
||||
defer am.mu.RUnlock()
|
||||
|
||||
status := map[string]interface{}{
|
||||
"status": "healthy",
|
||||
"running": am.isRunning,
|
||||
"timestamp": time.Now(),
|
||||
"apis": map[string]interface{}{},
|
||||
}
|
||||
|
||||
apis := status["apis"].(map[string]interface{})
|
||||
|
||||
// REST API status
|
||||
apis["rest"] = map[string]interface{}{
|
||||
"enabled": am.restRouter != nil,
|
||||
"status": "healthy",
|
||||
}
|
||||
|
||||
// GraphQL status
|
||||
if am.graphqlServer != nil {
|
||||
apis["graphql"] = am.graphqlServer.GetMetrics()
|
||||
} else {
|
||||
apis["graphql"] = map[string]interface{}{"enabled": false}
|
||||
}
|
||||
|
||||
// gRPC status
|
||||
if am.grpcServer != nil {
|
||||
apis["grpc"] = am.grpcServer.GetMetrics()
|
||||
} else {
|
||||
apis["grpc"] = map[string]interface{}{"enabled": false}
|
||||
}
|
||||
|
||||
// WebSocket status
|
||||
if am.websocketManager != nil {
|
||||
apis["websocket"] = am.websocketManager.GetMetrics()
|
||||
} else {
|
||||
apis["websocket"] = map[string]interface{}{"enabled": false}
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
// Feature management handlers
|
||||
func (am *APIManager) handleGetFeatures(c *gin.Context) {
|
||||
if am.featureManager == nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Feature manager not available"})
|
||||
return
|
||||
}
|
||||
|
||||
summary := am.featureManager.GetFeatureSummary()
|
||||
c.JSON(http.StatusOK, gin.H{"data": summary})
|
||||
}
|
||||
|
||||
func (am *APIManager) handleGetFeature(c *gin.Context) {
|
||||
featureID := c.Param("id")
|
||||
|
||||
if am.featureManager == nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Feature manager not available"})
|
||||
return
|
||||
}
|
||||
|
||||
feature, err := am.featureManager.GetFeature(c.Request.Context(), featureID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": map[string]interface{}{
|
||||
"id": feature.GetID(),
|
||||
"name": feature.GetName(),
|
||||
"version": feature.GetVersion(),
|
||||
"type": feature.GetType(),
|
||||
"domain": feature.GetDomain(),
|
||||
"healthy": feature.IsHealthy(),
|
||||
"status": feature.GetHealthStatus(),
|
||||
"metrics": feature.GetMetrics(),
|
||||
}})
|
||||
}
|
||||
|
||||
func (am *APIManager) handleStartFeature(c *gin.Context) {
|
||||
// TODO: Implement feature start
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
|
||||
func (am *APIManager) handleStopFeature(c *gin.Context) {
|
||||
// TODO: Implement feature stop
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
|
||||
func (am *APIManager) handleFeaturesHealth(c *gin.Context) {
|
||||
if am.featureManager == nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Feature manager not available"})
|
||||
return
|
||||
}
|
||||
|
||||
healthStatus := am.featureManager.GetFeatureHealthStatus()
|
||||
c.JSON(http.StatusOK, gin.H{"data": healthStatus})
|
||||
}
|
||||
|
||||
func (am *APIManager) handleFeaturesMetrics(c *gin.Context) {
|
||||
if am.featureManager == nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Feature manager not available"})
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Implement comprehensive metrics collection
|
||||
c.JSON(http.StatusOK, gin.H{"data": "metrics"})
|
||||
}
|
||||
|
||||
// Placeholder handlers for feature endpoints (to be implemented)
|
||||
func (am *APIManager) handleGetUserProfile(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleUpdateUserProfile(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleFollowUser(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleUnfollowUser(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetFollowers(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetFollowing(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetAchievements(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetLeaderboard(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleClaimAchievement(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleStartVerification(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetVerificationStatus(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetTrustScore(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetRooms(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleCreateRoom(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetRoom(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleJoinRoom(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleLeaveRoom(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleStartVoiceChat(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleStopVoiceChat(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetVoiceStatus(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleStartVideoStream(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleStopVideoStream(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetVideoStreams(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleUploadAudio(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleStreamAudio(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetAudioMetadata(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetSmartPlaylists(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleCreateSmartPlaylist(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetSmartPlaylist(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleDiscoverContent(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetTrending(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetSimilarContent(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetRecommendations(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleRecommendationFeedback(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleModerateContent(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetModerationHistory(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleAnalyzeSentiment(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetSentimentTrends(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetDashboard(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetRealtimeMetrics(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetUserBehavior(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetEngagementMetrics(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetRevenueAnalytics(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetConversionMetrics(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleExternalAPIRequest(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetExternalAPIStatus(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleCreateWebhook(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetWebhooks(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleDeleteWebhook(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleProcessPayment(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetPaymentMethods(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
func (am *APIManager) handleGetPaymentHistory(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "Not implemented"})
|
||||
}
|
||||
Loading…
Reference in a new issue