Origin e deploy passam a documentar git.hellomanoel.com; GitHub/GHCR ficam como legado/backup. Co-authored-by: Cursor <cursoragent@cursor.com>
6.6 KiB
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, notartisan 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. ghtalks to GitHub only. Use the Gitea web UI or API for PRs onamare. If you still needghagainst the legacy remote, confirmgh auth statusshowsmanoel-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\Domainuses strict types and neverdd/dump/die.App\Domainnever depends onApp\FilamentorApp\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
localdisk whenFILESYSTEM_DISK=r2, because the S3 driver would make the browser PUT straight to R2 and hit CORS. Final media still lands onr2viaApp\Support\PublicImageUploadRules. SetLIVEWIRE_TEMPORARY_FILE_UPLOAD_DISKexplicitly to override. - Contact form is rate limited: named limiter
contact-briefing, 5/min per IP, registered inAppServiceProviderand applied inroutes/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 inResources/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; seeDESIGN.md).tests/Feature/PublicSite/HeritageEditorialTokensTest.phpreads 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 inresources/js/motion.jsand is asserted bytests/Feature/PublicSite/MotionMarkupTest.php+tests/Browser/MotionTest.php.
Navigating the normative docs
SPEC.mdis the product source of truth and is ~2600 lines. Never read it whole —grep -n '^## ' SPEC.mdand 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.mdfor current capabilities,openspec/changes/<change>/{proposal,design,tasks}.mdfor in-flight work.openspec/config.yamlholds the precedence rule (product owner >SPEC.md> ADRs > tests > conventions) and repo-wide constraints (YAGNI, money as BIGINT centavos, no generic repositories/BaseService).PRODUCT.mdfor positioning,DESIGN.mdfor the design system,docs/conventions/php-strict-types.md,docs/deployment/dokploy.mdfor the deploy runbook.