Compare commits

...

2 Commits

Author SHA1 Message Date
7fc17967e0 feat(dev): Add development build workflows and Nomad job
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 55s
2026-02-24 13:10:25 -08:00
afdf9fa5b7 chore(conductor): Add new track 'Refactor the meal tracking system to decouple 'Journal Logs' from 'Cookbook Recipes'' 2026-02-23 13:26:12 -08:00
8 changed files with 246 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
name: Build and Push Docker Image (DEV)
on:
workflow_dispatch:
push:
branches:
- dev
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
container_sha: ${{ github.sha }}
registry_url: ${{ steps.registry.outputs.url }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set registry URL
id: registry
run: |
if [ "${{ github.server_url }}" = "https://github.com" ]; then
echo "url=ghcr.io" >> $GITHUB_OUTPUT
else
echo "url=${{ github.server_url }}" | sed 's|https://||' >> $GITHUB_OUTPUT
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ steps.registry.outputs.url }}
username: ${{ github.actor }}
password: ${{ secrets.PACKAGE_TOKEN || secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push multi-arch Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: |
${{ steps.registry.outputs.url }}/${{ github.repository }}:dev
${{ steps.registry.outputs.url }}/${{ github.repository }}:${{ github.sha }}
build-args: |
COMMIT_SHA=${{ github.sha }}
cache-from: type=registry,ref=${{ steps.registry.outputs.url }}/${{ github.repository }}:buildcache-dev
cache-to: type=registry,ref=${{ steps.registry.outputs.url }}/${{ github.repository }}:buildcache-dev,mode=max
labels: org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}

56
.github/workflows/nomad-deploy-dev.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: Deploy to Nomad (DEV)
on:
workflow_run:
workflows: ["Build and Push Docker Image (DEV)"] # Must match your build workflow name exactly
types:
- completed
workflow_dispatch: # Allows manual triggering for testing
inputs:
container_sha:
description: 'Container SHA to deploy (leave empty for latest commit)'
required: false
type: string
jobs:
nomad:
runs-on: ubuntu-latest
name: Deploy to Nomad (DEV)
# Only run if the build workflow succeeded
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
steps:
# 1. Checkout Code
- name: Checkout Repository
uses: actions/checkout@v4
# 2. Install Nomad CLI
- name: Setup Nomad CLI
uses: hashicorp/setup-nomad@main
with:
version: '1.10.0' # Use your desired version or remove for 'latest'
# 3. Determine container version to deploy
- name: Set Container Version
id: container_version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.container_sha }}" ]; then
echo "sha=${{ inputs.container_sha }}" >> $GITHUB_OUTPUT
elif [ "${{ github.event_name }}" = "workflow_run" ]; then
echo "sha=${{ github.event.workflow_run.head_sha }}" >> $GITHUB_OUTPUT
else
echo "sha=${{ github.sha }}" >> $GITHUB_OUTPUT
fi
# 4. Deploy the Nomad Job
- name: Deploy Nomad Job
id: deploy
env:
# REQUIRED: Set the Nomad server address
NOMAD_ADDR: http://nomad.service.dc1.consul:4646
run: |
echo "Deploying container version: ${{ steps.container_version.outputs.sha }}"
nomad status
nomad job run
-var="container_version=${{ steps.container_version.outputs.sha }}"
foodplanner-dev.nomad

View File

@@ -3,3 +3,6 @@
This file tracks all major tracks for the project. Each track has its own detailed plan in its respective folder.
---
- [ ] **Track: Refactor the meal tracking system to decouple 'Journal Logs' from 'Cookbook Recipes'**
*Link: [./tracks/meal_tracker_refactor_20250223/](./tracks/meal_tracker_refactor_20250223/)*

View File

@@ -0,0 +1,5 @@
# Track meal_tracker_refactor_20250223 Context
- [Specification](./spec.md)
- [Implementation Plan](./plan.md)
- [Metadata](./metadata.json)

View File

@@ -0,0 +1,8 @@
{
"track_id": "meal_tracker_refactor_20250223",
"type": "refactor",
"status": "new",
"created_at": "2025-02-23T12:00:00Z",
"updated_at": "2025-02-23T12:00:00Z",
"description": "Refactor the meal tracking system to decouple 'Journal Logs' from 'Cookbook Recipes', resolving database pollution and improving system structure."
}

View File

@@ -0,0 +1,28 @@
# Implementation Plan - Meal Tracker Refactoring
This plan outlines the steps for refactoring the meal tracking system to decouple "Journal Logs" from "Cookbook Recipes," resolving database pollution and improving system structure.
## Phase 1: Preparation & Schema Updates
- [ ] Task: Create a new branch for the refactoring track.
- [ ] Task: Add the 'name' column to the 'TrackedMeal' table and make 'meal_id' nullable in 'app/database.py'.
- [ ] Task: Create and run an Alembic migration for the schema changes.
- [ ] Task: Conductor - User Manual Verification 'Phase 1: Preparation & Schema Updates' (Protocol in workflow.md)
## Phase 2: Logic & Calculation Updates
- [ ] Task: Write failing unit tests for 'calculate_tracked_meal_nutrition' with 'meal_id=None'.
- [ ] Task: Implement support for 'meal_id=None' in 'calculate_tracked_meal_nutrition' within 'app/database.py'.
- [ ] Task: Write failing unit tests for the refactored 'tracker_add_food' endpoint.
- [ ] Task: Refactor the 'tracker_add_food' route in 'app/api/routes/tracker.py' to use the new 'TrackedMeal' structure.
- [ ] Task: Conductor - User Manual Verification 'Phase 2: Logic & Calculation Updates' (Protocol in workflow.md)
## Phase 3: UI & Cookbook Refinement
- [ ] Task: Update the 'tracker.html' template to display 'TrackedMeal.name' for template-less logs.
- [ ] Task: Update the Meals page in 'app/api/routes/meals.py' to filter out 'single_food' and 'snapshot' types.
- [ ] Task: Write failing E2E tests for the new tracking workflow.
- [ ] Task: Conductor - User Manual Verification 'Phase 3: UI & Cookbook Refinement' (Protocol in workflow.md)
## Phase 4: Database Migration & Cleanup
- [ ] Task: Create a Python migration script for cleaning up existing 'single_food' entries.
- [ ] Task: Run the migration script on the development PostgreSQL database.
- [ ] Task: Verify the database state and ensure no orphans remain.
- [ ] Task: Conductor - User Manual Verification 'Phase 4: Database Migration & Cleanup' (Protocol in workflow.md)

View File

@@ -0,0 +1,28 @@
# Specification - Meal Tracker Refactoring
**Overview:**
Refactor the meal tracking system to decouple "Journal Logs" from "Cookbook Recipes". Currently, adding a single food item via the tracker incorrectly creates a permanent 'Meal' record of type 'single_food', leading to database pollution and duplicate entries in the Meals library.
**Functional Requirements:**
- **TrackedMeal Schema Update:** Add a 'name' column to the 'TrackedMeal' model to store the display name of a logged meal or a single food item.
- **Nullable meal_id:** Modify 'TrackedMeal.meal_id' to be nullable, allowing "template-less" logs.
- **Refactored Tracker Logic:** Update the 'tracker_add_food' route to log single items directly as a 'TrackedMeal' with 'meal_id=NULL' and the 'name' set to the food item's name.
- **Nutrition Calculation:** Update nutrition calculation logic to handle 'TrackedMeal' entries without a parent 'Meal' template.
- **Tracker UI Update:** Ensure the tracker page displays 'TrackedMeal.name' for these logs and maintains the seamless visual style of existing entries.
- **Cookbook Cleanup (One-time Migration):** Migrate existing 'single_food' meals to the new format and purge the redundant records from the 'meals' and 'meal_foods' tables.
- **Cookbook Filtering:** Update the Meals page to exclude 'single_food' and 'snapshot' meal types from view.
**Non-Functional Requirements:**
- **Database Integrity:** Ensure all existing logs remain accurate and correctly linked to their food items during migration.
- **Performance:** The tracker page should remain fast and responsive with the new logic.
**Acceptance Criteria:**
- [ ] Adding a single food to the tracker does **not** create a new entry in the 'meals' table.
- [ ] Existing 'single_food' duplicates are removed from the 'meals' library.
- [ ] The Meals page only shows "Cookbook Recipes" (e.g., proper combined meals).
- [ ] The Tracker page correctly displays names and calculates nutrition for all logs (both template-based and template-less).
- [ ] "Save as New Meal" remains available for all log entries, including single foods.
**Out of Scope:**
- Refactoring the entire meal planning system beyond the tracker/cookbook separation.
- Changes to the external Open Food Facts integration.

59
foodplanner-dev.nomad Normal file
View File

@@ -0,0 +1,59 @@
variable "container_version" {
default = "dev"
}
job "foodplanner-dev" {
datacenters = ["dc1"]
type = "service"
group "app" {
count = 1
network {
port "http" {
to = 8999
}
}
service {
name = "foodplanner-dev"
port = "http"
check {
type = "http"
path = "/"
interval = "10s"
timeout = "2s"
}
}
task "app" {
driver = "docker"
config {
image = "ghcr.io/sstent/foodplanner:${var.container_version}"
ports = ["http"]
}
env {
DATABASE_URL = "postgresql://postgres:postgres@master.postgres.service.dc1.consul/meal_planner_dev"
}
resources {
cpu = 500
memory = 1024
}
# Restart policy
restart {
attempts = 3
interval = "10m"
delay = "15s"
mode = "fail"
}
}
}
}