Project Structure & Architecture

Project Structure & Architecture

Sphere follows a pragmatic project structure that keeps code generation, server code, and business logic cleanly separated while staying fast to iterate on. The structure is based on the sphere-layout template and follows Go community best practices.

Architecture Philosophy

Sphere embraces a monolith-first approach with clean boundaries:

  • Start with one binary using the standard project structure
  • Share contracts via Protobuf and generated code across services
  • Extract services only when scaling requires it
  • Maintain clear boundaries via directories and interfaces
  • Automate with Makefile targets to maintain repeatability

This approach allows you to begin with a modular monolith and easily scale to microservices without restructuring your codebase.

Overview

The project structure is designed to:

  • Provide clear separation of concerns
  • Support efficient code generation workflows
  • Enable easy testing and development
  • Scale from monolith to microservices

Directory Structure

├── api                 # Go files generated by Protobuf definitions
├── assets              # Static files (e.g., UI assets, templates)
├── cmd                 # Application entry points
│   ├── app             # Main application
│   └── tools           # Developer tools
├── devops              # DevOps and infrastructure files (e.g., Docker, CI/CD)
├── internal            # Private application and library code
│   ├── biz             # Business logic layer (use cases)
│   ├── config          # Configuration loading and management
│   ├── pkg             # Shared internal packages
│   │   ├── database    # Database setup, including ent schemas and client
│   │   └── ...         # Other shared utilities
│   ├── server          # Server implementation (gRPC, HTTP)
│   └── service         # Service layer implementing the API interfaces
├── proto               # Protobuf source files (.proto)
├── scripts             # Helper scripts for development
└── swagger             # Generated Swagger/OpenAPI documentation

Key Directories

At a glance, common top-level directories:

  • api/: Generated Go from .proto (do not edit)
  • cmd/: Entrypoints and developer tools
  • internal/: Private application code (service, biz, data, server)
  • proto/: Protobuf contracts
  • devops/: CI/CD and infrastructure
  • scripts/: Developer scripts and helpers
  • swagger/: Generated OpenAPI assets

Layer Responsibilities

Transport Layer (internal/server/)

  • HTTP request/response handling
  • Protocol-specific concerns
  • Middleware application
  • Request routing

Service Layer (internal/service/)

  • API contract implementation
  • Request validation
  • Response formatting
  • Transport-agnostic logic

Business Layer (internal/biz/)

  • Core business logic
  • Use case orchestration
  • Domain rules enforcement
  • Transaction management

Data Layer (internal/pkg/database/)

  • Data persistence
  • Query optimization
  • Schema management
  • Database transactions

Notes

  • Keep generated code under api/ separate and unedited
  • Group proto and services by domain + version (e.g., api.v1)
  • Add custom Make targets for project-specific tasks
  • Modify the build process in the Makefile

However, maintain the core separation between generated code (api/), business logic (internal/biz/), and service implementations (internal/service/) to ensure code generation tools continue to work effectively.

Migration from Other Structures

If you’re migrating from other project layouts:

  1. From Standard Go Layout: Move business logic from pkg/ to internal/biz/
  2. From DDD Layout: Align domain packages with proto package structure
  3. From Layered Architecture: Merge controller and service layers into internal/service/
  4. From Hexagonal Architecture: Map ports/adapters to service/biz layers

The key is maintaining clear boundaries between transport, business logic, and data access while leveraging code generation for the transport layer.

Scaling Out

As your application grows, Sphere enables seamless scaling:

  • Multiple binaries can reuse the same contracts and tooling
  • Consistent errors, routing, and payloads via generators reduce drift between services
  • Shared proto packages keep all services in sync
  • Makefile targets ensure consistent build and generation processes across all services

Repository Strategy

Sphere recommends a pragmatic approach to repository organization:

Single Repository Approach (Recommended for Start)

  • Keep everything in one repository initially
  • Use Makefile-driven code generation for consistency
  • Maintain clear module boundaries through interfaces
  • Scale to multiple repositories only when necessary

Multi-Repository Strategy (When Scaling)

  • Separate repositories for independent microservices
  • Shared proto definitions in a dedicated repository
  • Shared libraries in separate packages
  • Consistent tooling across all repositories

The key is starting simple with a single monolithic structure and evolving to microservices only when business requirements demand it. The shared Protobuf contracts and generators ensure consistency across the entire system.

Last updated on