Skip to content

pchs20/diet-backend

Repository files navigation

Diet project - Backend

This is my first experience with Golang, and I used it to build a backend service for a multi-day diet planning system. It exposes REST endpoints for CRUD operations and gRPC services tailored for optimization clients.


1) Project Overview

diet-backend is the data and API layer of a larger personal diet-planning project.

Its responsibilities are:

  • manage domain data (categories, ingredients, dishes, meals),
  • provide public REST endpoints for management and inspection,
  • provide gRPC endpoints consumed by optimization workflows,
  • persist all data in PostgreSQL with explicit SQL migrations,
  • bootstrap a realistic dataset for local development and demos.

This backend is designed to support the companion project diet-dietitian, where optimization logic generates diet plans from nutritional constraints.


2) Problem & Vision

The intended product flow is:

  • users can generate a diet for a configurable number of days,
  • daily and global requirements can be enforced (e.g., protein/fat targets, vegetarian constraints, dish preferences),
  • users can inspect and modify generated diets,
  • both built-in and user-defined dishes/ingredients can be part of the process.

This repository focuses on the backend foundation required for those capabilities.


3) Architecture and structure

Project architecture

The codebase follows a layered, ports-and-adapters style:

  • Domain (internal/domain)

    • Core entities (Category, Ingredient, Dish, Meal, Quantity) and invariants.
    • Validation rules live here (e.g., non-empty names, non-negative quantities, valid hex colors).
    • Explicit quantity types following the Quantity pattern: composition (g, units), nutrient (g/100g, g/unit, kcal/100g), and currency (euro/100g, euro/unit).
  • Application (internal/application)

    • Use-case interfaces (in/) and service implementations (services/).
    • Repository and ID generation interfaces (out/) for dependency inversion.
  • Adapters In (internal/adapters/in)

    • REST API (Gin + Swagger annotations).
    • gRPC API (protobuf contracts + handlers).
  • Adapters Out (internal/adapters/out)

    • Persistence via GORM + PostgreSQL models/repositories.
    • Migration handling with golang-migrate.
    • UUID ID generator.
  • Bootstrap / Runtime

    • main.go wires all dependencies manually.
    • Runs REST and gRPC servers concurrently.

Project Structure

.
├── main.go
├── Makefile
├── docker-compose.yml
├── internal/
│   ├── adapters/
│   │   ├── in/
│   │   │   ├── grpc/
│   │   │   └── rest/
│   │   └── out/
│   │       └── persistence/
│   ├── application/
│   │   ├── in/
│   │   ├── out/
│   │   ├── services/
│   │   └── testutil/
│   ├── domain/
│   ├── config/
│   └── seed/
└── README.md

4) API Surfaces

REST API (Gin)

Swagger docs are exposed at:

  • GET /docs/index.html

Current routes:

Categories

  • POST /categories

Ingredients

  • GET /ingredients
  • POST /ingredients
  • GET /ingredients/:id
  • PATCH /ingredients/:id
  • DELETE /ingredients/:id

Dishes

  • GET /dishes
  • POST /dishes
  • GET /dishes/:id
  • PATCH /dishes/:id
  • DELETE /dishes/:id

Meals

  • GET /meals
  • POST /meals
  • DELETE /meals/:id

gRPC API

Proto contracts live in:

  • internal/adapters/in/grpc/proto/diet/v1/dish.proto
  • internal/adapters/in/grpc/proto/diet/v1/meal.proto

Services:

  • DishService.ListDishes
  • MealService.ListMeals

5) Seed & Demo Data

Seeding uses embedded JSON files (internal/seed/data) and is designed to be idempotent:

  • creates missing entities,
  • updates existing ingredients/dishes by name,
  • ensures referential consistency across meals, categories, ingredients, and dish recipes.

Current dataset size:

  • categories.json: 10
  • ingredients.json: 61
  • dish_recipes.json: 75
  • dishes.json: 75
  • meals.json: 3

Run seed in Docker:

make seed

Or (after services are up):

docker compose run --rm backend ./main seed

6) Local Setup & Runbook

Prerequisites

  • Go 1.25.5
  • Docker + Docker Compose
  • Optional local tools for full workflow:
    • swag
    • buf
    • golangci-lint
    • migrate

Environment

Example .env values:

DB_HOST=localhost
DB_PORT=5432
DB_USER=dietuser
DB_PASSWORD=test
DB_NAME=dietdb
DB_SSLMODE=disable

SERVER_REST_PORT=8080
SERVER_GRPC_PORT=9090

Quickstart (Docker-first)

make up-build

This will:

  • build and start backend + database,
  • run migrations,
  • seed data.

Ports:

  • REST: 8080
  • gRPC: 9090
  • PostgreSQL host mapping: 5433 -> 5432 by default

Stop everything:

make down

Local development commands

make fmt
make lint
make swagger
make grpc-gen
make build
make run
make test
make test-coverage
make ci

Migration helpers

make migration name=add_new_table
make migration-up
make migration-down
make migration-version

7) Testing and code quality

Testing

  • Domain tests for entity invariants and value objects.
  • Application service tests with repository and ID generator mocks.
  • Focus on behavior and error propagation.

Test files currently cover:

  • internal/domain/{category,ingredient,dish,meal,quantity}
  • internal/application/services/{category,ingredient,dish,meal}

Code quality

  • Linting configured with golangci-lint (formatting, vet/static checks, complexity and duplication checks).
  • Swagger and protobuf generation are part of the build workflow.

Operational behavior

  • Startup fails fast on invalid config or DB connection issues.
  • REST and gRPC servers start in one process and shut down gracefully.

8) Known Limitations

  • HTTP error mapping is still coarse in several handlers; many failures currently map to 500.
  • Dietary flags (vegetarian, vegan) in gRPC are inferred heuristically from ingredient names, not modeled explicitly in domain entities.
  • No authentication/authorization yet.

About

Diet project backend

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors