feat: setup docker, backend, and gitea pipeline for production
All checks were successful
Build and Deploy / build-and-push (push) Successful in 4m19s
All checks were successful
Build and Deploy / build-and-push (push) Successful in 4m19s
This commit is contained in:
11
.env.example
Normal file
11
.env.example
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
PORT=3001
|
||||||
|
DB_HOST=db
|
||||||
|
DB_USER=root
|
||||||
|
DB_PASSWORD=root_password
|
||||||
|
DB_NAME=agenciac_comia
|
||||||
|
|
||||||
|
# Gitea Runner Configuration
|
||||||
|
GITEA_INSTANCE_URL=https://gitea.blyzer.com.br
|
||||||
|
GITEA_RUNNER_REGISTRATION_TOKEN=your_token_here
|
||||||
|
GITEA_RUNNER_NAME=fasto-runner
|
||||||
|
GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:16-bullseye
|
||||||
44
.gitea/workflows/build-deploy.yaml
Normal file
44
.gitea/workflows/build-deploy.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
name: Build and Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Convert repository name to lowercase
|
||||||
|
run: echo "repo_name=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Login to Gitea Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: gitea.blyzer.com.br
|
||||||
|
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
gitea.blyzer.com.br/${{ env.repo_name }}:latest
|
||||||
|
gitea.blyzer.com.br/${{ env.repo_name }}:${{ gitea.sha }}
|
||||||
|
|
||||||
|
- name: Deploy to Portainer
|
||||||
|
run: |
|
||||||
|
if [ -n "${{ secrets.PORTAINER_WEBHOOK }}" ]; then
|
||||||
|
curl -k -X POST "${{ secrets.PORTAINER_WEBHOOK }}"
|
||||||
|
else
|
||||||
|
echo "PORTAINER_WEBHOOK secret not set, skipping deployment trigger."
|
||||||
|
fi
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -22,3 +22,11 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# Environment and Secrets
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Runner Data
|
||||||
|
fasto_runner/
|
||||||
|
|||||||
37
Dockerfile
Normal file
37
Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Stage 1: Build Frontend
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json ./
|
||||||
|
# In a real scenario, copy package-lock.json too
|
||||||
|
# COPY package-lock.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 2: Production Runtime
|
||||||
|
FROM node:22-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
COPY package.json ./
|
||||||
|
COPY backend/package.json ./backend/
|
||||||
|
|
||||||
|
# Install dependencies (including production deps for backend)
|
||||||
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
|
# Copy backend source
|
||||||
|
COPY backend/ ./backend/
|
||||||
|
|
||||||
|
# Copy built frontend from builder stage
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
|
EXPOSE 3001
|
||||||
|
|
||||||
|
CMD ["node", "backend/index.js"]
|
||||||
58
GEMINI.md
Normal file
58
GEMINI.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Fasto Project Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Fasto is a commercial team management system built with React (Vite) on the frontend and Node.js (Express) on the backend. It uses a MySQL database.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
- **Frontend**: React, TypeScript, Vite.
|
||||||
|
- **Backend**: Node.js, Express, MySQL2.
|
||||||
|
- **Database**: MySQL 8.0.
|
||||||
|
- **Deployment**: Docker Compose for local development; Gitea Actions for CI/CD pushing to a Gitea Registry and deploying via Portainer webhook.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- Node.js (for local development outside Docker)
|
||||||
|
|
||||||
|
## Setup & Running
|
||||||
|
|
||||||
|
### 1. Environment Variables
|
||||||
|
Copy `.env.example` to `.env` and adjust the values:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
Ensure you set the database credentials and Gitea Runner token if you plan to run the runner locally.
|
||||||
|
|
||||||
|
### 2. Database
|
||||||
|
The project expects a MySQL database. A `docker-compose.yml` file is provided which spins up a MySQL container and initializes it with `agenciac_comia.sql`.
|
||||||
|
|
||||||
|
### 3. Running with Docker Compose
|
||||||
|
To start the application, database, and runner:
|
||||||
|
```bash
|
||||||
|
docker-compose up -d --build
|
||||||
|
```
|
||||||
|
- Frontend/Backend: http://localhost:3001
|
||||||
|
- Database: Exposed on port 3306 (internal to network mostly, but mapped if needed)
|
||||||
|
|
||||||
|
### 4. Gitea Runner
|
||||||
|
The `docker-compose.yml` includes a service for a Gitea Runner (`fasto-runner`).
|
||||||
|
- Ensure `GITEA_RUNNER_REGISTRATION_TOKEN` is set in `.env`.
|
||||||
|
- The runner data is persisted in `./fasto_runner/data`.
|
||||||
|
|
||||||
|
## CI/CD Pipeline
|
||||||
|
The project uses Gitea Actions defined in `.gitea/workflows/build-deploy.yaml`.
|
||||||
|
- **Triggers**: Push to `main` or `master`.
|
||||||
|
- **Steps**:
|
||||||
|
1. Checkout code.
|
||||||
|
2. Build Docker image.
|
||||||
|
3. Push to `gitea.blyzer.com.br`.
|
||||||
|
4. Trigger Portainer webhook.
|
||||||
|
- **Secrets Required in Gitea**:
|
||||||
|
- `REGISTRY_USERNAME`
|
||||||
|
- `REGISTRY_TOKEN`
|
||||||
|
- `PORTAINER_WEBHOOK`
|
||||||
|
- `API_KEY` (Optional build arg)
|
||||||
|
|
||||||
|
## Development
|
||||||
|
- **Frontend**: `npm run dev` (Runs on port 3000)
|
||||||
|
- **Backend**: `node backend/index.js` (Runs on port 3001)
|
||||||
|
*Note: For local dev, you might need to run a local DB or point to the dockerized one.*
|
||||||
199
agenciac_comia.sql
Normal file
199
agenciac_comia.sql
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 5.2.2
|
||||||
|
-- https://www.phpmyadmin.net/
|
||||||
|
--
|
||||||
|
-- Host: localhost:3306
|
||||||
|
-- Tempo de geração: 23-Fev-2026 às 10:41
|
||||||
|
-- Versão do servidor: 8.0.45
|
||||||
|
-- versão do PHP: 8.3.30
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
START TRANSACTION;
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Base de dados: `agenciac_comia`
|
||||||
|
--
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Estrutura da tabela `attendances`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `attendances` (
|
||||||
|
`id` varchar(36) NOT NULL,
|
||||||
|
`tenant_id` varchar(36) NOT NULL,
|
||||||
|
`user_id` varchar(36) NOT NULL,
|
||||||
|
`summary` text,
|
||||||
|
`score` int DEFAULT NULL,
|
||||||
|
`first_response_time_min` int DEFAULT '0',
|
||||||
|
`handling_time_min` int DEFAULT '0',
|
||||||
|
`funnel_stage` enum('Sem atendimento','Identificação','Negociação','Ganhos','Perdidos') NOT NULL,
|
||||||
|
`origin` enum('WhatsApp','Instagram','Website','LinkedIn','Referral') NOT NULL,
|
||||||
|
`product_requested` varchar(255) DEFAULT NULL,
|
||||||
|
`product_sold` varchar(255) DEFAULT NULL,
|
||||||
|
`converted` tinyint(1) DEFAULT '0',
|
||||||
|
`attention_points` json DEFAULT NULL,
|
||||||
|
`improvement_points` json DEFAULT NULL,
|
||||||
|
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Extraindo dados da tabela `attendances`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `attendances` (`id`, `tenant_id`, `user_id`, `summary`, `score`, `first_response_time_min`, `handling_time_min`, `funnel_stage`, `origin`, `product_requested`, `product_sold`, `converted`, `attention_points`, `improvement_points`, `created_at`) VALUES
|
||||||
|
('att_demo_1', 'tenant_123', 'u2', 'Cliente interessado no plano Enterprise.', 95, 5, 30, 'Ganhos', 'LinkedIn', 'Suíte Enterprise', 'Suíte Enterprise', 1, '[]', '[\"Oferecer desconto anual na próxima\"]', '2026-02-20 12:42:10');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Estrutura da tabela `teams`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `teams` (
|
||||||
|
`id` varchar(36) NOT NULL,
|
||||||
|
`tenant_id` varchar(36) NOT NULL,
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`description` text,
|
||||||
|
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Extraindo dados da tabela `teams`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `teams` (`id`, `tenant_id`, `name`, `description`, `created_at`) VALUES
|
||||||
|
('sales_1', 'tenant_123', 'Vendas Alpha', NULL, '2026-02-20 12:42:10'),
|
||||||
|
('sales_2', 'tenant_123', 'Vendas Beta', NULL, '2026-02-20 12:42:10');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Estrutura da tabela `tenants`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `tenants` (
|
||||||
|
`id` varchar(36) NOT NULL,
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`slug` varchar(255) NOT NULL,
|
||||||
|
`admin_email` varchar(255) DEFAULT NULL,
|
||||||
|
`logo_url` text,
|
||||||
|
`status` enum('active','inactive','trial') DEFAULT 'active',
|
||||||
|
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Extraindo dados da tabela `tenants`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `tenants` (`id`, `name`, `slug`, `admin_email`, `logo_url`, `status`, `created_at`, `updated_at`) VALUES
|
||||||
|
('system', 'System Admin', 'system', 'root@system.com', NULL, 'active', '2026-02-20 12:42:10', '2026-02-20 12:42:10'),
|
||||||
|
('tenant_101', 'Soylent Green', 'soylent', 'admin@soylent.com', NULL, 'active', '2023-02-10 14:20:00', '2026-02-20 12:42:10'),
|
||||||
|
('tenant_123', 'Fasto Corp', 'fasto', 'admin@fasto.com', NULL, 'active', '2023-01-15 13:00:00', '2026-02-20 12:42:10'),
|
||||||
|
('tenant_456', 'Acme Inc', 'acme-inc', 'contact@acme.com', NULL, 'trial', '2023-06-20 17:30:00', '2026-02-20 12:42:10'),
|
||||||
|
('tenant_789', 'Globex Utils', 'globex', 'sysadmin@globex.com', NULL, 'inactive', '2022-11-05 12:15:00', '2026-02-20 12:42:10');
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Estrutura da tabela `users`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `users` (
|
||||||
|
`id` varchar(36) NOT NULL,
|
||||||
|
`tenant_id` varchar(36) DEFAULT NULL,
|
||||||
|
`team_id` varchar(36) DEFAULT NULL,
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`email` varchar(255) NOT NULL,
|
||||||
|
`password_hash` varchar(255) NOT NULL DEFAULT 'hash_placeholder',
|
||||||
|
`avatar_url` text,
|
||||||
|
`role` enum('super_admin','admin','manager','agent') NOT NULL DEFAULT 'agent',
|
||||||
|
`bio` text,
|
||||||
|
`status` enum('active','inactive') DEFAULT 'active',
|
||||||
|
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Extraindo dados da tabela `users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `users` (`id`, `tenant_id`, `team_id`, `name`, `email`, `password_hash`, `avatar_url`, `role`, `bio`, `status`, `created_at`) VALUES
|
||||||
|
('sa1', 'system', NULL, 'Super Administrator', 'root@system.com', 'hash_placeholder', 'https://ui-avatars.com/api/?name=Super+Admin&background=0f172a&color=fff', 'super_admin', 'Administrador Global', 'active', '2026-02-20 12:42:10'),
|
||||||
|
('u1', 'tenant_123', 'sales_1', 'Lidya Chan', 'lidya@fasto.com', 'hash_placeholder', 'https://picsum.photos/id/1011/200/200', 'manager', 'Gerente de Vendas Experiente', 'active', '2026-02-20 12:42:10'),
|
||||||
|
('u2', 'tenant_123', 'sales_1', 'Alex Noer', 'alex@fasto.com', 'hash_placeholder', 'https://picsum.photos/id/1012/200/200', 'agent', 'Top performer Q3', 'active', '2026-02-20 12:42:10'),
|
||||||
|
('u3', 'tenant_123', 'sales_1', 'Angela Moss', 'angela@fasto.com', 'hash_placeholder', 'https://picsum.photos/id/1013/200/200', 'agent', '', 'inactive', '2026-02-20 12:42:10'),
|
||||||
|
('u4', 'tenant_123', 'sales_2', 'Brian Samuel', 'brian@fasto.com', 'hash_placeholder', 'https://picsum.photos/id/1014/200/200', 'agent', '', 'active', '2026-02-20 12:42:10'),
|
||||||
|
('u5', 'tenant_123', 'sales_2', 'Benny Chagur', 'benny@fasto.com', 'hash_placeholder', 'https://picsum.photos/id/1025/200/200', 'agent', '', 'active', '2026-02-20 12:42:10');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Índices para tabelas despejadas
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Índices para tabela `attendances`
|
||||||
|
--
|
||||||
|
ALTER TABLE `attendances`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `tenant_id` (`tenant_id`),
|
||||||
|
ADD KEY `user_id` (`user_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Índices para tabela `teams`
|
||||||
|
--
|
||||||
|
ALTER TABLE `teams`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD KEY `tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Índices para tabela `tenants`
|
||||||
|
--
|
||||||
|
ALTER TABLE `tenants`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `slug` (`slug`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Índices para tabela `users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `users`
|
||||||
|
ADD PRIMARY KEY (`id`),
|
||||||
|
ADD UNIQUE KEY `email` (`email`),
|
||||||
|
ADD KEY `tenant_id` (`tenant_id`),
|
||||||
|
ADD KEY `team_id` (`team_id`);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Restrições para despejos de tabelas
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Limitadores para a tabela `attendances`
|
||||||
|
--
|
||||||
|
ALTER TABLE `attendances`
|
||||||
|
ADD CONSTRAINT `attendances_ibfk_1` FOREIGN KEY (`tenant_id`) REFERENCES `tenants` (`id`) ON DELETE CASCADE,
|
||||||
|
ADD CONSTRAINT `attendances_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Limitadores para a tabela `teams`
|
||||||
|
--
|
||||||
|
ALTER TABLE `teams`
|
||||||
|
ADD CONSTRAINT `teams_ibfk_1` FOREIGN KEY (`tenant_id`) REFERENCES `tenants` (`id`) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Limitadores para a tabela `users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `users`
|
||||||
|
ADD CONSTRAINT `users_ibfk_1` FOREIGN KEY (`tenant_id`) REFERENCES `tenants` (`id`) ON DELETE CASCADE,
|
||||||
|
ADD CONSTRAINT `users_ibfk_2` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON DELETE SET NULL;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
@@ -4,15 +4,13 @@ const mysql = require('mysql2/promise');
|
|||||||
// Configuração da conexão com o banco de dados
|
// Configuração da conexão com o banco de dados
|
||||||
// Em produção, estes valores devem vir de variáveis de ambiente (.env)
|
// Em produção, estes valores devem vir de variáveis de ambiente (.env)
|
||||||
const pool = mysql.createPool({
|
const pool = mysql.createPool({
|
||||||
host: '162.240.103.190',
|
host: process.env.DB_HOST || 'localhost',
|
||||||
user: 'agenciac_comia',
|
user: process.env.DB_USER || 'root',
|
||||||
password: 'Blyzer@2025#',
|
password: process.env.DB_PASSWORD || 'password',
|
||||||
database: 'agenciac_comia',
|
database: process.env.DB_NAME || 'agenciac_comia',
|
||||||
waitForConnections: true,
|
waitForConnections: true,
|
||||||
connectionLimit: 10,
|
connectionLimit: 10,
|
||||||
queueLimit: 0,
|
queueLimit: 0,
|
||||||
// Opções de SSL podem ser necessárias dependendo do servidor,
|
|
||||||
// mas vamos tentar sem SSL inicialmente dado o host.
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Teste de conexão simples ao iniciar
|
// Teste de conexão simples ao iniciar
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
|
const path = require('path');
|
||||||
const pool = require('./db');
|
const pool = require('./db');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = 3001; // Porta do backend
|
const PORT = process.env.PORT || 3001; // Porta do backend
|
||||||
|
|
||||||
app.use(cors()); // Permite que o React (localhost:3000) acesse este servidor
|
app.use(cors()); // Permite que o React (localhost:3000) acesse este servidor
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Serve static files from the React app
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
app.use(express.static(path.join(__dirname, '../dist')));
|
||||||
|
}
|
||||||
|
|
||||||
// --- Rotas de Usuários ---
|
// --- Rotas de Usuários ---
|
||||||
|
|
||||||
// Listar Usuários (com filtro opcional de tenant)
|
// Listar Usuários (com filtro opcional de tenant)
|
||||||
@@ -124,6 +130,12 @@ app.get('/api/tenants', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Serve index.html for any unknown routes (for client-side routing)
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
app.get('*', (req, res) => {
|
||||||
|
res.sendFile(path.join(__dirname, '../dist/index.html'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`🚀 Servidor Backend rodando em http://localhost:${PORT}`);
|
console.log(`🚀 Servidor Backend rodando em http://localhost:${PORT}`);
|
||||||
|
|||||||
3
backend/package.json
Normal file
3
backend/package.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"type": "commonjs"
|
||||||
|
}
|
||||||
44
docker-compose.yml
Normal file
44
docker-compose.yml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
image: gitea.blyzer.com.br/blyzer/fasto:latest
|
||||||
|
container_name: fasto-app
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PORT=3001
|
||||||
|
- DB_HOST=db
|
||||||
|
- DB_USER=${DB_USER:-root}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD:-root_password}
|
||||||
|
- DB_NAME=${DB_NAME:-agenciac_comia}
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: fasto-db
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-root_password}
|
||||||
|
MYSQL_DATABASE: ${DB_NAME:-agenciac_comia}
|
||||||
|
volumes:
|
||||||
|
- ./agenciac_comia.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
runner:
|
||||||
|
image: gitea/act_runner:latest
|
||||||
|
container_name: fasto-runner
|
||||||
|
environment:
|
||||||
|
- GITEA_INSTANCE_URL=https://gitea.example.com
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN=CHANGE_ME_TOKEN_FROM_SERVER
|
||||||
|
- GITEA_RUNNER_NAME=${GITEA_RUNNER_NAME:-fasto-runner}
|
||||||
|
- GITEA_RUNNER_LABELS=${GITEA_RUNNER_LABELS:-ubuntu-latest:docker://node:16-bullseye}
|
||||||
|
volumes:
|
||||||
|
- ./fasto_runner/data:/data
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
@@ -13,7 +13,10 @@
|
|||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"react-router-dom": "^7.13.0",
|
"react-router-dom": "^7.13.0",
|
||||||
"lucide-react": "^0.574.0",
|
"lucide-react": "^0.574.0",
|
||||||
"recharts": "^3.7.0"
|
"recharts": "^3.7.0",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"mysql2": "^3.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.14.0",
|
"@types/node": "^22.14.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user