mirror of
https://github.com/aljazceru/enclava.git
synced 2025-12-17 07:24:34 +01:00
cleaup env
This commit is contained in:
50
.env.example
50
.env.example
@@ -1,9 +1,19 @@
|
||||
# ===================================
|
||||
# ENCLAVA MINIMAL CONFIGURATION
|
||||
# ENCLAVA CONFIGURATION
|
||||
# ===================================
|
||||
# Only essential environment variables that CANNOT have defaults
|
||||
# Other settings should be configurable through the app UI
|
||||
|
||||
# Admin user (created on first startup only)
|
||||
ADMIN_EMAIL=admin@example.com
|
||||
ADMIN_PASSWORD=admin123
|
||||
|
||||
|
||||
# ===================================
|
||||
# APPLICATION BASE URL (Required - derives all URLs and CORS)
|
||||
# ===================================
|
||||
BASE_URL=localhost
|
||||
|
||||
# ===================================
|
||||
# INFRASTRUCTURE (Required)
|
||||
# ===================================
|
||||
@@ -18,9 +28,7 @@ POSTGRES_PASSWORD=enclava_pass
|
||||
JWT_SECRET=your-super-secret-jwt-key-here-change-in-production
|
||||
PRIVATEMODE_API_KEY=your-privatemode-api-key-here
|
||||
|
||||
# Admin user (created on first startup only)
|
||||
ADMIN_EMAIL=admin@example.com
|
||||
ADMIN_PASSWORD=admin123
|
||||
|
||||
|
||||
# ===================================
|
||||
# ADDITIONAL SECURITY SETTINGS (Optional but recommended)
|
||||
@@ -36,29 +44,31 @@ ADMIN_PASSWORD=admin123
|
||||
# API Key prefix (default: en_)
|
||||
# API_KEY_PREFIX=en_
|
||||
|
||||
# Security thresholds (0.0-1.0)
|
||||
# API_SECURITY_RISK_THRESHOLD=0.8
|
||||
# API_SECURITY_WARNING_THRESHOLD=0.6
|
||||
# API_SECURITY_ANOMALY_THRESHOLD=0.7
|
||||
|
||||
# IP security (comma-separated for multiple IPs)
|
||||
# API_BLOCKED_IPS=
|
||||
# API_ALLOWED_IPS=
|
||||
|
||||
# ===================================
|
||||
# APPLICATION BASE URL (Required - derives all URLs and CORS)
|
||||
# FRONTEND ENVIRONMENT (Required for production)
|
||||
# ===================================
|
||||
BASE_URL=localhost
|
||||
# Frontend derives: APP_URL=http://localhost, API_URL=http://localhost, WS_URL=ws://localhost
|
||||
# Backend derives: CORS_ORIGINS=["http://localhost"]
|
||||
NODE_ENV=production
|
||||
NEXT_PUBLIC_APP_NAME=Enclava
|
||||
# NEXT_PUBLIC_BASE_URL is derived from BASE_URL in Docker configuration
|
||||
|
||||
# ===================================
|
||||
# DOCKER NETWORKING (Required for containers)
|
||||
# LOGGING CONFIGURATION
|
||||
# ===================================
|
||||
BACKEND_INTERNAL_PORT=8000
|
||||
FRONTEND_INTERNAL_PORT=3000
|
||||
# Hosts are fixed: enclava-backend, enclava-frontend
|
||||
# Upstreams derive: enclava-backend:8000, enclava-frontend:3000
|
||||
LOG_LLM_PROMPTS=false
|
||||
|
||||
# For production HTTPS deployments, set:
|
||||
# BASE_URL=your-domain.com
|
||||
# The system will automatically detect HTTPS and use it for all URLs and CORS
|
||||
|
||||
# ===================================
|
||||
# DOCKER NETWORKING (Optional - defaults provided)
|
||||
# ===================================
|
||||
# Internal ports use defaults: backend=8000, frontend=3000
|
||||
# Override only if you need to change these defaults:
|
||||
# BACKEND_INTERNAL_PORT=8000
|
||||
# FRONTEND_INTERNAL_PORT=3000
|
||||
|
||||
# ===================================
|
||||
# QDRANT (Required for RAG)
|
||||
|
||||
@@ -48,7 +48,8 @@ class Settings(BaseSettings):
|
||||
"""Derive CORS origins from BASE_URL if not explicitly set"""
|
||||
if v is None:
|
||||
base_url = info.data.get('BASE_URL', 'localhost')
|
||||
return [f"http://{base_url}"]
|
||||
# Support both HTTP and HTTPS for production environments
|
||||
return [f"http://{base_url}", f"https://{base_url}"]
|
||||
return v if isinstance(v, list) else [v]
|
||||
|
||||
# CORS origins (derived from BASE_URL)
|
||||
|
||||
@@ -26,6 +26,8 @@ services:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile.prod
|
||||
env_file:
|
||||
- ./.env
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@enclava-postgres:5432/${POSTGRES_DB}
|
||||
depends_on:
|
||||
@@ -40,6 +42,8 @@ services:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile.prod
|
||||
env_file:
|
||||
- ./.env
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@enclava-postgres:5432/${POSTGRES_DB}
|
||||
- REDIS_URL=redis://enclava-redis:6379
|
||||
@@ -76,11 +80,11 @@ services:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
target: runner # Use the production stage from multi-stage build
|
||||
env_file:
|
||||
- ./.env
|
||||
environment:
|
||||
- BASE_URL=${BASE_URL}
|
||||
- NEXT_PUBLIC_BASE_URL=${BASE_URL}
|
||||
- BACKEND_INTERNAL_PORT=8000
|
||||
- FRONTEND_INTERNAL_PORT=3000
|
||||
- INTERNAL_API_URL=http://enclava-backend:8000
|
||||
- NODE_ENV=production
|
||||
- NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
@@ -68,11 +68,8 @@ services:
|
||||
# Required base URL (derives APP/API/WS URLs)
|
||||
- BASE_URL=${BASE_URL}
|
||||
- NEXT_PUBLIC_BASE_URL=${BASE_URL}
|
||||
# Docker internal ports
|
||||
- BACKEND_INTERNAL_PORT=${BACKEND_INTERNAL_PORT}
|
||||
- FRONTEND_INTERNAL_PORT=${FRONTEND_INTERNAL_PORT}
|
||||
# Internal API URL
|
||||
- INTERNAL_API_URL=http://enclava-backend:${BACKEND_INTERNAL_PORT}
|
||||
- INTERNAL_API_URL=http://enclava-backend:8000
|
||||
depends_on:
|
||||
- enclava-backend
|
||||
ports:
|
||||
|
||||
@@ -16,8 +16,21 @@ export const viewport: Viewport = {
|
||||
initialScale: 1,
|
||||
}
|
||||
|
||||
// Function to determine the base URL with proper protocol
|
||||
const getBaseUrl = () => {
|
||||
// In production, we need to detect if we're behind HTTPS
|
||||
if (typeof window !== 'undefined') {
|
||||
const protocol = window.location.protocol === 'https:' ? 'https' : 'http'
|
||||
const host = process.env.NEXT_PUBLIC_BASE_URL || window.location.hostname
|
||||
return `${protocol}://${host}`
|
||||
}
|
||||
// For build time/server side, default to HTTP for dev, HTTPS for production
|
||||
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http'
|
||||
return `${protocol}://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(`http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`),
|
||||
metadataBase: new URL(getBaseUrl()),
|
||||
title: 'Enclava Platform',
|
||||
description: 'Secure AI processing platform with plugin-based architecture and confidential computing',
|
||||
keywords: ['AI', 'Enclava', 'Confidential Computing', 'LLM', 'TEE'],
|
||||
@@ -26,7 +39,7 @@ export const metadata: Metadata = {
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
locale: 'en_US',
|
||||
url: `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`,
|
||||
url: getBaseUrl(),
|
||||
title: 'Enclava Platform',
|
||||
description: 'Secure AI processing platform with plugin-based architecture and confidential computing',
|
||||
siteName: 'Enclava',
|
||||
|
||||
@@ -91,8 +91,9 @@ export function DocumentUpload({ collections, selectedCollection, onDocumentUplo
|
||||
updateProgress(60)
|
||||
|
||||
await uploadFile(
|
||||
'/api-internal/v1/rag/documents',
|
||||
uploadingFile.file,
|
||||
'/api-internal/v1/rag/documents',
|
||||
(progress) => updateProgress(progress),
|
||||
{ collection_id: targetCollection }
|
||||
)
|
||||
|
||||
|
||||
@@ -18,6 +18,16 @@ import {
|
||||
import { User, Settings, Lock, LogOut, ChevronDown } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
|
||||
// Helper function to get API URL with proper protocol
|
||||
const getApiUrl = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const protocol = window.location.protocol.slice(0, -1) // Remove ':' from 'https:'
|
||||
const host = window.location.hostname
|
||||
return `${protocol}://${host}`
|
||||
}
|
||||
return `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
|
||||
}
|
||||
|
||||
export function UserMenu() {
|
||||
const { user, logout } = useAuth()
|
||||
const { toast } = useToast()
|
||||
@@ -62,7 +72,7 @@ export function UserMenu() {
|
||||
throw new Error('Authentication required')
|
||||
}
|
||||
|
||||
const response = await fetch('/api-internal/v1/auth/change-password', {
|
||||
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/change-password`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -4,6 +4,16 @@ import { createContext, useContext, useState, useEffect, ReactNode } from "react
|
||||
import { useRouter } from "next/navigation"
|
||||
import { tokenManager } from "@/lib/token-manager"
|
||||
|
||||
// Helper function to get API URL with proper protocol
|
||||
const getApiUrl = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const protocol = window.location.protocol.slice(0, -1) // Remove ':' from 'https:'
|
||||
const host = window.location.hostname
|
||||
return `${protocol}://${host}`
|
||||
}
|
||||
return `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string
|
||||
email: string
|
||||
@@ -84,7 +94,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const token = await tokenManager.getAccessToken()
|
||||
if (!token) return
|
||||
|
||||
const response = await fetch('/api-internal/v1/auth/me', {
|
||||
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/me`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
},
|
||||
@@ -114,7 +124,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
setIsLoading(true)
|
||||
|
||||
try {
|
||||
const response = await fetch('/api-internal/v1/auth/login', {
|
||||
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
import axios from 'axios';
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || '';
|
||||
// Dynamic base URL with protocol detection
|
||||
const getApiBaseUrl = (): string => {
|
||||
if (typeof window !== 'undefined') {
|
||||
// Client-side: use the same protocol as the current page
|
||||
const protocol = window.location.protocol.slice(0, -1); // Remove ':' from 'https:'
|
||||
const host = window.location.hostname;
|
||||
return `${protocol}://${host}`;
|
||||
}
|
||||
|
||||
// Server-side: use environment variable or default to localhost
|
||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'localhost';
|
||||
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
||||
return `${protocol}://${baseUrl}`;
|
||||
};
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
baseURL: getApiBaseUrl(),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
@@ -36,7 +49,7 @@ axiosInstance.interceptors.response.use(
|
||||
try {
|
||||
const refreshToken = Cookies.get('refresh_token');
|
||||
if (refreshToken) {
|
||||
const response = await axios.post(`${API_BASE_URL}/api/auth/refresh`, {
|
||||
const response = await axios.post(`${getApiBaseUrl()}/api/auth/refresh`, {
|
||||
refresh_token: refreshToken,
|
||||
});
|
||||
|
||||
|
||||
@@ -76,12 +76,20 @@ export const downloadFileFromData = (
|
||||
export const uploadFile = async (
|
||||
file: File,
|
||||
url: string,
|
||||
onProgress?: (progress: number) => void
|
||||
onProgress?: (progress: number) => void,
|
||||
additionalData?: Record<string, any>
|
||||
): Promise<any> => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
// Add additional form data if provided
|
||||
if (additionalData) {
|
||||
Object.entries(additionalData).forEach(([key, value]) => {
|
||||
formData.append(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Reference in New Issue
Block a user