Backend development for real_deal platform using Go 1.23, Gin framework, MongoDB, Redis, MinIO, and NATS. Use when working on backend API development, database operations, object storage, message queuing, or maintaining the Go server.
cmd/
server/main.go # Entry point
seed/main.go # Database seeding
internal/
config/config.go # Configuration management
db/
mongo.go # MongoDB connection
redis.go # Redis connection
handlers/ # API route handlers
types.go # Shared data types
auth.go # Authentication
explore.go # Explore endpoint
jobs.go # Job listings
projects.go # Project listings
dealroom.go # Deal room API
pitch.go # Pitch page API
# ... other handlers
storage/storage.go # MinIO interface
internal/handlers/types.go)type MediaAsset struct {
ID string `json:"id"`
Type string `json:"type"`
Title string `json:"title"`
Key string `json:"key"`
ContentURL string `json:"contentUrl"`
CreatedAt time.Time `json:"createdAt"`
}
type Job struct {
ID string `json:"id"`
Title string `json:"title"`
Location string `json:"location"`
Level string `json:"level"`
Salary string `json:"salary"`
Skills []string `json:"skills"`
}
type Company struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Verified bool `json:"verified"`
Tags []string `json:"tags"`
}
type ExploreResponse struct {
Projects []Project `json:"projects"`
Products []Product `json:"products"`
Posts []Post `json:"posts"`
Jobs []Job `json:"jobs"`
Companies []Company `json:"companies"`
}
All handlers follow this pattern:
package handlers
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
type JobHandler struct{ DB *mongo.Database }
func NewJob(db *mongo.Database) *JobHandler { return &JobHandler{DB: db} }
func (h *JobHandler) List(c *gin.Context) {
ctx := context.Background()
cur, err := h.DB.Collection("jobs").Find(ctx, bson.D{}, nil)
if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}); return }
var items []Job
for cur.Next(ctx) { var j Job; _ = cur.Decode(&j); items = append(items, j) }
c.JSON(http.StatusOK, items)
}
type AuthHandler struct{ DB *mongo.Database }
func NewAuth(db *mongo.Database) *AuthHandler { return &AuthHandler{DB: db} }
func (h *AuthHandler) Login(c *gin.Context) {
var req loginReq
if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}); return }
ctx := context.Background()
var u map[string]any
err := h.DB.Collection("users").FindOne(ctx, bson.M{"email": req.Email}).Decode(&u)
if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "not found"}); return }
id, _ := u["id"].(string)
c.SetCookie("uid", id, 86400*7, "/", "localhost", false, true)
c.JSON(http.StatusOK, u)
}
func (h *AuthHandler) Me(c *gin.Context) {
uid, err := c.Cookie("uid")
if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauth"}); return }
ctx := context.Background()
var u map[string]any
err = h.DB.Collection("users").FindOne(ctx, bson.M{"id": uid}).Decode(&u)
if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauth"}); return }
c.JSON(http.StatusOK, u)
}
// Load config with config.Load()
cfg := config.Load()
// Environment variables:
// MONGO_URI, MONGO_DB
// REDIS_ADDR, REDIS_PASSWORD
// MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET
// SERVER_ADDR
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000", "http://127.0.0.1:3000"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Content-Type", "Authorization", "X-Requested-With", "Accept", "Origin"},
ExposeHeaders: []string{"Set-Cookie"},
AllowCredentials: true,
}))
internal/handlers/types.gointernal/handlers/ following the patterncmd/server/main.goseeds/ directoryusers - User accounts and profilesprojects - Project listingsproducts - Product listingsposts - Blog postsjobs - Job listingscompanies - Company profilespitch_pages - Pitch pagesdeal_rooms - Deal roomsinvestors - Investor profilescompany_verifications - Verification recordsjob_compliance - Job compliance recordscontent_moderation - Content moderation records# 1. Create handler file
touch internal/handlers/yourfeature.go
# 2. Define handler
type YourHandler struct{ DB *mongo.Database }
func NewYour(db *mongo.Database) *YourHandler { return &YourHandler{DB: db} }
# 3. Implement methods
func (h *YourHandler) List(c *gin.Context) {
// Implementation
}
# 4. Register in main.go
r.GET("/api/your-endpoint", handlers.NewYour(mongo.DB).List)
# Build and run seed
go build -o seed ./cmd/seed
./seed
# Or with Docker
docker-compose --profile seed up seed
# Start services
docker-compose up -d
# Run backend
go run cmd/server/main.go
# Run tests
go test ./...
# Run specific package tests
go test ./internal/handlers
# Run with coverage
go test -cover ./...