initial commit
This commit is contained in:
commit
e7987e88a7
70 changed files with 13661 additions and 0 deletions
241
internal/service/project_service.go
Normal file
241
internal/service/project_service.go
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/dnoulet/go-first/internal/model"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ProjectService struct {
|
||||
mu sync.RWMutex
|
||||
projects map[uuid.UUID]*model.Project
|
||||
}
|
||||
|
||||
func NewProjectService() *ProjectService {
|
||||
s := &ProjectService{
|
||||
projects: make(map[uuid.UUID]*model.Project),
|
||||
}
|
||||
s.seedData()
|
||||
return s
|
||||
}
|
||||
|
||||
type catalogProject struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
ShortDesc string `json:"shortDesc"`
|
||||
TechStack []string `json:"techStack"`
|
||||
ImageURL string `json:"imageUrl"`
|
||||
DemoURL *string `json:"demoUrl"`
|
||||
RepoURL string `json:"repoUrl"`
|
||||
Category string `json:"category"`
|
||||
Featured bool `json:"featured"`
|
||||
Order int `json:"order"`
|
||||
}
|
||||
|
||||
func projectsFile() string {
|
||||
if v := os.Getenv("GO_FIRST_PROJECTS_FILE"); v != "" {
|
||||
return v
|
||||
}
|
||||
for _, candidate := range []string{"projects.json", "/app/projects.json"} {
|
||||
if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func loadCatalog() ([]*model.Project, bool) {
|
||||
path := projectsFile()
|
||||
if path == "" {
|
||||
return nil, false
|
||||
}
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
var rows []catalogProject
|
||||
if err := json.Unmarshal(raw, &rows); err != nil || len(rows) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
projects := make([]*model.Project, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
demo := ""
|
||||
if row.DemoURL != nil {
|
||||
demo = *row.DemoURL
|
||||
}
|
||||
projects = append(projects, &model.Project{
|
||||
ID: uuid.New(),
|
||||
Title: row.Title,
|
||||
Description: row.Description,
|
||||
ShortDesc: row.ShortDesc,
|
||||
TechStack: row.TechStack,
|
||||
ImageURL: row.ImageURL,
|
||||
DemoURL: demo,
|
||||
RepoURL: row.RepoURL,
|
||||
Category: row.Category,
|
||||
Featured: row.Featured,
|
||||
Order: row.Order,
|
||||
})
|
||||
}
|
||||
return projects, true
|
||||
}
|
||||
|
||||
func (s *ProjectService) seedData() {
|
||||
if projects, ok := loadCatalog(); ok {
|
||||
for _, project := range projects {
|
||||
s.projects[project.ID] = project
|
||||
}
|
||||
return
|
||||
}
|
||||
projects := []*model.Project{
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Title: "E-Commerce Platform",
|
||||
Description: "A full-featured e-commerce platform built with Go microservices, React frontend, and Kubernetes deployment. Features include user authentication, product catalog, shopping cart, payment integration, order management, and admin dashboard.",
|
||||
ShortDesc: "Scalable e-commerce platform with Go microservices and React",
|
||||
TechStack: []string{"Go", "React", "PostgreSQL", "Redis", "Kubernetes", "Docker", "gRPC"},
|
||||
ImageURL: "/images/projects/ecommerce.jpg",
|
||||
DemoURL: "https://demo.urpi.be/ecommerce",
|
||||
RepoURL: "https://github.com/urpi/ecommerce-platform",
|
||||
Category: "Full Stack",
|
||||
Featured: true,
|
||||
Order: 1,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Title: "API Gateway Service",
|
||||
Description: "High-performance API gateway built in Go with rate limiting, authentication, request/response transformation, circuit breaker, and distributed tracing. Handles 100k+ requests/second with sub-millisecond latency.",
|
||||
ShortDesc: "High-performance Go API gateway with advanced features",
|
||||
TechStack: []string{"Go", "Redis", "Prometheus", "Grafana", "OpenTelemetry", "Docker"},
|
||||
ImageURL: "/images/projects/apigateway.jpg",
|
||||
DemoURL: "",
|
||||
RepoURL: "https://github.com/urpi/api-gateway",
|
||||
Category: "Backend",
|
||||
Featured: true,
|
||||
Order: 2,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Title: "Real-time Collaboration Tool",
|
||||
Description: "Real-time collaborative document editor with operational transformation, WebSocket connections, presence indicators, and conflict resolution. Built with Go backend and React frontend.",
|
||||
ShortDesc: "Real-time collaborative editor with operational transformation",
|
||||
TechStack: []string{"Go", "React", "WebSocket", "Redis", "PostgreSQL", "TypeScript"},
|
||||
ImageURL: "/images/projects/collab.jpg",
|
||||
DemoURL: "https://collab.urpi.be",
|
||||
RepoURL: "https://github.com/urpi/realtime-collab",
|
||||
Category: "Full Stack",
|
||||
Featured: true,
|
||||
Order: 3,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Title: "Distributed Task Queue",
|
||||
Description: "Distributed task queue system with priority queues, delayed jobs, retry logic, dead letter queues, and horizontal scaling. Built for high-throughput background job processing.",
|
||||
ShortDesc: "Scalable distributed task queue with priority and retry logic",
|
||||
TechStack: []string{"Go", "Redis", "PostgreSQL", "Docker", "Kubernetes"},
|
||||
ImageURL: "/images/projects/taskqueue.jpg",
|
||||
DemoURL: "",
|
||||
RepoURL: "https://github.com/urpi/distributed-task-queue",
|
||||
Category: "Backend",
|
||||
Featured: false,
|
||||
Order: 4,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Title: "Infrastructure as Code Framework",
|
||||
Description: "Custom IaC framework for managing multi-cloud infrastructure with Go templates, drift detection, and policy enforcement. Supports AWS, GCP, and Azure.",
|
||||
ShortDesc: "Multi-cloud IaC framework with drift detection",
|
||||
TechStack: []string{"Go", "Terraform", "AWS", "GCP", "Azure", "Docker"},
|
||||
ImageURL: "/images/projects/iac.jpg",
|
||||
DemoURL: "",
|
||||
RepoURL: "https://github.com/urpi/iac-framework",
|
||||
Category: "DevOps",
|
||||
Featured: false,
|
||||
Order: 5,
|
||||
},
|
||||
{
|
||||
ID: uuid.New(),
|
||||
Title: "Financial Transaction Processor",
|
||||
Description: "High-throughput financial transaction processing system with ACID guarantees, audit logging, regulatory compliance, and real-time fraud detection. Processes millions of transactions daily.",
|
||||
ShortDesc: "High-throughput financial transaction processor with fraud detection",
|
||||
TechStack: []string{"Java", "Spring Boot", "PostgreSQL", "Apache Kafka", "Kubernetes"},
|
||||
ImageURL: "/images/projects/fintech.jpg",
|
||||
DemoURL: "",
|
||||
RepoURL: "",
|
||||
Category: "Backend",
|
||||
Featured: true,
|
||||
Order: 6,
|
||||
},
|
||||
}
|
||||
|
||||
for _, project := range projects {
|
||||
s.projects[project.ID] = project
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ProjectService) GetAll(ctx context.Context, category string, featured bool) ([]*model.Project, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
var result []*model.Project
|
||||
for _, project := range s.projects {
|
||||
if category != "" && project.Category != category {
|
||||
continue
|
||||
}
|
||||
if featured && !project.Featured {
|
||||
continue
|
||||
}
|
||||
result = append(result, project)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *ProjectService) GetFeatured(ctx context.Context) ([]*model.Project, error) {
|
||||
return s.GetAll(ctx, "", true)
|
||||
}
|
||||
|
||||
func (s *ProjectService) GetByID(ctx context.Context, id uuid.UUID) (*model.Project, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
project, ok := s.projects[id]
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (s *ProjectService) Create(ctx context.Context, project *model.Project) (*model.Project, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
project.ID = uuid.New()
|
||||
s.projects[project.ID] = project
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (s *ProjectService) Update(ctx context.Context, project *model.Project) (*model.Project, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, ok := s.projects[project.ID]; !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
s.projects[project.ID] = project
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (s *ProjectService) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, ok := s.projects[id]; !ok {
|
||||
return ErrNotFound
|
||||
}
|
||||
delete(s.projects, id)
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue