first-deploy #72

Merged
kilder merged 12 commits from first-deploy into master 2026-01-13 17:54:12 +00:00
44 changed files with 7690 additions and 1484 deletions
Showing only changes of commit a94ec86349 - Show all commits

View File

@@ -29,7 +29,7 @@ jobs:
file: ./apps/web/Dockerfile
# Only push on 'push' event (merge to master), not on 'pull_request'
push: ${{ github.event_name == 'push' }}
tags: killercf/sgc:latest
tags: sgsedevs/sgse-app:latest
platforms: linux/amd64
build-args: |
PUBLIC_CONVEX_URL=${{ secrets.PUBLIC_CONVEX_URL }}

View File

@@ -3,6 +3,7 @@
import { useConvexClient, useQuery } from 'convex-svelte';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { SvelteMap } from 'svelte/reactivity';
import {
Package,
AlertTriangle,
@@ -23,8 +24,8 @@
// Criar mapa de materiais para lookup eficiente
const materiaisMap = $derived.by(() => {
if (!materiaisQuery.data) return new Map();
const map = new Map();
if (!materiaisQuery.data) return new SvelteMap();
const map = new SvelteMap();
for (const material of materiaisQuery.data) {
map.set(material._id, material);
}
@@ -41,7 +42,7 @@
}
const produtos = ultimosProdutosQuery.data;
// Ordenar do mais antigo para o mais recente (para o gráfico)
const produtosOrdenados = [...produtos].reverse();
@@ -56,7 +57,7 @@
'#f43f5e', // red
'#fb7185', // pink-400
'#f87171', // red-400
'#fb923c' // orange-400
'#fb923c' // orange-400
];
return {
@@ -89,14 +90,12 @@
<!-- Cabeçalho -->
<div class="mb-8">
<div class="mb-4 flex items-center gap-4">
<div class="rounded-2xl bg-gradient-to-br from-primary/20 to-primary/30 p-4 shadow-lg">
<Package class="h-10 w-10 text-primary" strokeWidth={2.5} />
<div class="from-primary/20 to-primary/30 rounded-2xl bg-gradient-to-br p-4 shadow-lg">
<Package class="text-primary h-10 w-10" strokeWidth={2.5} />
</div>
<div>
<h1 class="text-primary mb-2 text-4xl font-bold tracking-tight">Almoxarifado</h1>
<p class="text-base-content/70 text-lg">
Controle de estoque e gestão de materiais
</p>
<p class="text-base-content/70 text-lg">Controle de estoque e gestão de materiais</p>
</div>
</div>
</div>
@@ -108,69 +107,77 @@
</div>
{:else if statsQuery.data}
<div class="mb-8 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4">
<div class="card bg-gradient-to-br from-primary/10 via-primary/5 to-base-100 border border-primary/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-primary/10 via-primary/5 to-base-100 border-primary/20 border bg-gradient-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Total de Materiais</div>
<div class="text-3xl font-bold text-primary mb-1">
<div class="text-base-content/60 mb-1 text-sm font-medium">Total de Materiais</div>
<div class="text-primary mb-1 text-3xl font-bold">
{statsQuery.data.totalMateriais}
</div>
<div class="text-xs text-base-content/50">Materiais cadastrados</div>
<div class="text-base-content/50 text-xs">Materiais cadastrados</div>
</div>
<div class="rounded-xl bg-primary/20 p-3">
<Package class="h-8 w-8 text-primary" strokeWidth={2.5} />
<div class="bg-primary/20 rounded-xl p-3">
<Package class="text-primary h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
</div>
<div class="card bg-gradient-to-br from-success/10 via-success/5 to-base-100 border border-success/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-success/10 via-success/5 to-base-100 border-success/20 border bg-gradient-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Materiais Ativos</div>
<div class="text-3xl font-bold text-success mb-1">
<div class="text-base-content/60 mb-1 text-sm font-medium">Materiais Ativos</div>
<div class="text-success mb-1 text-3xl font-bold">
{statsQuery.data.totalMateriaisAtivos}
</div>
<div class="text-xs text-base-content/50">Em estoque</div>
<div class="text-base-content/50 text-xs">Em estoque</div>
</div>
<div class="rounded-xl bg-success/20 p-3">
<CheckCircle2 class="h-8 w-8 text-success" strokeWidth={2.5} />
<div class="bg-success/20 rounded-xl p-3">
<CheckCircle2 class="text-success h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
</div>
<div class="card bg-gradient-to-br from-warning/10 via-warning/5 to-base-100 border border-warning/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-warning/10 via-warning/5 to-base-100 border-warning/20 border bg-gradient-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Alertas Ativos</div>
<div class="text-3xl font-bold text-warning mb-1">
<div class="text-base-content/60 mb-1 text-sm font-medium">Alertas Ativos</div>
<div class="text-warning mb-1 text-3xl font-bold">
{statsQuery.data.totalAlertasAtivos}
</div>
<div class="text-xs text-base-content/50">Estoque baixo</div>
<div class="text-base-content/50 text-xs">Estoque baixo</div>
</div>
<div class="rounded-xl bg-warning/20 p-3">
<AlertTriangle class="h-8 w-8 text-warning" strokeWidth={2.5} />
<div class="bg-warning/20 rounded-xl p-3">
<AlertTriangle class="text-warning h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
</div>
<div class="card bg-gradient-to-br from-info/10 via-info/5 to-base-100 border border-info/20 shadow-xl hover:shadow-2xl transition-all duration-300 hover:scale-105">
<div
class="card from-info/10 via-info/5 to-base-100 border-info/20 border bg-gradient-to-br shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
>
<div class="card-body">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-base-content/60 mb-1">Movimentações</div>
<div class="text-3xl font-bold text-info mb-1">
<div class="text-base-content/60 mb-1 text-sm font-medium">Movimentações</div>
<div class="text-info mb-1 text-3xl font-bold">
{statsQuery.data.movimentacoesMes}
</div>
<div class="text-xs text-base-content/50">Este mês</div>
<div class="text-base-content/50 text-xs">Este mês</div>
</div>
<div class="rounded-xl bg-info/20 p-3">
<ArrowLeftRight class="h-8 w-8 text-info" strokeWidth={2.5} />
<div class="bg-info/20 rounded-xl p-3">
<ArrowLeftRight class="text-info h-8 w-8" strokeWidth={2.5} />
</div>
</div>
</div>
@@ -180,11 +187,11 @@
<!-- Gráfico de Produtos x Quantidades -->
<div class="mb-8">
<div class="card bg-base-100 border border-base-300 shadow-xl">
<div class="card bg-base-100 border-base-300 border shadow-xl">
<div class="card-body">
<h2 class="card-title text-2xl mb-4">
<div class="rounded-lg bg-primary/20 p-2">
<BarChart3 class="h-6 w-6 text-primary" />
<h2 class="card-title mb-4 text-2xl">
<div class="bg-primary/20 rounded-lg p-2">
<BarChart3 class="text-primary h-6 w-6" />
</div>
<span>Últimos 10 Produtos Cadastrados</span>
</h2>
@@ -196,7 +203,7 @@
<div class="w-full">
<BarChart3D data={chartData} height={400} />
</div>
<div class="mt-4 text-sm text-base-content/60">
<div class="text-base-content/60 mt-4 text-sm">
<p>Mostrando os últimos 10 produtos cadastrados ordenados por data de criação</p>
</div>
{:else}
@@ -211,11 +218,11 @@
<!-- Alertas Recentes -->
<div class="mb-8">
<div class="card bg-base-100 border border-base-300 shadow-xl">
<div class="card bg-base-100 border-base-300 border shadow-xl">
<div class="card-body">
<h2 class="card-title text-2xl mb-1">
<div class="rounded-lg bg-warning/20 p-2">
<AlertTriangle class="h-6 w-6 text-warning" />
<h2 class="card-title mb-1 text-2xl">
<div class="bg-warning/20 rounded-lg p-2">
<AlertTriangle class="text-warning h-6 w-6" />
</div>
<span>Alertas de Estoque</span>
</h2>
@@ -225,7 +232,7 @@
</div>
{:else if alertasQuery.data && alertasQuery.data.length > 0}
<div class="overflow-x-auto">
<table class="table table-zebra">
<table class="table-zebra table">
<thead>
<tr class="bg-base-200">
<th class="font-semibold">Material</th>
@@ -236,13 +243,13 @@
</tr>
</thead>
<tbody>
{#each alertasQuery.data.slice(0, 5) as alerta}
{#each alertasQuery.data.slice(0, 5) as alerta (alerta._id)}
{@const material = materiaisMap.get(alerta.materialId)}
<tr class="hover:bg-base-200/50 transition-colors">
<td>
<div class="font-medium">{material?.nome || 'Carregando...'}</div>
{#if material?.codigo}
<div class="text-xs text-base-content/50 font-mono">{material.codigo}</div>
<div class="text-base-content/50 font-mono text-xs">{material.codigo}</div>
{/if}
</td>
<td>
@@ -255,7 +262,7 @@
{/if}
</td>
<td>
<span class="font-bold text-error">{alerta.quantidadeAtual}</span>
<span class="text-error font-bold">{alerta.quantidadeAtual}</span>
</td>
<td>
<span class="font-medium">{alerta.quantidadeMinima}</span>
@@ -273,11 +280,8 @@
</tbody>
</table>
</div>
<div class="card-actions justify-end mt-4">
<button
class="btn btn-primary"
onclick={() => goto('/almoxarifado/alertas')}
>
<div class="card-actions mt-4 justify-end">
<button class="btn btn-primary" onclick={() => goto('/almoxarifado/alertas')}>
Ver Todos os Alertas
</button>
</div>
@@ -294,64 +298,63 @@
<!-- Ações Rápidas -->
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4">
<button
class="card bg-base-100 border border-base-300 shadow-xl hover:shadow-2xl hover:border-primary/50 transition-all duration-300 hover:scale-[1.02] group"
class="card bg-base-100 border-base-300 hover:border-primary/50 group border shadow-xl transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl"
onclick={() => goto('/almoxarifado/materiais/cadastro')}
>
<div class="card-body">
<div class="flex items-center gap-4 mb-2">
<div class="rounded-xl bg-primary/20 p-3 group-hover:bg-primary/30 transition-colors">
<Package class="h-7 w-7 text-primary" strokeWidth={2.5} />
<div class="mb-2 flex items-center gap-4">
<div class="bg-primary/20 group-hover:bg-primary/30 rounded-xl p-3 transition-colors">
<Package class="text-primary h-7 w-7" strokeWidth={2.5} />
</div>
<h3 class="card-title text-lg mb-0">Cadastrar Material</h3>
<h3 class="card-title mb-0 text-lg">Cadastrar Material</h3>
</div>
<p class="text-base-content/70 text-sm">Adicionar novo material ao estoque</p>
</div>
</button>
<button
class="card bg-base-100 border border-base-300 shadow-xl hover:shadow-2xl hover:border-info/50 transition-all duration-300 hover:scale-[1.02] group"
class="card bg-base-100 border-base-300 hover:border-info/50 group border shadow-xl transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl"
onclick={() => goto('/almoxarifado/movimentacoes')}
>
<div class="card-body">
<div class="flex items-center gap-4 mb-2">
<div class="rounded-xl bg-info/20 p-3 group-hover:bg-info/30 transition-colors">
<ArrowLeftRight class="h-7 w-7 text-info" strokeWidth={2.5} />
<div class="mb-2 flex items-center gap-4">
<div class="bg-info/20 group-hover:bg-info/30 rounded-xl p-3 transition-colors">
<ArrowLeftRight class="text-info h-7 w-7" strokeWidth={2.5} />
</div>
<h3 class="card-title text-lg mb-0">Registrar Movimentação</h3>
<h3 class="card-title mb-0 text-lg">Registrar Movimentação</h3>
</div>
<p class="text-base-content/70 text-sm">Registrar entrada ou saída de material</p>
</div>
</button>
<button
class="card bg-base-100 border border-base-300 shadow-xl hover:shadow-2xl hover:border-secondary/50 transition-all duration-300 hover:scale-[1.02] group"
class="card bg-base-100 border-base-300 hover:border-secondary/50 group border shadow-xl transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl"
onclick={() => goto('/almoxarifado/materiais')}
>
<div class="card-body">
<div class="flex items-center gap-4 mb-2">
<div class="rounded-xl bg-secondary/20 p-3 group-hover:bg-secondary/30 transition-colors">
<List class="h-7 w-7 text-secondary" strokeWidth={2.5} />
<div class="mb-2 flex items-center gap-4">
<div class="bg-secondary/20 group-hover:bg-secondary/30 rounded-xl p-3 transition-colors">
<List class="text-secondary h-7 w-7" strokeWidth={2.5} />
</div>
<h3 class="card-title text-lg mb-0">Listar Materiais</h3>
<h3 class="card-title mb-0 text-lg">Listar Materiais</h3>
</div>
<p class="text-base-content/70 text-sm">Visualizar e gerenciar materiais cadastrados</p>
</div>
</button>
<button
class="card bg-base-100 border border-base-300 shadow-xl hover:shadow-2xl hover:border-success/50 transition-all duration-300 hover:scale-[1.02] group"
class="card bg-base-100 border-base-300 hover:border-success/50 group border shadow-xl transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl"
onclick={() => goto('/almoxarifado/relatorios')}
>
<div class="card-body">
<div class="flex items-center gap-4 mb-2">
<div class="rounded-xl bg-success/20 p-3 group-hover:bg-success/30 transition-colors">
<BarChart3 class="h-7 w-7 text-success" strokeWidth={2.5} />
<div class="mb-2 flex items-center gap-4">
<div class="bg-success/20 group-hover:bg-success/30 rounded-xl p-3 transition-colors">
<BarChart3 class="text-success h-7 w-7" strokeWidth={2.5} />
</div>
<h3 class="card-title text-lg mb-0">Relatórios</h3>
<h3 class="card-title mb-0 text-lg">Relatórios</h3>
</div>
<p class="text-base-content/70 text-sm">Visualizar relatórios e estatísticas</p>
</div>
</button>
</div>
</main>

View File

@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "sgse-app",
@@ -14,6 +15,7 @@
"svelte-sonner": "^1.0.7",
},
"devDependencies": {
"@types/bun": "^1.3.5",
"eslint": "^9.39.1",
"eslint-plugin-svelte": "^3.13.1",
"globals": "^16.5.0",
@@ -669,6 +671,8 @@
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],
"@types/cookie": ["@types/cookie@1.0.0", "", { "dependencies": { "cookie": "*" } }, "sha512-mGFXbkDQJ6kAXByHS7QAggRXgols0mAdP4MuXgloGY1tXokvzaFFM4SMqWvf7AH0oafI7zlFJwoGWzmhDqTZ9w=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
@@ -937,6 +941,8 @@
"buffers": ["buffers@0.1.1", "", {}, "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="],
"bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],

View File

@@ -25,9 +25,11 @@
"dev:native": "turbo -F native dev",
"dev:web": "turbo -F web dev",
"dev:server": "turbo -F @sgse-app/backend dev",
"dev:setup": "turbo -F @sgse-app/backend dev:setup"
"dev:setup": "turbo -F @sgse-app/backend dev:setup",
"deploy:convex:prod": "bun scripts/convex-deploy-prod.ts"
},
"devDependencies": {
"@types/bun": "^1.3.5",
"eslint": "^9.39.1",
"eslint-plugin-svelte": "^3.13.1",
"globals": "^16.5.0",

View File

@@ -0,0 +1,6 @@
import { $ } from 'bun';
await $`bunx convex deploy`.cwd('packages/backend');
// await $`bun --env-file=.env.prod -e 'console.log(process.env.CONVEX_SELF_HOSTED_URL)'`.cwd(
// 'packages/backend'
// );