# Citrus — Sistema de Gestão de Diárias

Gestão de pagamento de diárias de trabalhadores MEI em obras da Citrus Engenharia.
Fluxo central: líderes registram presença diária → financeiro fecha cards quinzenais → relatórios.
Spec completa de requisitos: `Citrus_Requisitos_v1.0.docx.md` (leia antes de mexer em regra de negócio).

## Stack
Docker + PHP 8.2 + Yii2 (yii2-app-basic) + MySQL 8 + Bootstrap 5. Mobile-first. Idioma `pt-BR`.

## Como rodar
Tudo roda **dentro do container `php`** (o `php` local da máquina é 7.4 e quebra: o projeto exige ≥8.2).

```bash
cp .env.example .env                              # ajuste as senhas
cp config/secrets.example.php config/secrets.php  # preencha cookieValidationKey
docker compose up -d                              # sobe nginx(:8082) + php + mysql(:3308)
docker compose exec php composer install
docker compose exec php ./yii migrate             # aplica migrations
docker compose exec php vendor/bin/codecept run   # roda toda a suíte
```

- App: http://localhost:8082
- Suítes: `Unit` e `Functional` (capitalizadas) — ex.: `codecept run Unit`. Functional precisa do banco `citrus_test` (criado via root).
- Sem Docker, use um binário 8.2+ explícito (ex.: `/opt/homebrew/opt/php/bin/php vendor/bin/codecept run Unit`). NÃO use o `php` do PATH.
- `.env` a partir de `.env.example`.

## Arquitetura e convenções (siga os padrões existentes)

**Models de negócio estendem `app\models\BaseActiveRecord`**, que já provê:
- Soft-delete: `delete()` seta `deleted_at` (NUNCA exclusão física). Toda tabela de negócio tem `created_at`, `updated_at`, `deleted_at` (inteiros).
- `find()` retorna `SoftDeleteQuery` — registros deletados já saem filtrados por padrão.
- Auditoria automática (`AuditBehavior`) grava create/update/delete em `auditoria`.
- Timestamps automáticos (`TimestampBehavior`).
- Normalização monetária em `beforeValidate()`: sobrescreva `moneyAttributes()` retornando os campos `Monetário`. Eles chegam mascarados (`R$ 1.234,56`) e são convertidos para decimal (`1234.56`) antes da validação `number`.

**Controllers** (ver `FuncaoController` como referência): `declare(strict_types=1)`, behaviors com `PermissaoBehavior` (access) + `VerbFilter` (delete só POST), padrão `actionIndex/Create/Update/Delete/Export`, `findModel()` lançando `NotFoundHttpException`, flash messages em pt-BR.

**Permissões**: `PermissaoBehavior` checa a tabela `permissao` por (`tela`=controller id, `acao`=action id). Sem tela de edição na v1.0. Perfis: Profissional (sem login), Líder, Gerente, Administrativo — acumuláveis.

**Listagens**: `*Search` model + `GridView`/`dataProvider`. Toda listagem tem export Excel via `ExportHelper::download($nome, $headers, $rows)`.

**Máscaras de input** (`web/js/mask.js`, registrado em `AppAsset`):
- Padrão fixo: `data-mask="###.###.###-##"` (CPF, CNPJ, WhatsApp, CEP).
- Monetário: `data-mask-money` + `inputmode="numeric"`. No campo do ActiveForm use `['enableClientValidation' => false]` (a string `R$ ...` reprovaria no validador client `number`; o servidor valida após normalizar).

**Migrations**: nomeadas `mYYMMDD_NNNNNN_create_<tabela>_table.php`.

## Segredos
Fonte única em `config/secrets.php` (gitignored; template em `config/secrets.example.php`): `cookieValidationKey` + credenciais de banco (lidas do `.env` via `getenv`). `db.php`, `test_db.php` e `web.php` leem dele. Nunca versione segredo nem hardcode em arquivo versionado.

## Não faça
- Não regenere `cookieValidationKey` (em `config/secrets.php`) — é fixo de propósito; mudá-lo quebra sessão/CSRF.
- Não use exclusão física nem ignore o soft-delete.
- Não rode `composer`/`yii`/`codecept` com o PHP 7.4 do PATH.
- Não duplique regra de negócio aqui — a fonte é o doc de requisitos.
