Botoes acima do prompt que rodam deploy.sh e deploy-fast.sh do Portal Apps sem passar pelo modelo

Este documento define o padrão de arquitetura para o desenvolvimento de novas funcionalidades neste repositório. O objetivo é manter uma base de código organizada, modular e consistente, seguindo os princípios estabelecidos.
A arquitetura é baseada em Módulos do Laravel, onde cada módulo encapsula sua própria lógica de negócios, rotas, controllers, models e views.
Todo novo desenvolvimento deve aderir estritamente aos seguintes princípios:
Um novo módulo (ex: app/Modules/NovoModulo) deve seguir esta estrutura de diretórios:
app/Modules/NovoModulo/ ├── database │ └── migrations/ │ └── 0000_00_00_000000_ExemploMigration.php ├── Http/ │ └── Controllers/ │ └── ExemploController.php ├── Models/ │ └── ExemploModel.php ├── resources/ │ └── views/ │ ├── index.blade.php │ └── create.blade.php ├── routes.php └── NovoModuloServiceProvider.php
Vamos usar como exemplo a criação de um módulo chamado GestorTarefas.
Crie a seguinte estrutura:
app/Modules/GestorTarefas/ ├── database │ └── migrations/ ├── Http/ │ └── Controllers/ ├── Models/ ├── resources/ │ └── views/ ├── routes.php └── GestorTarefasServiceProvider.php
Crie o arquivo app/Modules/GestorTarefas/GestorTarefasServiceProvider.php. Este arquivo é o coração do módulo, responsável por carregar suas rotas e views.
<?php
namespace App\Modules\GestorTarefas;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
class GestorTarefasServiceProvider extends ServiceProvider
{
/**
* Define o namespace do módulo para as views.
* @var string
*/
protected $namespace = 'GestorTarefas';
public function boot()
{
// Carrega as views do módulo com um namespace
// Ex: view('GestorTarefas::index')
$this->loadViewsFrom(__DIR__.'/resources/views', $this->namespace);
// Carrega as migrações do módulo
$this->loadMigrationsFrom(__DIR__ . '/database/migrations');
// Carrega o arquivo de rotas do módulo
Route::middleware('web')
->group(__DIR__ . '/routes.php');
}
public function register()
{
//
}
}
Adicione seu novo provider ao arquivo bootstrap/providers.php:
<?php
return [
App\Providers\AppServiceProvider::class,
App\Providers\VoltServiceProvider::class,
App\Modules\Admin\AdminServiceProvider::class,
App\Modules\DspaceForms\DspaceFormsServiceProvider::class,
App\Modules\GestorTarefas\GestorTarefasServiceProvider::class, // <-- ADICIONAR AQUI
];
Todos os modelos Eloquent específicos deste módulo devem residir em app/Modules/GestorTarefas/Models/.
As migrations continuam globais, no diretório database/migrations/.
Edite o arquivo app/Modules/GestorTarefas/routes.php. Defina um prefixo e um nome de rota para evitar conflitos.
<?php
use Illuminate\Support\Facades\Route;
use App\Modules\GestorTarefas\Http\Controllers\TarefaController;
Route::middleware(['web', 'auth', 'admin']) // Use os middlewares necessários (ex: 'admin')
->prefix('gestor-tarefas') // Prefixo da URL (ex: /gestor-tarefas/...)
->name('gestor-tarefas.') // Prefixo do nome da rota (ex: route('gestor-tarefas.index'))
->group(function () {
Route::get('/', [TarefaController::class, 'index'])->name('index');
Route::get('/criar', [TarefaController::class, 'create'])->name('create');
Route::post('/', [TarefaController::class, 'store'])->name('store');
// Exemplo de rota resource
// Route::resource('tarefas', TarefaController::class);
});
Crie o controller em app/Modules/GestorTarefas/Http/Controllers/TarefaController.php. Siga o padrão de retornar views diretamente.
<?php
namespace App\Modules\GestorTarefas\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Modules\GestorTarefas\Models\Tarefa; // Modelo do módulo
use Illuminate\Http\Request;
class TarefaController extends Controller
{
/**
* Exibe a lista de tarefas.
*/
public function index()
{
// 1. Busca dados usando o Model
$tarefas = Tarefa::where('user_id', auth()->id())->get();
// 2. Retorna a View do módulo, passando os dados
return view('GestorTarefas::index', compact('tarefas'));
}
/**
* Salva uma nova tarefa.
*/
public function store(Request $request)
{
// 1. Validação padrão
$validated = $request->validate([
'titulo' => 'required|string|max:255',
'descricao' => 'nullable|string',
]);
// 2. Lógica de negócios (salvar no banco)
auth()->user()->tarefas()->create($validated); // Exemplo
// 3. Redirecionamento padrão com mensagem de sucesso
return redirect()->route('gestor-tarefas.index')
->with('success', 'Tarefa criada com sucesso.');
}
}
Crie os arquivos Blade em app/Modules/GestorTarefas/resources/views/.
index.blade.php (Exemplo):
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Minhas Tarefas') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<!-- Mensagem de Sucesso -->
@if(session('success'))
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-6 rounded" role="alert">
<p>{{ session('success') }}</p>
</div>
@endif
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900 dark:text-gray-100">
<ul>
@forelse ($tarefas as $tarefa)
<li>{{ $tarefa->titulo }}</li>
@empty
<p>Nenhuma tarefa encontrada.</p>
@endforelse
</ul>
</div>
</div>
</div>
</div>
</x-app-layout>
hooks/register.tsx 51 lines1import type { Register } from 'claude-code'
2
3const deploys = [
4 { key: 'deploy', label: 'Deploy', script: 'deploy.sh' },
5 { key: 'deploy-fast', label: 'Deploy Fast', script: 'deploy-fast.sh' },
6]
7
8export const register: Register = on => {
9 let isBusy = false
10
11 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
12 if (e.props.hasSurvey || !(await $.fs.exists('deploy.sh'))) {
13 return next(e)
14 }
15
16 const { Box, Button, Text } = $.ui.resolve(e)
17
18 const rodar = async (label: string, script: string) => {
19 if (isBusy) {
20 $.ui.toast('Ja existe um deploy em andamento')
21 return
22 }
23 isBusy = true
24 $.ui.status(`Portal: ${label}...`)
25 try {
26 const r = await $.process.run(['bash', `./${script}`], { timeoutMs: 900000 })
27 if (r.exitCode === 0) {
28 $.ui.toast(`Portal ${label}: OK`)
29 } else {
30 const tail = (r.stderr || r.stdout).trim().split('\n').slice(-3).join(' | ')
31 $.ui.toast(`Portal ${label} falhou: ${tail}`)
32 }
33 } catch (err) {
34 $.ui.toast(`Portal ${label}: ${String(err)}`)
35 } finally {
36 isBusy = false
37 $.ui.status(undefined)
38 }
39 }
40
41 return (
42 <Box>
43 <Text dimColor>Deploy: </Text>
44 {deploys.map(d => (
45 <Button key={d.key} label={d.label} onPress={() => rodar(d.label, d.script)} />
46 ))}
47 </Box>
48 )
49 })
50}
51