commit 74a73f5cd009d7c663b4d307d27534a17a68c16f Author: pedro Date: Mon Jun 8 17:08:10 2026 +0100 Initial commit: Substituição pelo portal Apex Solutions diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..158d16a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +npm-debug.log +.env +.git +.gitea \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab2dc7d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.env +*.backup +.DS_Store diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..ddba666 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,9 @@ +FROM node:18-alpine +WORKDIR /usr/src/app/backend +COPY backend/package*.json ./ +RUN npm install --omit=dev +WORKDIR /usr/src/app +COPY backend/ ./backend/ +COPY frontend/ ./frontend/ +EXPOSE 3000 +CMD ["node", "backend/server.js"] \ No newline at end of file diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..75910e6 --- /dev/null +++ b/backend/package.json @@ -0,0 +1,14 @@ +{ + "name": "corporate-portal", + "version": "2.0.0", + "description": "Multi-page Corporate Portal for DevSecOps PoC", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "cors": "^2.8.5", + "express": "^4.18.2", + "nodemailer": "^6.9.3" + } +} \ No newline at end of file diff --git a/backend/server.js b/backend/server.js new file mode 100644 index 0000000..3a78ec8 --- /dev/null +++ b/backend/server.js @@ -0,0 +1,90 @@ +const express = require('express'); +const cors = require('cors'); +const path = require('path'); +const nodemailer = require('nodemailer'); + +const app = express(); +const PORT = process.env.PORT || 3000; + +app.use(cors()); +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + +// Serve a pasta frontend +app.use(express.static(path.join(__dirname, '../frontend'), { extensions: ['html'] })); + +// Rotas das 4 páginas +app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../frontend/index.html'))); +app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/about.html'))); +app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend/careers.html'))); +app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); + +// Configuração do transporte de E-mail +const transporter = nodemailer.createTransport({ + host: 'mail.limpezascleanandcare.com', + port: 465, + secure: true, + auth: { + user: 'teste@limpezascleanandcare.com', + pass: 'HTC?D=}5&cHoTrH=' + }, + tls: { + rejectUnauthorized: false // Ignora avisos de certificado no servidor SMTP + } +}); + +// Endpoint do Formulário de Contacto (Com Recetor Dinâmico) +app.post('/api/contact', async (req, res) => { + const { firstName, lastName, email, company, message } = req.body; + + if (!email || !message) { + return res.status(400).json({ error: 'Email and message are required.' }); + } + + try { + // Construção do Email - Agora enviado para o e-mail inserido no formulário + const mailOptions = { + from: '"Apex Solutions" ', // Remetente fixo válido + to: email, // RECETOR DINÂMICO (Vem diretamente do campo Email Address) + subject: `Confirmation: We received your request, ${firstName}!`, + html: ` +
+

Hello ${firstName} ${lastName},

+

+ Thank you for reaching out to Apex Solutions. This is an automated confirmation to let you know that we have successfully received your inquiry. +

+ +
+

Summary of your submission:

+

Subject/Company: ${company || 'Not specified'}

+

"${message}"

+
+ +

+ Our advisory team will review your details and get back to you within 24 business hours. +

+ +
+ +

+ Best regards,
+ Apex Solutions Corporate Team +

+
+ ` + }; + + // Envia o e-mail real + const info = await transporter.sendMail(mailOptions); + console.log(`[Email Sent Automatically to ${email}] Message ID: ${info.messageId}`); + + res.status(200).json({ success: true, message: 'Thank you! A confirmation email has been dispatched to your address.' }); + } catch (error) { + console.error(`[Email Error]:`, error); + res.status(500).json({ error: 'Internal server error. Could not send confirmation email.' }); + } +}); + +app.listen(PORT, () => { + console.log(`[Apex Server] Running on port ${PORT}`); +}); \ No newline at end of file diff --git a/frontend/about.html b/frontend/about.html new file mode 100644 index 0000000..914f2ff --- /dev/null +++ b/frontend/about.html @@ -0,0 +1,50 @@ + + + + + + About Us | Apex Solutions + + + + + + +
+
+

Who We Are

+

Founded in 2005, Apex Solutions started with a simple idea: business services should be accessible, transparent, and driven by results. Today, we are proud to be a trusted partner for companies around the world.

+ +

Our Mission

+

Our mission is to empower organizations by providing them with the tools, strategies, and support they need to thrive in a competitive landscape. We believe in creating sustainable growth through ethical business practices and continuous improvement.

+ +

Our Core Values

+
    +
  • Integrity: We do what is right, not what is easy. Honesty is the foundation of all our client relationships.
  • +
  • Innovation: We continuously seek new ways to solve old problems, staying ahead of market trends.
  • +
  • Excellence: We strive for perfection in every project, delivering high-quality results consistently.
  • +
  • Collaboration: We work closely with our clients, believing that the best solutions come from teamwork.
  • +
+
+
+ +
+

© 2026 Apex Solutions. All rights reserved.

+
+ + \ No newline at end of file diff --git a/frontend/careers.html b/frontend/careers.html new file mode 100644 index 0000000..acab44a --- /dev/null +++ b/frontend/careers.html @@ -0,0 +1,66 @@ + + + + + + Careers | Apex Solutions + + + + + + +
+
+

Join Our Team

+

We are always looking for passionate individuals to help us build the future.

+
+ +

Open Positions

+
+
+
+

Senior Business Analyst

+

Full-Time • Remote (Europe) • Consulting Dept.

+
+ Apply Now → +
+ +
+
+

Account Executive

+

Full-Time • New York, USA • Sales Dept.

+
+ Apply Now → +
+ +
+
+

Customer Success Manager

+

Part-Time • London, UK • Support Dept.

+
+ Apply Now → +
+
+
+ +
+

© 2026 Apex Solutions. All rights reserved.

+
+ + \ No newline at end of file diff --git a/frontend/contact.html b/frontend/contact.html new file mode 100644 index 0000000..1a38e0d --- /dev/null +++ b/frontend/contact.html @@ -0,0 +1,117 @@ + + + + + + Contact Us | Apex Solutions + + + + + + +
+
+
+

Get in Touch

+

Have a question or want to work together? Leave your details below and we will get back to you.

+
+ +
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + + +
+
+
+ +
+

© 2026 Apex Solutions. All rights reserved.

+
+ + + + \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..a181e65 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,101 @@ + + + + + + Home | Apex Solutions + + + + + + + +
+
+
+

+ Innovative Solutions for + Modern Businesses +

+

+ At Apex Solutions, we deliver high-quality business consulting, technology services, and strategic insights. We help organizations across the globe achieve their goals through operational excellence and digital transformation. +

+ +
+
+ +
+
+

Our Services

+

Comprehensive solutions designed to elevate your business operations and drive meaningful results.

+ +
+
+
1
+

Management Consulting

+

We analyze your current organizational structure and provide actionable strategies to improve efficiency, reduce costs, and accelerate business growth.

+
+
+
2
+

Technology Integration

+

Upgrade your legacy systems. We help you implement modern software solutions, CRM systems, and cloud-based applications tailored to your specific industry.

+
+
+
3
+

Financial Advisory

+

Expert guidance on capital allocation, risk management, and financial restructuring to ensure your company remains profitable in volatile markets.

+
+
+
4
+

Human Resources Support

+

From talent acquisition to employee retention programs, we provide full-scale HR solutions to build and maintain a strong corporate culture.

+
+
+
+
+ +
+

Why Choose Us?

+
+
+

Global Reach

+

With offices in over 20 countries, our international presence allows us to understand diverse markets and deliver tailored solutions that meet local and global demands.

+
+
+

Proven Expertise

+

Our team consists of industry veterans and certified professionals dedicated to providing top-tier service. We bring decades of combined experience to every project we undertake.

+
+
+

Customer First

+

Your success is our success. We prioritize transparent communication, rapid response times, and a commitment to exceeding expectations in everything we do.

+
+
+
+
+ + + + \ No newline at end of file diff --git a/frontend/style.css b/frontend/style.css new file mode 100644 index 0000000..b00f00e --- /dev/null +++ b/frontend/style.css @@ -0,0 +1,474 @@ +/* ========================================================= + 1. RESET E VARIÁVEIS + ========================================================= */ +:root { + --primary-color: #0f172a; + --accent-color: #3b82f6; + --bg-color: #f8fafc; + --card-bg: #ffffff; + --text-main: #334155; + --text-muted: #64748b; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Inter', sans-serif; +} + +body { + background-color: var(--bg-color); + color: var(--text-main); + display: flex; + flex-direction: column; + min-height: 100vh; +} + +.container { + max-width: 900px; + margin: 0 auto; + padding: 0 40px; +} + +/* ========================================================= + 2. NAVEGAÇÃO E RODAPÉ + ========================================================= */ +.navbar { + background-color: rgba(15, 23, 42, 0.95); /* Cor escura com 5% de transparência */ + backdrop-filter: blur(8px); /* Cria o efeito de vidro desfocado */ + color: white; + padding: 20px 0; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); /* Sombra mais suave e espalhada */ + position: sticky; /* Fixa a barra no topo */ + top: 0; + z-index: 1000; /* Garante que a barra fica sempre por cima do conteúdo */ +} + +.navbar .container { + display: flex; + justify-content: space-between; + align-items: center; +} + +.logo { + font-size: 24px; + font-weight: 700; + letter-spacing: -0.5px; /* Junta ligeiramente as letras para um look corporativo */ +} + +.logo span { + color: var(--accent-color); +} + +.navbar ul { + list-style: none; + display: flex; + gap: 10px; /* Reduzido o gap para acomodar o padding dos novos botões */ +} + +.navbar a { + color: #cbd5e1; + text-decoration: none; + font-weight: 500; + padding: 8px 16px; /* Transforma o link num botão clicável com espaço interno */ + border-radius: 6px; /* Cantos arredondados */ + transition: all 0.3s ease; /* Transição suave de cores e fundos */ +} + +/* Efeito ao passar o rato (Hover) */ +.navbar a:hover { + color: white; + background-color: rgba(255, 255, 255, 0.1); /* Fundo branco muito subtil */ +} + +/* Estado da página atual (Active) */ +.navbar a.active { + color: white; + background-color: var(--accent-color); + box-shadow: 0 2px 8px rgba(59, 130, 246, 0.4); /* Sombra azul ao redor do botão ativo */ +} + +footer { + background-color: white; + text-align: center; + padding: 40px 20px; + color: var(--text-muted); + font-size: 14px; + border-top: 1px solid #e2e8f0; +} + +/* ========================================================= + 3. ESTRUTURA GERAL (MAIN & INTRO) + ========================================================= */ +main { + flex-grow: 1; + padding: 80px 20px; +} + +.intro { + margin-bottom: 40px; + border-bottom: 1px solid #e2e8f0; + padding-bottom: 20px; +} + +.intro h2 { + font-size: 28px; + color: var(--primary-color); + margin-bottom: 5px; +} + +.intro p { + color: var(--text-muted); +} + +/* --- Lógica de View (Single Page App) --- */ +.view-section.hidden { + display: none; +} +.view-section.active { + display: block; + animation: fadeIn 0.4s ease-in-out; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +/* ========================================================= + 4. COMPONENTES (Cartões, Tabelas, Formulários) + ========================================================= */ + +/* --- Diretório: Grelha de Cartões --- */ +.grid-colaboradores { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 20px; +} + +.cartao { + background: var(--card-bg); + border-radius: 8px; + padding: 20px; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + display: flex; + align-items: center; + gap: 15px; + transition: transform 0.2s, box-shadow 0.2s; + border: 1px solid #e2e8f0; +} + +.cartao:hover { + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0,0,0,0.1); +} + +.avatar { + width: 50px; + height: 50px; + background-color: var(--accent-color); + color: white; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + font-size: 20px; + font-weight: bold; +} + +.info h3 { + font-size: 16px; + color: var(--primary-color); +} + +.cargo { + font-size: 14px; + font-weight: 600; + color: var(--accent-color); + margin: 2px 0; +} + +.departamento { + font-size: 13px; + color: var(--text-muted); +} + +.email { + font-size: 13px; + color: var(--text-muted); + text-decoration: none; + display: inline-block; + margin-top: 5px; +} + +.email:hover { + color: var(--accent-color); + text-decoration: underline; +} + +/* --- Departamentos: Tabela --- */ +.table-container { + background: var(--card-bg); + border-radius: 8px; + border: 1px solid #e2e8f0; + overflow: hidden; + box-shadow: 0 1px 3px rgba(0,0,0,0.05); +} + +.data-table { + width: 100%; + border-collapse: collapse; + text-align: left; +} + +.data-table th { + background-color: #f1f5f9; + color: var(--primary-color); + padding: 15px; + font-size: 14px; + border-bottom: 2px solid #e2e8f0; +} + +.data-table td { + padding: 15px; + border-bottom: 1px solid #e2e8f0; + color: var(--text-main); + font-size: 14px; +} + +.data-table tr:last-child td { + border-bottom: none; +} + +.data-table tr:hover td { + background-color: #f8fafc; +} + +.badge { + background-color: #dcfce7; + color: #166534; + padding: 4px 8px; + border-radius: 12px; + font-size: 12px; + font-weight: 600; +} + +.text-center { + text-align: center; +} + +/* --- Definições: Cartões e Botões --- */ +.settings-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 20px; +} + +.settings-card { + background: var(--card-bg); + border-radius: 8px; + padding: 25px; + border: 1px solid #e2e8f0; + box-shadow: 0 1px 3px rgba(0,0,0,0.05); +} + +.settings-card h3 { + color: var(--primary-color); + margin-bottom: 10px; +} + +.settings-card p { + color: var(--text-muted); + font-size: 14px; + margin-bottom: 20px; + min-height: 40px; +} + +.btn-outline { + background: transparent; + color: var(--accent-color); + border: 1px solid var(--accent-color); + padding: 8px 16px; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s; + width: 100%; + margin-top: 0; +} + +.btn-outline:hover { + background: var(--accent-color); + color: white; +} + +/* --- Formulário de Contacto --- */ +.divisor { + border: 0; + height: 1px; + background: #e2e8f0; + margin: 40px 0; +} + +.contacto-suporte { + background: var(--card-bg); + padding: 30px; + border-radius: 8px; + border: 1px solid #e2e8f0; + box-shadow: 0 1px 3px rgba(0,0,0,0.05); +} + +.contacto-suporte h2 { + color: var(--primary-color); + margin-bottom: 5px; +} + +.contacto-suporte p { + color: var(--text-muted); + margin-bottom: 20px; + font-size: 14px; +} + +.formulario { + display: flex; + flex-direction: column; + gap: 15px; + max-width: 600px; +} + +.grupo-input { + display: flex; + flex-direction: column; + gap: 5px; +} + +.grupo-input label { + font-weight: 600; + font-size: 14px; + color: var(--text-main); +} + +.grupo-input input, +.grupo-input textarea { + padding: 10px 12px; + border: 1px solid #cbd5e1; + border-radius: 6px; + font-size: 14px; + outline: none; + transition: border-color 0.2s; + font-family: inherit; +} + +.grupo-input input:focus, +.grupo-input textarea:focus { + border-color: var(--accent-color); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +button[type="submit"] { + background-color: var(--accent-color); + color: white; + border: none; + padding: 12px 20px; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: background-color 0.2s; + margin-top: 10px; +} + +button[type="submit"]:hover { + background-color: #2563eb; +} + +button[type="submit"]:disabled { + background-color: #94a3b8; + cursor: not-allowed; +} + +/* Status da Mensagem / Notificações */ +.status-oculto { + display: none; +} + +.status-visivel { + display: block; + padding: 10px; + border-radius: 6px; + margin-top: 15px; + font-size: 14px; + font-weight: 600; + text-align: center; +} + +.status-sucesso { + background-color: #dcfce7; + color: #166534; + border: 1px solid #bbf7d0; +} + +.status-erro { + background-color: #fee2e2; + color: #991b1b; + border: 1px solid #fecaca; +} + +/* ========================================================= + 5. RESPONSIVIDADE (Mobile & Tablets) + ========================================================= */ +@media (max-width: 768px) { + main { + padding: 40px 15px; + } + + .container { + padding: 0 15px; + } + + .navbar { + padding: 15px 0; + } + + .navbar .container { + flex-direction: column; + gap: 15px; + } + + .navbar ul { + flex-wrap: wrap; + justify-content: center; + gap: 5px; + } + + .navbar a { + padding: 6px 12px; + font-size: 14px; + } + + .intro h2 { + font-size: 24px; + } + + .intro p { + font-size: 14px; + } + + .grid-colaboradores { + grid-template-columns: 1fr; + } + + .settings-grid { + grid-template-columns: 1fr; + } + + .table-container { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .data-table th, .data-table td { + white-space: nowrap; + padding: 10px; + } +} \ No newline at end of file