feat(profile): endpoint mobile de leitura do perfil (Feature 3) - #566
tecrodrigocastro wants to merge 8 commits into
Conversation
Guard "api" (php-open-source-saver/jwt-auth): endpoints de redirect/callback OAuth (Discord/GitHub/Twitch) que devolvem um código de troca de uso único via deep link, GET /api/mobile/me, refresh e logout. Implementa a Feature 0 de docs/plans/2026-09-22-api-mobile-jwt.md. Refs he4rt#531
… contra a app real
Achados testando os endpoints de verdade (não só Pest):
- Discord/GitHub/Twitch só conhecem UMA redirect_uri fixa por app, o
callback web (/auth/oauth/{provider}). MobileOAuthController::callback
nunca seria chamado de verdade. O callback web agora distingue o login
mobile via OAuthIntent::MobileLogin (lido do state) e finaliza com
código de troca + deep link em vez de duplicar rota de callback.
- Qualquer request pra rota auth:api sem "Accept: application/json" dava
500 em vez de 401: o middleware padrão tenta redirect(route('login')),
que este app não tem (login é só OAuth). Fix em bootstrap/app.php.
Suíte inteira (1749 testes) verde depois da mudança global.
Marca rotas auth:* como bearer na doc (scramble.security_strategy — não vinha configurado) e adiciona resumo/descrição nos endpoints mobile pro Stoplight Elements em /docs/3.x/api. Tipa o retorno de MobileTokenDTO::toArray() como array-shape pra schema de resposta mais preciso. Verificado contra o /docs/3.x/swagger.json gerado: os 5 endpoints aparecem, com bearer marcado corretamente em /me, /logout e no default do documento (redirect e exchange ficam públicos, como deveria).
O módulo he4rt/docs nasceu (he4rt#123) quando a branch principal do repo ainda era 3.x — a string ficou hardcoded em 5 lugares e nunca acompanhou o bump pra 4.x. Move resources/docs/3.x pro caminho novo, atualiza Documentation.php, DocsServiceProvider.php, config/docs.php e config/scramble.php, e o teste que trava a URL do Scramble. /docs/4.x/api agora serve a doc da API mobile gerada nesta branch.
…bit) Cache::pull() é get()+forget() como duas chamadas separadas — duas requisições concorrentes com o mesmo código podiam ambas ler o valor antes de qualquer uma apagar, mintando dois tokens da mesma autorização (CWE-367). ExchangeMobileCodeAction agora serializa leitura+remoção com Cache::lock(). Atualiza o plano com o contrato real (refresh usa o mesmo JWT, sem refresh_token separado; não existe rota de callback mobile própria) e documenta como débito técnico conhecido o outro achado da revisão: o deep link por custom scheme pode ser sequestrado por outro app no aparelho — a correção certa é PKCE, mas depende do he4rt-app também mudar, então não é fechada nesta PR.
- Remove comentário narrativo e o returnUrl 'mobile' morto — o fluxo mobile nunca chega a ler returnUrl, então null (já aceito pelo tipo) é mais honesto que uma string mágica sem uso. - getAuthenticate: centraliza a checagem de OAuthIntent::MobileLogin numa variável ($isMobile) calculada uma vez em vez de repetida em 3 pontos do método.
GET /api/mobile/profile retorna o perfil do usuário autenticado (profissional, skills e experiências), via ProfileResource. v1 só leitura, conforme o PRD. Depende da story/531-api-mobile-auth-jwt (guard JWT `api`).
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Central YAML (inherited) Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (40)
Files not reviewed due to moderation or processing errors (29)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughAdds JWT-backed mobile authentication through OAuth, including short-lived exchange codes, token exchange, refresh, logout, and current-user endpoints. Adds an authenticated mobile profile endpoint with serialized profile, skill, and work-experience data. Adds JWT and deep-link configuration, exception handling, and feature tests. Updates API documentation configuration, routes, tests, and examples from 3.x to 4.x. Priority: ⬇️ Low Estimated code review effort: Suggested reviewers: Change: Feature Merge Risk: 🔵 Low · up to The profile endpoint has no established blocking issue in the supplied evidence. The mobile OAuth handoff still warrants coordination with the app before rollout because custom-scheme links may be intercepted. Security Architecture ReviewSecurity architecture risk: 🟠 High · up to The new mobile sign-in flow sends a short-lived login code through a configurable app link. If another app receives that link, it could exchange the code for the user’s token. The example cache setting also does not provide the shared storage this authentication flow needs. The actual mobile-link handling and production cache settings remain unverified. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 32.26% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 30 files. (6 skipped: 6 unsupported.)
Warning Review coverage is incomplete: 29 files could not be fully reviewed. Findings from completed review steps are included; see review info for details. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Warning
Draft — não revisar ainda. O diff mostra 41 arquivos / ~1700 linhas porque esta branch está empilhada em cima da
story/531-api-mobile-auth-jwt(#565), que ainda não está na4.x. O escopo real desta PR é só 4 arquivos novos do móduloprofile(controller, resource, rota, teste) — veja a lista abaixo. Assim que a #565 mergear, o GitHub recalcula o diff sozinho e esta PR passa a mostrar só isso. Vou tirar do draft nesse momento.Depende da #565 (merge primeiro)
Não mergear antes da #565.
Escopo real (o que muda de fato)
app-modules/profile/routes/api-mobile-routes.php(novo)app-modules/profile/src/Http/Controllers/Mobile/MobileProfileController.php(novo)app-modules/profile/src/Http/Resources/ProfileResource.php(novo)app-modules/profile/tests/Feature/Http/MobileProfileControllerTest.php(novo)docs/plans/2026-09-22-api-mobile-jwt.md(2 linhas, marca a Feature 3 como implementada)Summary
Feature 3 do plano (
docs/plans/2026-09-22-api-mobile-jwt.md): endpoint de leitura do perfil do usuário autenticado para o app mobile.GET /api/mobile/profile(atrás deauth:api) retorna o perfil viaProfileResource: dados profissionais (nickname, headline, seniority, anos de experiência, about, social_links), disponibilidade/preferências, skills e experiências profissionais.MobileProfileControllerreaproveitaProfile::ensureExists(auth()->id()), já usado no resto do domínio.ResourceResponsepadrão do Laravel: quando o profile é criado na hora (primeiro acesso), ele devolveria201numa rotaGET— forçado200explicitamente.Test plan
vendor/bin/pint --dirtyvendor/bin/phpstan analyse app-modules/profile/src --memory-limit=1G(0 erros)vendor/bin/pest app-modules/profile/tests(73 testes passando, incluindo os 3 novos do endpoint)ProfileResourceconferido)