Files
food-ai/CLAUDE.md
dbastrikin 2b149eab1c docs: add backend README sync rule to CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 13:09:56 +02:00

5.6 KiB

Project Rules

Language

  • All code comments must be written in English.
  • All git commit messages must be written in English.

What NOT to commit

  • The examples/ directory — it contains sample images and fixtures used for manual testing only. It is listed in .gitignore and must never be staged or committed.

Localisation

Rule: Every table that stores human-readable text must have a companion {table}_translations table. The base table always contains the English canonical text (used as fallback). Translations live only in _translations tables — never as extra columns (name_ru, title_de).

SQL pattern

-- Base table — English canonical text always present
CREATE TABLE cuisines (
    slug       VARCHAR(50) PRIMARY KEY,
    name       TEXT NOT NULL,
    sort_order SMALLINT NOT NULL DEFAULT 0
);
-- Translation companion
CREATE TABLE cuisine_translations (
    cuisine_slug VARCHAR(50) REFERENCES cuisines(slug) ON DELETE CASCADE,
    lang         VARCHAR(10) NOT NULL,
    name         TEXT NOT NULL,
    PRIMARY KEY  (cuisine_slug, lang)
);

Query pattern

SELECT COALESCE(ct.name, c.name) AS name
FROM cuisines c
LEFT JOIN cuisine_translations ct ON ct.cuisine_slug = c.slug AND ct.lang = $lang

Already compliant tables

units + unit_translations, ingredient_categories + ingredient_category_translations, ingredients + ingredient_translations + ingredient_aliases, recipes + recipe_translations, cuisines + cuisine_translations, tags + tag_translations, dish_categories + dish_category_translations, dishes + dish_translations, recipe_ingredients + recipe_ingredient_translations, recipe_steps + recipe_step_translations.

Rule when adding new entities

When adding a new entity with text fields, always create a {table}_translations companion table and use LEFT JOIN COALESCE in all read queries.

File and Directory Naming

  • File names: snake_case — token_verifier.go, wire_gen.go, entity.go.
  • Package directories: lowercase, no separators — follow Go convention (savedrecipe/, openai/, infra/). Do not use underscores in package names.
  • Non-package directories (migrations, docs, scripts): snake_case is acceptable.

Naming

No abbreviated variable names. Variables must use full descriptive names. Single- or two-letter names are only allowed when the abbreviation is the full description (e.g., a loop index i, a matrix coordinate x).

Examples

Avoid Use instead
err parseError, writeError, dbError, validationError
ctx requestContext, handlerContext, queryContext
s service, server
r request, repository
w writer, responseWriter
h handler
req request
res response, result
msg message
cfg config
db database
tx transaction
buf buffer
tmp temp, or a descriptive name

This rule applies to all languages in this repo (Go and Dart). In Go, name variables to avoid shadowing the error built-in and the context package — use descriptive prefixes: parseError, requestContext, etc.

Backend Documentation

Rule: backend/README.md must stay in sync with the code. When making backend changes, update the README if the change affects any of the following:

  • Stack or dependencies — new or removed libraries
  • Environment variables — new, renamed, or removed variables
  • API endpoints — new routes, changed paths or methods, removed endpoints
  • Makefile targets — new or removed make commands
  • Project structure — new top-level packages under cmd/, internal/domain/, internal/adapters/, or internal/infra/
  • Database schema — new tables added to the high-level table list
  • Import tools — changes to cmd/importoff flags or behaviour

The README does not need updating for: internal refactoring that doesn't change the public interface, bug fixes, test changes, or minor logic tweaks inside existing packages.

Flutter Client Localisation

Rule: Every UI string in client/ must go through AppLocalizations. Never hardcode user-visible text in Dart source files.

Current setup

  • flutter_localizations (sdk: flutter) + intl: ^0.20.2 in client/pubspec.yaml
  • generate: true under flutter: in client/pubspec.yaml
  • client/l10n.yaml — generator config (arb-dir, template-arb-file, output-class)
  • Generated class: package:food_ai/l10n/app_localizations.dart

Supported languages

en, ru, es, de, fr, it, pt, zh, ja, ko, ar, hi

ARB files

All translation files live in client/lib/l10n/:

  • app_en.arb — English (template / canonical)
  • app_ru.arb, app_es.arb, app_de.arb, app_fr.arb, app_it.arb
  • app_pt.arb, app_zh.arb, app_ja.arb, app_ko.arb, app_ar.arb, app_hi.arb

Usage pattern

import 'package:food_ai/l10n/app_localizations.dart';

// Inside build():
final l10n = AppLocalizations.of(context)!;
Text(l10n.someKey)

Adding new strings

  1. Add the key + English value to client/lib/l10n/app_en.arb (template file).
  2. Add the same key with the correct translation to all other 11 ARB files.
  3. Run flutter gen-l10n inside client/ to regenerate AppLocalizations.
  4. Use l10n.<newKey> in the widget.

For parameterised strings use the ICU placeholder syntax in ARB files:

"queuePosition": "Position {position}",
"@queuePosition": { "placeholders": { "position": { "type": "int" } } }

Then call l10n.queuePosition(n) in Dart.