diff --git a/backend/.env.example b/backend/.env.example index 446564f..45db2ce 100755 --- a/backend/.env.example +++ b/backend/.env.example @@ -38,6 +38,21 @@ CORS_ORIGINS=http://localhost:3000,http://localhost:8963 CLOUDFLARE_API_TOKEN=your-cloudflare-api-token CLOUDFLARE_ZONE_ID=your-zone-id +# ============================================================================= +# Stripe +# ============================================================================= +STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key +STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret +STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key + +# ============================================================================= +# Gateway de Pagamento (Fictício) +# ============================================================================= +PAYMENT_GATEWAY_MERCHANT_ID=merchant_demo +PAYMENT_GATEWAY_API_KEY=fake_gateway_key +PAYMENT_GATEWAY_ENDPOINT=https://payments.example.com/api +PAYMENT_GATEWAY_WEBHOOK_SECRET=fake_webhook_secret + # ============================================================================= # cPanel API (for email management) # ============================================================================= @@ -51,3 +66,8 @@ CPANEL_API_TOKEN=your-cpanel-api-token RESEND_API_KEY=re_xxxx_your_api_key EMAIL_FROM=noreply@gohorsejobs.com APP_URL=https://gohorsejobs.com + +# ============================================================================= +# LavinMQ (AMQP) +# ============================================================================= +AMQP_URL=amqps://nwigjply:nwEGZdcfz3--H8xc68IKmjiBCVtI09Cq@horse.lmq.cloudamqp.com/nwigjply diff --git a/backend/internal/services/credentials_service.go b/backend/internal/services/credentials_service.go index ab1933d..5515402 100644 --- a/backend/internal/services/credentials_service.go +++ b/backend/internal/services/credentials_service.go @@ -268,6 +268,14 @@ func (s *CredentialsService) BootstrapCredentials(ctx context.Context) error { "publishableKey": os.Getenv("STRIPE_PUBLISHABLE_KEY"), } }, + "payment_gateway": func() interface{} { + return map[string]string{ + "merchantId": os.Getenv("PAYMENT_GATEWAY_MERCHANT_ID"), + "apiKey": os.Getenv("PAYMENT_GATEWAY_API_KEY"), + "endpoint": os.Getenv("PAYMENT_GATEWAY_ENDPOINT"), + "webhookSecret": os.Getenv("PAYMENT_GATEWAY_WEBHOOK_SECRET"), + } + }, "storage": func() interface{} { return map[string]string{ "endpoint": os.Getenv("AWS_ENDPOINT"), @@ -277,6 +285,11 @@ func (s *CredentialsService) BootstrapCredentials(ctx context.Context) error { "region": os.Getenv("AWS_REGION"), } }, + "lavinmq": func() interface{} { + return map[string]string{ + "amqpUrl": os.Getenv("AMQP_URL"), + } + }, "cloudflare_config": func() interface{} { return map[string]string{ "apiToken": os.Getenv("CLOUDFLARE_API_TOKEN"), diff --git a/backoffice/.env.example b/backoffice/.env.example index a93d08a..03cb0a6 100644 --- a/backoffice/.env.example +++ b/backoffice/.env.example @@ -17,6 +17,14 @@ STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key +# ============================================================================= +# Gateway de Pagamento (Fictício) +# ============================================================================= +PAYMENT_GATEWAY_MERCHANT_ID=merchant_demo +PAYMENT_GATEWAY_API_KEY=fake_gateway_key +PAYMENT_GATEWAY_ENDPOINT=https://payments.example.com/api +PAYMENT_GATEWAY_WEBHOOK_SECRET=fake_webhook_secret + # ============================================================================= # Database # ============================================================================= @@ -53,3 +61,8 @@ CLOUDFLARE_ZONE_ID=your-zone-id CPANEL_HOST=https://cpanel.yourdomain.com:2083 CPANEL_USERNAME=your-cpanel-username CPANEL_API_TOKEN=your-cpanel-api-token + +# ============================================================================= +# LavinMQ (AMQP) +# ============================================================================= +AMQP_URL=amqps://nwigjply:nwEGZdcfz3--H8xc68IKmjiBCVtI09Cq@horse.lmq.cloudamqp.com/nwigjply diff --git a/backoffice/src/credentials/credentials.service.ts b/backoffice/src/credentials/credentials.service.ts index 01d7b36..81c6a68 100644 --- a/backoffice/src/credentials/credentials.service.ts +++ b/backoffice/src/credentials/credentials.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ExternalServicesCredentials } from './credentials.entity'; @@ -35,6 +35,8 @@ export class CredentialsService { let cred = await this.credentialsRepo.findOne({ where: { serviceName } }); if (!cred) { cred = this.credentialsRepo.create({ serviceName }); + } else { + throw new BadRequestException('Credentials already configured for this service.'); } cred.encryptedPayload = encrypted; cred.updatedBy = updatedBy; diff --git a/frontend/src/app/dashboard/settings/page.tsx b/frontend/src/app/dashboard/settings/page.tsx index b9ef411..886c87e 100644 --- a/frontend/src/app/dashboard/settings/page.tsx +++ b/frontend/src/app/dashboard/settings/page.tsx @@ -8,7 +8,7 @@ import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" import { settingsApi, credentialsApi, ConfiguredService, storageApi } from "@/lib/api" import { toast } from "sonner" -import { Loader2, Check, Key, Trash2 } from "lucide-react" +import { Loader2, Check, Key } from "lucide-react" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Dialog, @@ -107,19 +107,6 @@ export default function SettingsPage() { - const handleDeleteCredential = async (serviceName: string) => { - if (!confirm(`Are you sure you want to remove credentials for ${serviceName}?`)) return - - try { - await credentialsApi.delete(serviceName) - toast.success(`Credentials for ${serviceName} removed`) - fetchCredentials() - } catch (error) { - console.error("Failed to delete credential", error) - toast.error("Failed to delete credential") - } - } - if (loading) { return
} @@ -134,6 +121,15 @@ export default function SettingsPage() { { key: "publishableKey", label: "Publishable Key (pk_...)", type: "text" }, ] }, + payment_gateway: { + label: "Gateway de Pagamento (Fictício)", + fields: [ + { key: "merchantId", label: "Merchant ID", type: "text" }, + { key: "apiKey", label: "API Key", type: "password" }, + { key: "endpoint", label: "Endpoint URL", type: "text" }, + { key: "webhookSecret", label: "Webhook Secret", type: "password" }, + ] + }, storage: { label: "AWS S3 / Compatible", fields: [ @@ -152,6 +148,12 @@ export default function SettingsPage() { { key: "apiToken", label: "API Token", type: "password" }, ] }, + lavinmq: { + label: "LavinMQ (AMQP)", + fields: [ + { key: "amqpUrl", label: "AMQP URL", type: "password" }, + ] + }, cloudflare_config: { label: "Cloudflare", fields: [ @@ -304,7 +306,7 @@ export default function SettingsPage() { External Services - Manage credentials for third-party integrations securely. Keys are encrypted. + Manage credentials for third-party integrations securely. Keys are encrypted and locked after saving.
@@ -334,15 +336,16 @@ export default function SettingsPage() { )}
- - {svc.is_configured && ( - - )}
@@ -358,7 +361,7 @@ export default function SettingsPage() { Configure {selectedService && (schemas[selectedService]?.label || selectedService)} - Enter credentials. Keys are encrypted before storage and hidden after saving. + Enter credentials. Keys are encrypted before storage, hidden after saving, and cannot be edited later.