# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project requirement: PROJECT_CHANGES.md

Before making **any** change to this project, create or append to `PROJECT_CHANGES.md` in the
project root (see the format the repo's own instructions define). Never overwrite existing entries —
append chronologically. Each entry records date/time, task, files created/modified, migrations,
models, controllers, views, and notable decisions. Update it before considering a task complete.

## What this is

A [Yii 2 Basic Application Template](https://www.yiiframework.com/) (`yiisoft/yii2-app-basic`, PHP >= 7.4)
being grown into a multilingual, SEO-aware CMS / admin panel ("cinova"). The app `id` is still
`basic` in `config/web.php` and `config/console.php`; the framework scaffolding (SiteController,
the in-memory `models/User.php`, ContactForm/LoginForm) is mostly untouched template code. The
**real, project-specific work lives in `helpers/` and `migrations/`** — read those first.

Runs locally under OpenServer (Windows) against MySQL database `cinova` (`config/db.php`,
root / empty password by default).

## Commands

Console entry point is `php yii <route>` (Windows: `yii.bat`). Tests use Codeception.

```bash
php yii migrate                 # apply pending DB migrations (migrations/)
php yii migrate/down 1          # roll back the last migration
php yii migrate/create name     # scaffold a new migration
php yii hello/index "msg"       # sample console command (commands/HelloController.php)

composer install                # install deps; regenerates cookieValidationKey

vendor/bin/codecept run                 # run unit + functional suites
vendor/bin/codecept run unit            # one suite
vendor/bin/codecept run unit ModelTest  # a single test (suite + Cest/Test class)
```

Tests run against `config/test.php` / `config/test_db.php` (see `codeception.yml`). Acceptance
tests are disabled by default (require Selenium; see README "Running acceptance tests").

## Architecture & conventions

The helpers encode conventions that the rest of the app is expected to follow. The most important:

### Database column naming carries a size/role suffix
Columns are named `<role>_<size>_string`, e.g. `name_big_string`, `slug_big_string`,
`seo_title_small_string`, `seo_description_big_string`, `seo_og_type_mini_string`. The
`_mini_/_small_/_big_string` suffix signals intended length, and `seo_*` columns are consumed
directly by `SeoHelper::apply()` to populate `<title>` and meta/OpenGraph tags. `ModelHelper::getByType()`
filters model properties by substring (e.g. all `*_string` props), so these suffixes are
load-bearing — keep them consistent when adding columns.

### Enums are centralized string constants
`helpers/EnumHelper.php` is the single registry of every status / type / category string used in the
app (user states, order/checkout/payment lifecycle, priorities, email types, etc.). DB `ENUM` columns
are generated from these constants via `EnumHelper::generateQuery([Enum::A, Enum::B], 'not null default ...')`
inside migrations — never hand-write ENUM column SQL. `RecordHelper::getStatusEnum()` maps every status
constant to a UI color bucket (`active`/`warning`/`error`/`verify`) and renders a translated badge via
`Yii::t('admin/status', $status)`, so a new status constant should be added to that map too.

### Intended (not-yet-built) model layout
`EntityHelper.php` and the other helpers reference a target structure that **does not fully exist yet** —
treat them as the blueprint, and expect to create classes when wiring features:
- Models live in per-entity sub-namespaces: `app\models\Users\Users`, `app\models\Languages\Languages`,
  `app\models\Courses\Courses`. (The current flat `models/User.php` is leftover template code.)
- Translatable entities have a parallel `*Translations` model/table, e.g. `Courses` + `CoursesTranslations`.
- `app\constants\EntityConstants` is a registry of entity keys; `EntityHelper::getEntityMap()` /
  `getModelClass()` resolve a key → model class. Add new entities in both places.
- Note existing casing inconsistencies in the helpers (`app\models\Users\Users` vs.
  `app\models\pages\Pages` in `PageHelper`) — pick the capitalized sub-namespace form for new code.

### Multilingual
`migrations/...create_languages_table` seeds ~33 languages; `RO`, `EN`, `RU` are `ACTIVE`, the rest
`INACTIVE`. `LanguageHelper::getActiveLanguages()` returns active language codes; `languageList()` maps
language code → flag-icon country code. Drive language-aware logic off the `languages` table status,
not hard-coded lists.

### Auditing columns & helpers
Tables carry `created_at/updated_at` plus `created_by/updated_by` (or `added_by/updated_by`) FKs to
`users`, generally `ON DELETE SET NULL`. Other reusable helpers: `DataProviderHelper` (custom
query-string driven pagination via `?page=&limit=`, with redirect-on-out-of-range), `FileHelper`
(upload/replace/delete under `@web`, falling back to `/core/images/no-file.png`), `UrlHelper`
(transliterated slug generation), `RecordHelper` (date/number/list formatting utilities).

## Gotchas

- The helpers are ahead of the rest of the codebase: several reference classes/columns that aren't
  created yet (`app\models\Courses\*`, `app\constants\EntityConstants`, `seo_*_string` columns on
  `pages`). Don't assume a referenced class exists — check before calling.
- `config/db.php` is git-tracked and modified locally; it hard-codes local MySQL credentials.
- `config/web.php` `cookieValidationKey` is committed — fine for local dev only.
