Origin e deploy passam a documentar git.hellomanoel.com; GitHub/GHCR ficam como legado/backup. Co-authored-by: Cursor <cursoragent@cursor.com>
78 lines
6.6 KiB
Markdown
78 lines
6.6 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
@AGENTS.md
|
|
|
|
If the import above did not load, read `AGENTS.md` at the repo root now — it is the primary contract.
|
|
|
|
`AGENTS.md` (imported above) is the primary contract: structure, commands, style, testing, husky hooks, commit/PR rules. This file records the cross-file architecture and environment facts that are not obvious from any single file.
|
|
|
|
## Non-negotiables (repeated from AGENTS.md because breaking them is expensive)
|
|
|
|
- Never modify or commit from the primary working tree on `main`. Create a worktree per branch: `git worktree add -b <branch> <path> main`.
|
|
- Every project-owned PHP file starts with `declare(strict_types=1);` immediately after `<?php`.
|
|
- Browser tests are CI-only (they run against a FrankenPHP container built by `docker build`, not `artisan serve`).
|
|
|
|
## Design principles: DRY & YAGNI (not TDD)
|
|
|
|
Write for the problem at hand, not an imagined future. **DRY**: extract and reuse only once logic is genuinely duplicated in more than one place. **YAGNI**: no speculative abstraction, configurability, or layers — add them only when a concrete requirement demands it. Prefer the simplest thing that solves the current requirement; avoid over-engineering and premature extraction. Tests are verification, not a design driver: write them to cover behavior already implemented, not as a front-loaded TDD ceremony.
|
|
|
|
## Environment note
|
|
|
|
PHP and Composer are **not on PATH** in this environment, and `vendor/` and `node_modules/` are absent. Every `composer …` / `php artisan …` command in `AGENTS.md` and `README.md` assumes a PHP 8.4+ runtime with Composer 2 installed. Verify the toolchain before promising a command ran.
|
|
|
|
## Git remotes — Gitea origin, GitHub legacy
|
|
|
|
`origin` is `git@git.hellomanoel.com:manoel-freitas/amare.git` (self-hosted Gitea). CI/CD and the container registry live there (`git.hellomanoel.com`). Verify SSH with `ssh -T git@git.hellomanoel.com` → should greet `Hi there, manoel-freitas!`.
|
|
|
|
The remote named `github` is the legacy mirror `git@github.com:manoel-freitas/amore-site.git`. Push there only when intentionally syncing the backup. That GitHub account still needs `~/.ssh/id_github_pessoal` (or an equivalent key) when the machine's default identity is a different GitHub user (`manoel-freitas-neto`) that cannot see the repo.
|
|
|
|
- Prefer plain `git push` / `git push origin <branch>` against Gitea.
|
|
- **`gh`** talks to GitHub only. Use the Gitea web UI or API for PRs on `amare`. If you still need `gh` against the legacy remote, confirm `gh auth status` shows `manoel-freitas`.
|
|
|
|
## Request spine for the public site
|
|
|
|
Adding or changing a public page follows one path — controllers never query models directly:
|
|
|
|
```
|
|
routes/web.php
|
|
→ App\Http\Controllers\PublicSite\*Controller (thin; injects a query object)
|
|
→ App\Application\Queries\Marketing\* (invokable, final; owns all Eloquent access)
|
|
→ App\Application\Data\* (DTO: HomeContent, PageMeta)
|
|
→ resources/views/pages/*.blade.php
|
|
```
|
|
|
|
`HomeController` + `GetHomeContent` together show the shape. Page-level SEO is built with `PageMeta::forPage(canonical:, settings:, jsonLd:)`.
|
|
|
|
`AppServiceProvider::boot()` registers a **View composer on `layouts.public`** that auto-injects `siteSettings` and `pageMeta` when the view didn't supply them — new pages do not have to pass them manually.
|
|
|
|
Site-wide content is a singleton row reached via `SiteSetting::instance()`. Publication state comes from the `HasPublication` concern (`->published()` scope).
|
|
|
|
## Architecture boundary — what is actually enforced
|
|
|
|
`tests/Architecture/DomainBoundariesTest.php` enforces only:
|
|
|
|
- `App\Domain` uses strict types and never `dd`/`dump`/`die`.
|
|
- `App\Domain` never depends on `App\Filament` or `App\Livewire`.
|
|
|
|
`App\Application` is **not** covered by that rule. `app/Domain/` currently holds a single placeholder (`DomainModule.php`); business reads live in `app/Application/Queries`. Extend the arch test when you add a boundary.
|
|
|
|
## Deterministic test support
|
|
|
|
`APP_FROZEN_NOW` configures `CarbonImmutable::setTestNow()` through `AppServiceProvider::freezeClockWhenConfigured()` outside production. `VisualContentSeeder` provides deterministic image/content fixtures for tests that explicitly need them. Neither setting is a browser-CI global default.
|
|
|
|
## Other things that bite
|
|
|
|
- **Livewire/Filament temp uploads are pinned to the `local` disk** when `FILESYSTEM_DISK=r2`, because the S3 driver would make the browser PUT straight to R2 and hit CORS. Final media still lands on `r2` via `App\Support\PublicImageUploadRules`. Set `LIVEWIRE_TEMPORARY_FILE_UPLOAD_DISK` explicitly to override.
|
|
- **Contact form is rate limited**: named limiter `contact-briefing`, 5/min per IP, registered in `AppServiceProvider` and applied in `routes/web.php`.
|
|
- **Filament 5 nested resource layout**: resources are split into `app/Filament/Resources/<Resource>/{Pages,Schemas,Tables,RelationManagers}` rather than a flat resource class. Follow the existing shape in `Resources/PortfolioCases/`.
|
|
- **Everything user-facing is pt-BR**: routes are `/servicos`, `/portfolio`, `/portfolio/{slug}`, `/sobre`, `/privacidade`, `/contato`. `APP_LOCALE=pt_BR`, `APP_TIMEZONE=America/Sao_Paulo` (`config/app.php:68`).
|
|
- **Design tokens** live in `resources/css/tokens.css` (Heritage Editorial; see `DESIGN.md`). `tests/Feature/PublicSite/HeritageEditorialTokensTest.php` reads that file and asserts the exact hex values, `EB Garamond`, zero border radii, `--amare-container-max: 1120px`, and the *absence* of shadow tokens — so any token edit is a deliberate test change too. Motion lives in `resources/js/motion.js` and is asserted by `tests/Feature/PublicSite/MotionMarkupTest.php` + `tests/Browser/MotionTest.php`.
|
|
|
|
## Navigating the normative docs
|
|
|
|
- `SPEC.md` is the product source of truth and is ~2600 lines. **Never read it whole** — `grep -n '^## ' SPEC.md` and read the numbered section you need (e.g. 7 functional requirements, 8 domain model/DB, 9 technical architecture, 13 test strategy, 15 FrankenPHP deploy).
|
|
- `openspec/` is the channel for planned change: `openspec/specs/<capability>/spec.md` for current capabilities, `openspec/changes/<change>/{proposal,design,tasks}.md` for in-flight work. `openspec/config.yaml` holds the precedence rule (product owner > `SPEC.md` > ADRs > tests > conventions) and repo-wide constraints (YAGNI, money as BIGINT centavos, no generic repositories/BaseService).
|
|
- `PRODUCT.md` for positioning, `DESIGN.md` for the design system, `docs/conventions/php-strict-types.md`, `docs/deployment/dokploy.md` for the deploy runbook.
|