Skip to content

chore(squads): sync 4.x into feat/squads#404

Merged
gvieira18 merged 17 commits into
feat/squadsfrom
chore/sync-squads-4x
Jul 9, 2026
Merged

chore(squads): sync 4.x into feat/squads#404
gvieira18 merged 17 commits into
feat/squadsfrom
chore/sync-squads-4x

Conversation

@gvieira18

Copy link
Copy Markdown
Member

Why

#402 landed on 4.x (conventions, tooling, tests). This brings the
feat/squads long-lived integration branch up to date so sub-work PR'd
into it inherits the current standards.

What

  • Merge origin/4.x into feat/squads.
  • composer.json: auto-merged to 4.x (correct ^1.0.0 module
    constraints + package bumps); squads adds no new root dependency.
  • composer.lock: took 4.x's lock — no new external deps on this
    branch (squads/onboarding module composer.json unchanged in deps).
  • OnboardingServiceProvider: 4.x relocated it to src/ root per
    the module convention. Kept squads' boot() with loadMigrationsFrom
    because this branch adds real onboarding migrations
    (create_onboardings_table, create_onboarding_steps_table), which
    4.x's empty boot() would fail to load.

Notes

composer validate passes; no conflict markers remain. CI runs on this PR.

fernanduandrade and others added 12 commits July 6, 2026 22:01
## Contexto

A página inicial da comunidade reúne diversos acessos importantes, porém
o link para a documentação (`/docs`) não estava em destaque, o que pode
dificultar que novos membros descobrissem um dos principais recursos da
plataforma.

Este PR adiciona um **Call to Action (CTA)** para a documentação na
landing page da comunidade, tornando o acesso mais visível e
incentivando os usuários a explorarem os guias, tutoriais e demais
conteúdos disponíveis.

### Arquivos afetados

- `app-modules/portal/resources/views/sections/hero.blade.php` —
adiciona um CTA para `/docs` na landing page da comunidade.

### Alterações

- Novo botão/CTA direcionando para `/docs`.
- Ajuste da interface para destacar a documentação como um dos
principais pontos de entrada da comunidade.

### ANTES
<img width="1919" height="866" alt="image"
src="https://github.com/user-attachments/assets/0a40dd21-f36e-4721-93cc-38fba48b6281"
/>


### DEPOIS
<img width="1919" height="868" alt="image"
src="https://github.com/user-attachments/assets/4f68c4ac-ab6d-4771-8dc0-7ac157fbabf2"
/>
## Summary
- Add a caller workflow that reuses
`he4rt/.github/actions/dependabot-automerge` to approve and squash-merge
Dependabot **github-actions** patch/minor PRs. Majors and other
ecosystems stay manual.
- Mirrors how this repo already consumes
`he4rt/.github/actions/auto-assign`.

## Requires
- Org/repo setting **Allow GitHub Actions to create and approve pull
requests** must be enabled (used by the approve step).
Members can attach skills to their profile, each with a proficiency
level and years of experience, chosen from a curated catalog.

- skills catalog (global, seeded inline in the create migration) +
profile_skills pivot (tenant-scoped via profile) with UNIQUE(profile_id,
skill_id) and INDEX(skill_id, proficiency)
- SkillCategory and SkillProficiency enums with pt_BR/en labels
- Skill/ProfileSkill models, Profile relations, per-request memoized
label lookup
- SyncProfileSkills action + ProfileSkillDTO (validates catalog, dedup,
range)
- skills repeater on the profile page with a server-side searched select
(getSearchResultsUsing over name/slug, capped) + preview card rendering
- ADR-0001 documenting the data-modeling decision

---------

Signed-off-by: Daniel Reis <danielhe4rt@gmail.com>
Co-authored-by: Daniel Reis <danielhe4rt@gmail.com>
Co-authored-by: Gabriel Vieira <48625433+gvieira18@users.noreply.github.com>
Signed-off-by: Daniel Reis <danielhe4rt@gmail.com>
Co-authored-by: danielhe4rt <danielhe4rt@gmail.com>
## Contexto

O componente de terminal iniciava com uma altura reduzida e aumentava
gradualmente conforme a animação dos comandos era executada. Esse
comportamento causava mudanças de layout (layout shift), prejudicando a
experiência visual da página.

Este PR corrige a altura inicial do componente para que ela permaneça
estável durante toda a animação.

### Arquivos afetados

- `app-modules/portal/resource/view/components/terminal.blade.php` —
ajuste da altura inicial do componente de terminal.

### Alterações

- Definida uma altura inicial consistente para o terminal.
- Evitado o aumento progressivo da altura durante a animação dos
comandos.
- Reduzido o layout shift, proporcionando uma experiência visual mais
estável.

### ANTES
<img width="1280" height="579" alt="agora"
src="https://github.com/user-attachments/assets/88b02cf5-c854-4073-bc85-31f2e91559aa"
/>


### DEPOIS
<img width="1280" height="579" alt="fix_terminal"
src="https://github.com/user-attachments/assets/942aa745-4780-49cb-bd37-fb61219333a5"
/>
Signed-off-by: Clinton Rocha <50300876+Clintonrocha98@users.noreply.github.com>
Co-authored-by: danielhe4rt <danielhe4rt@gmail.com>
…hi) (#388)

## Summary

- Adiciona selects dinâmicos de **país**, **estado** e **cidade** na
página de perfil (`ProfilePage`), com busca assíncrona e dependência
entre os campos
- Países e estados usam **Sushi** com cache Laravel sob demanda (sync
lazy via jobs); cidades ficam em **Postgres** (`geo_cities`) e são
buscadas na API apenas quando necessário
- Integração com a [World API](https://world.bmbc.cloud/api)
(`WorldApiClient` + `config/geo.php`), sem seedar o mundo inteiro no
banco
- Normaliza colunas de endereço existentes: ISO3 → ISO2, UF brasileira →
nome completo do estado, `state` expandido para 100 chars
- Tooltip na cidade orientando o usuário a pesquisar caso a cidade não
apareça na listagem

## Arquitetura

| Camada | País / Estado | Cidade |
|--------|---------------|--------|
| Modelo | `GeoCountry`, `GeoState` (Sushi) | `GeoCity`
(Eloquent/Postgres) |
| Cache | `GeoSushiStore` (Laravel cache) | tabela `geo_cities` |
| Sync | `SyncWorldCountriesJob`, `SyncWorldStatesJob` |
`SyncWorldCitiesJob` |
| UI | `GeoSelect` (helpers para Filament selects) | busca local + API
com `GeoSearch` (ignora acentos) |

## Migrations

- `2026_07_07_180000_create_geo_tables.php` — cria `geo_cities`
- `2026_07_07_180001_normalize_address_location_columns.php` — normaliza
dados legados em `addresses`

## Config

```env
GEO_WORLD_API_URL=https://world.bmbc.cloud/api

Test plan
 

- [ ] Abrir perfil e verificar preload de países

 - [ ] Selecionar país → estados carregam; selecionar estado → cidades do cache aparecem
 - [ ] Buscar cidade com/sem acento (ex.: sao → São Paulo)
 - [ ] Salvar perfil e confirmar persistência em addresses (country ISO2, state nome, city nome)
 - [ ] Rodar php artisan test tests/Feature/Geo tests/Feature/AddressTest.php app-modules/panel-app/tests/Feature/ProfilePageTest.php

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: danielhe4rt <danielhe4rt@gmail.com>
Co-authored-by: BrunaDomingues <bruna@users.noreply.github.com>
## Problema

O feed da timeline retorna **500** com `Attempt to read property "name"
on null` em
`panel-app/resources/views/components/timeline/header.blade.php` sempre
que o autor de um post resolve para `null`. Como o feed renderiza todos
os posts, **um único post órfão derruba a página inteira** para todos.

## Causa raiz — merge de contas

Quando duas contas são mergeadas, `MergeAccountsAction` reatribui
`ExternalIdentity` e tenants para a conta sobrevivente e faz **hard
delete** da conta perdedora — mas **nunca reatribui
`activity_timeline.user_id`**. Não existe FK nessa coluna, então os
posts da conta mergeada ficam órfãos e o feed quebra.

```
 MergeAccountsAction (identity)                 activity module
   reatribui ExternalIdentity + tenants
   event(AccountsMerged(survivor, merged)) ──►  ReassignTimelineOwnership (listener)
   currentUser->delete()                         UPDATE activity_timeline
                                                 SET user_id = survivor
                                                 WHERE user_id = merged
```

## Fix — 3 camadas (defense-in-depth)

1. **Merge (causa raiz):** novo evento `AccountsMerged` disparado dentro
da transação do merge; listener em `activity` reatribui as linhas da
timeline para o sobrevivente. **Preserva os posts** e previne órfãos
futuros. Feito via evento para não criar dependência circular entre
módulos (`activity` já depende de `identity`). `activity_reactions` não
tem `user_id`, então a timeline é a única tabela a reatribuir.
2. **Filtro do feed:** `TimelineFeed` usa `whereHas('user')` para
blindar o feed contra os **órfãos que já existem em prod** (o mapeamento
id-antigo→novo se perdeu no hard delete e não dá pra reatribuir
automaticamente).
3. **View guard:** `header`/`post-show` toleram autor null e mostram
"Usuário removido" em vez de quebrar.

## Testes

22/22 verdes (3 novos + os existentes de timeline/merge):
- `MergeAccountsActionTest` — merge reatribui os posts ao sobrevivente
(exercita evento→listener ponta a ponta).
- `TimelineFeedQueryTest` — feed exclui posts de autor inexistente.
- `ThreadPageTest` — `PostShow` renderiza sem quebrar quando o autor foi
deletado.

## Observação

Os órfãos **já existentes** em produção continuam no banco — o filtro só
os esconde do feed. Uma limpeza/reatribuição retroativa precisaria de
uma fonte pro mapeamento (logs / `ExternalIdentity`) e fica fora deste
PR.
## Summary

- Corrige visibilidade do círculo de iniciais no dark mode (header e
preview card do perfil)
- Evita que o hover de upload da capa fique por cima do avatar
- Melhora visibilidade do avatar no menu lateral no dark mode
- Adiciona borda discreta na sidebar, no mesmo peso das bordas dos
inputs do form


**Antes:** no dark mode, o círculo das iniciais quase sumia no perfil; o
hover de upload da capa cobria parte do avatar; o avatar do menu lateral
ficava sem contorno visível; e não havia separação clara entre sidebar e
conteúdo.
<img width="1906" height="907" alt="Captura de tela 2026-07-08 131101"
src="https://github.com/user-attachments/assets/bfa3d0d3-0975-4d3d-b1d6-f02cc1ff067e"
/>

**Depois:** iniciais com borda/ring visível no header e no preview card;
avatar sempre acima do hover da capa; contorno discreto no avatar do
menu lateral; e borda suave na sidebar, no mesmo peso das bordas dos
inputs do form.

<img width="1906" height="911" alt="Captura de tela 2026-07-08 130813"
src="https://github.com/user-attachments/assets/5faa3fc0-7819-4aa6-9d91-552868f72c5f"
/>

## Commits

1. `fix(profile): keep initials avatar visible in dark mode preview
card`
2. `fix(profile): keep initials avatar visible in dark mode header`
3. `fix(profile): keep avatar above cover upload hover overlay`
4. `fix(panel): keep sidebar user avatar visible in dark mode`
5. `style(panel): add subtle sidebar border` *(fácil de reverter
isoladamente se necessário)*

## Test plan

- [ ] Abrir `/app/{tenant}/profile` em light e dark mode
- [ ] Sem foto: conferir se o círculo com iniciais aparece no header e
no preview card
- [ ] Passar o mouse na capa: hover não deve cobrir o avatar
- [ ] No menu lateral: avatar do usuário visível no dark mode
- [ ] Conferir se a borda da sidebar está discreta (similar aos inputs
do form)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
> 📄 <strong><a
href="https://waifuvault.moe/f/b2e0aef7-16c7-4c95-9dcf-7e51626f7ddb.html"
target="_blank" rel="noopener noreferrer">Visual overview of this
PR</a></strong> — one-screen interactive summary of every change.

> [!NOTE]
> **Why `tests/.pest/shards.json` is committed — it's intentional.**
Pest v4.6.0 balances the suite across shards using recorded per-test
timings. Committing this baseline (instead of regenerating it every run)
makes the split **deterministic and evenly balanced from the first CI
run** — no warm-up pass and no cross-run artifact upload to wire up.
It's refreshed automatically as the suite grows. See [Time-based
sharding in Pest
v4.6.0](https://laravel-news.com/time-based-sharding-in-pest-v4-6-0).

## Summary
- **Guidelines** — sync AI guidelines to he4rt conventions
(namespace/naming, issue-tracker repo `he4rt/heartdevs.com`, added
typed-JSON-cast + enum-contract guidance); drop 3 stale `docs/agents/*`
mirrors.
- **Modular** — fix `make:module` stubs + `config/app-modules.php` so a
module's ServiceProvider scaffolds at `src/` root (not `Providers/`);
migrate `squads` and `onboarding` to match.
- **Testing DX** — add tracked `.env.testing.example`, untrack the
per-dev `.env.testing`, bootstrap it via `post-root-package-install`;
use `LazilyRefreshDatabase` for feature tests.
- **CI** — run the Pest suite in 2 balanced shards (committed timings
baseline); gate the pipeline on canonical branch prefixes (`feature/**`,
`bugfix/**`, `chore/**`, `story/**`, `*.x`).
- **Deps** — pin intra-repo `he4rt/*` modules to `^1.0.0`; bump
dependencies.
- **Refactor** — apply the Rector named-argument convention across
models, commands, jobs and Livewire components.
- **Cleanup** — remove 24 redundant `.gitkeep` placeholders.

## Test plan
- [ ] `composer check` — Rector, Pint, PHPStan all clean
- [ ] `php artisan test` — 881 pass (539 feature + 342 unit, 2515
assertions)
- [ ] Fresh clone: `make setup` creates `.env.testing`; `make
setup-test-db` migrates it
- [ ] Scaffolding a new module places its ServiceProvider at `src/` root
Merge origin/4.x to pick up #402 (conventions, tooling, tests).
Kept onboarding ServiceProvider boot() with loadMigrationsFrom
(squads adds real onboarding migrations); took 4.x composer.lock
(no new external deps on this branch).
@gvieira18 gvieira18 requested a review from a team July 9, 2026 15:57
gvieira18 added 5 commits July 9, 2026 13:35
Named-argument attributes (ExplicitAttributeNamedArgsRector) on the
squads and onboarding models, per the stricter tooling merged from 4.x.
Source stub referenced by config/app-modules.php for the placeholder
files internachi/modular writes into every new module's tests and
database dirs. #402 removed it on 4.x, which breaks make:module.
Arquivo-fonte referenciado por config/app-modules.php para os
placeholders .gitkeep que o internachi/modular copia para cada novo
módulo (tests e database). O #402 removeu o arquivo, o que quebrava o
comando make:module ao tentar copiar um stub inexistente.
Regenerate the shard timing manifest so every discovered test class has
an entry, clearing the '[tests/.pest/shards.json] is out of date' warning
introduced when the branch's new tests merged with 4.x's shard plugin.

@DiogoKaster DiogoKaster left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@GustavoSimao GustavoSimao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@stherzada

Copy link
Copy Markdown
Contributor

lgtm

@gvieira18 gvieira18 merged commit bd219d5 into feat/squads Jul 9, 2026
8 checks passed
@gvieira18 gvieira18 deleted the chore/sync-squads-4x branch July 9, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants