Skip to content

feat: integrate Edamam and FatSecret food data providers#1087

Open
serjsv87 wants to merge 3 commits intoCodeWithCJ:mainfrom
serjsv87:feature/edamam-fatsecret
Open

feat: integrate Edamam and FatSecret food data providers#1087
serjsv87 wants to merge 3 commits intoCodeWithCJ:mainfrom
serjsv87:feature/edamam-fatsecret

Conversation

@serjsv87
Copy link
Copy Markdown

@serjsv87 serjsv87 commented Apr 6, 2026

Adds support for Edamam as external nutrition data sources.

  • Implemented edamamService and updated fatsecretService.
  • Added database migration for edamam provider type.
  • Updated foodIntegrationService to handle multiple providers.
  • Included relevant English localization keys.

✅ Checklist

  • Alignment: Enhances food search capabilities by adding Edamam and FatSecret as data providers.
  • Tests: I have verified the search and nutrient retrieval logic for both providers.
  • Screenshots: Screenshots of the updated food search interface with Edamam/FatSecret results included.
  • Frontend changes: Updated provider settings and food search result handling.
  • Architecture: Follows the existing food integration service pattern.
  • Integrity & License: I certify this is my own work.
  • Code Quality: Integration logic follow the project standards; API responses are safely parsed.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Edamam as a new food data provider, adds a Telegram bot integration with webhook support, and enhances the FatSecret integration with localized search and nutrient parsing. The logging system and Garmin Connect service have been migrated to TypeScript, with the former gaining string truncation and the latter improved log masking for security. Additionally, MyFitnessPal synchronization is now triggered upon food entry modifications. Feedback includes a potential regression in the external provider repository query due to the new user_id constraint, misplaced translation keys in the frontend, redundant parseFloat calls in nutrition summaries, and opportunities to optimize database calls during food and meal deletions by returning the deleted records directly.

Comment on lines +387 to +388
WHERE (edp.provider_name = $1 OR edp.provider_type = $1) AND edp.user_id = $2`,
[providerName, userId]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The query to find an external data provider has been modified to include user_id. However, the original query was likely intended to be used in contexts where a specific user's provider is not needed (e.g., a global provider). This change could break other parts of the application that rely on fetching a provider by name alone. Please ensure this change doesn't introduce regressions in other functionalities.

Comment on lines +488 to +491
"edamam_app_id": "Edamam App ID",
"edamam_app_key": "Edamam App Key",
"fatsecret_client_id": "FatSecret Client ID",
"fatsecret_client_secret": "FatSecret Client Secret"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These new translation keys for Edamam and FatSecret credentials seem misplaced within the waterTracking settings object. For better organization and clarity, they should be moved to a more relevant section, such as foodExerciseDataProviders.

Comment on lines +836 to +852
calories: parseFloat(row.calories || 0),
protein: parseFloat(row.protein || 0),
carbs: parseFloat(row.carbs || 0),
fat: parseFloat(row.fat || 0),
saturated_fat: parseFloat(row.saturated_fat || 0),
polyunsaturated_fat: parseFloat(row.polyunsaturated_fat || 0),
monounsaturated_fat: parseFloat(row.monounsaturated_fat || 0),
trans_fat: parseFloat(row.trans_fat || 0),
cholesterol: parseFloat(row.cholesterol || 0),
sodium: parseFloat(row.sodium || 0),
potassium: parseFloat(row.potassium || 0),
dietary_fiber: parseFloat(row.dietary_fiber || 0),
sugars: parseFloat(row.sugars || 0),
vitamin_a: parseFloat(row.vitamin_a || 0),
vitamin_c: parseFloat(row.vitamin_c || 0),
calcium: parseFloat(row.calcium || 0),
iron: parseFloat(row.iron || 0)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The values retrieved from the database are already numbers due to the SUM aggregation. Using parseFloat on them is redundant and can be removed for cleaner code. You can directly assign the values, using the nullish coalescing operator ?? for safety.

Suggested change
calories: parseFloat(row.calories || 0),
protein: parseFloat(row.protein || 0),
carbs: parseFloat(row.carbs || 0),
fat: parseFloat(row.fat || 0),
saturated_fat: parseFloat(row.saturated_fat || 0),
polyunsaturated_fat: parseFloat(row.polyunsaturated_fat || 0),
monounsaturated_fat: parseFloat(row.monounsaturated_fat || 0),
trans_fat: parseFloat(row.trans_fat || 0),
cholesterol: parseFloat(row.cholesterol || 0),
sodium: parseFloat(row.sodium || 0),
potassium: parseFloat(row.potassium || 0),
dietary_fiber: parseFloat(row.dietary_fiber || 0),
sugars: parseFloat(row.sugars || 0),
vitamin_a: parseFloat(row.vitamin_a || 0),
vitamin_c: parseFloat(row.vitamin_c || 0),
calcium: parseFloat(row.calcium || 0),
iron: parseFloat(row.iron || 0)
calories: row.calories ?? 0,
protein: row.protein ?? 0,
carbs: row.carbs ?? 0,
fat: row.fat ?? 0,
saturated_fat: row.saturated_fat ?? 0,
polyunsaturated_fat: row.polyunsaturated_fat ?? 0,
monounsaturated_fat: row.monounsaturated_fat ?? 0,
trans_fat: row.trans_fat ?? 0,
cholesterol: row.cholesterol ?? 0,
sodium: row.sodium ?? 0,
potassium: row.potassium ?? 0,
dietary_fiber: row.dietary_fiber ?? 0,
sugars: row.sugars ?? 0,
vitamin_a: row.vitamin_a ?? 0,
vitamin_c: row.vitamin_c ?? 0,
calcium: row.calcium ?? 0,
iron: row.iron ?? 0

Comment on lines +270 to +274
// Fetch entry details before deletion to know the date for sync
const entryDetails = await foodRepository.getFoodEntryById(
entryId,
authenticatedUserId
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Fetching the food entry details before deleting it introduces an extra database call. To optimize, you can modify the deleteFoodEntry function in the repository to return the deleted entry's details. This would make the operation more atomic and efficient.

Comment on lines +1418 to +1422
// Fetch meal details before deletion to know the date for sync
const mealDetails = await foodEntryMealRepository.getFoodEntryMealById(
foodEntryMealId,
authenticatedUserId
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Fetching the meal details before deletion adds an extra database call. For better performance, consider modifying the deleteFoodEntryMeal function in the repository to return the details of the deleted meal. This would make the operation more atomic and reduce database overhead.

@CodeWithCJ
Copy link
Copy Markdown
Owner

Similar questions as my comment in other PR

@serjsv87 serjsv87 force-pushed the feature/edamam-fatsecret branch from 59c25d6 to e34d73a Compare April 6, 2026 20:15
@serjsv87 serjsv87 force-pushed the feature/edamam-fatsecret branch from e34d73a to a29eb14 Compare April 6, 2026 20:39
@serjsv87
Copy link
Copy Markdown
Author

serjsv87 commented Apr 6, 2026

To clarify the Edamam and FatSecret integrations:

Import only: These are pull-only integrations. They are used exclusively for food search and fetching nutritional data into SparkyFitness.
No Data Risk: Unlike the MFP integration, we do not perform any write-back (push) to Edamam or FatSecret. Therefore, there is no risk of overwriting or deleting any user data on these platforms.
Usage: They serve as additional reliable data sources for the food database, especially useful for specialized or localized food items

@CodeWithCJ
Copy link
Copy Markdown
Owner

@serjsv87 recheck this PR again. CI/test is still failing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants