# Project Rules ## Language - All code comments must be written in **English**. - All git commit messages must be written in **English**. ## 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 ```sql -- 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 ```sql 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.