mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-16 17:55:55 -05:00
Compare commits
5 Commits
docs/deplo
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d4dcbd9e0 | ||
|
|
074be7aea6 | ||
|
|
39d28b24fc | ||
|
|
bf79a7748a | ||
|
|
649d4ab7f5 |
9
.github/workflows/platform-backend-ci.yml
vendored
9
.github/workflows/platform-backend-ci.yml
vendored
@@ -41,13 +41,18 @@ jobs:
|
||||
ports:
|
||||
- 6379:6379
|
||||
rabbitmq:
|
||||
image: rabbitmq:3.12-management
|
||||
image: rabbitmq:4.1.4
|
||||
ports:
|
||||
- 5672:5672
|
||||
- 15672:15672
|
||||
env:
|
||||
RABBITMQ_DEFAULT_USER: ${{ env.RABBITMQ_DEFAULT_USER }}
|
||||
RABBITMQ_DEFAULT_PASS: ${{ env.RABBITMQ_DEFAULT_PASS }}
|
||||
options: >-
|
||||
--health-cmd "rabbitmq-diagnostics -q ping"
|
||||
--health-interval 30s
|
||||
--health-timeout 10s
|
||||
--health-retries 5
|
||||
--health-start-period 10s
|
||||
clamav:
|
||||
image: clamav/clamav-debian:latest
|
||||
ports:
|
||||
|
||||
6
.github/workflows/platform-frontend-ci.yml
vendored
6
.github/workflows/platform-frontend-ci.yml
vendored
@@ -6,10 +6,16 @@ on:
|
||||
paths:
|
||||
- ".github/workflows/platform-frontend-ci.yml"
|
||||
- "autogpt_platform/frontend/**"
|
||||
- "autogpt_platform/backend/Dockerfile"
|
||||
- "autogpt_platform/docker-compose.yml"
|
||||
- "autogpt_platform/docker-compose.platform.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/platform-frontend-ci.yml"
|
||||
- "autogpt_platform/frontend/**"
|
||||
- "autogpt_platform/backend/Dockerfile"
|
||||
- "autogpt_platform/docker-compose.yml"
|
||||
- "autogpt_platform/docker-compose.platform.yml"
|
||||
merge_group:
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
@@ -53,63 +53,6 @@ COPY autogpt_platform/backend/backend/data/partial_types.py ./backend/data/parti
|
||||
COPY autogpt_platform/backend/gen_prisma_types_stub.py ./
|
||||
RUN poetry run prisma generate && poetry run gen-prisma-stub
|
||||
|
||||
# ============================== BACKEND SERVER ============================== #
|
||||
|
||||
FROM debian:13-slim AS server
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV POETRY_HOME=/opt/poetry \
|
||||
POETRY_NO_INTERACTION=1 \
|
||||
POETRY_VIRTUALENVS_CREATE=true \
|
||||
POETRY_VIRTUALENVS_IN_PROJECT=true \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
ENV PATH=/opt/poetry/bin:$PATH
|
||||
|
||||
# Install Python, FFmpeg, ImageMagick, and CLI tools for agent use.
|
||||
# bubblewrap provides OS-level sandbox (whitelist-only FS + no network)
|
||||
# for the bash_exec MCP tool.
|
||||
# Using --no-install-recommends saves ~650MB by skipping unnecessary deps like llvm, mesa, etc.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3.13 \
|
||||
python3-pip \
|
||||
ffmpeg \
|
||||
imagemagick \
|
||||
jq \
|
||||
ripgrep \
|
||||
tree \
|
||||
bubblewrap \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /usr/local/lib/python3* /usr/local/lib/python3*
|
||||
COPY --from=builder /usr/local/bin/poetry /usr/local/bin/poetry
|
||||
# Copy Node.js installation for Prisma
|
||||
COPY --from=builder /usr/bin/node /usr/bin/node
|
||||
COPY --from=builder /usr/lib/node_modules /usr/lib/node_modules
|
||||
COPY --from=builder /usr/bin/npm /usr/bin/npm
|
||||
COPY --from=builder /usr/bin/npx /usr/bin/npx
|
||||
COPY --from=builder /root/.cache/prisma-python/binaries /root/.cache/prisma-python/binaries
|
||||
|
||||
WORKDIR /app/autogpt_platform/backend
|
||||
|
||||
# Copy only the .venv from builder (not the entire /app directory)
|
||||
# The .venv includes the generated Prisma client
|
||||
COPY --from=builder /app/autogpt_platform/backend/.venv ./.venv
|
||||
ENV PATH="/app/autogpt_platform/backend/.venv/bin:$PATH"
|
||||
|
||||
# Copy dependency files + autogpt_libs (path dependency)
|
||||
COPY autogpt_platform/autogpt_libs /app/autogpt_platform/autogpt_libs
|
||||
COPY autogpt_platform/backend/poetry.lock autogpt_platform/backend/pyproject.toml ./
|
||||
|
||||
# Copy backend code + docs (for Copilot docs search)
|
||||
COPY autogpt_platform/backend ./
|
||||
COPY docs /app/docs
|
||||
RUN poetry install --no-ansi --only-root
|
||||
|
||||
ENV PORT=8000
|
||||
|
||||
CMD ["poetry", "run", "rest"]
|
||||
|
||||
# =============================== DB MIGRATOR =============================== #
|
||||
|
||||
# Lightweight migrate stage - only needs Prisma CLI, not full Python environment
|
||||
@@ -141,3 +84,59 @@ COPY autogpt_platform/backend/schema.prisma ./
|
||||
COPY autogpt_platform/backend/backend/data/partial_types.py ./backend/data/partial_types.py
|
||||
COPY autogpt_platform/backend/gen_prisma_types_stub.py ./
|
||||
COPY autogpt_platform/backend/migrations ./migrations
|
||||
|
||||
# ============================== BACKEND SERVER ============================== #
|
||||
|
||||
FROM debian:13-slim AS server
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install Python, FFmpeg, ImageMagick, and CLI tools for agent use.
|
||||
# bubblewrap provides OS-level sandbox (whitelist-only FS + no network)
|
||||
# for the bash_exec MCP tool.
|
||||
# Using --no-install-recommends saves ~650MB by skipping unnecessary deps like llvm, mesa, etc.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3.13 \
|
||||
python3-pip \
|
||||
ffmpeg \
|
||||
imagemagick \
|
||||
jq \
|
||||
ripgrep \
|
||||
tree \
|
||||
bubblewrap \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy poetry (build-time only, for `poetry install --only-root` to create entry points)
|
||||
COPY --from=builder /usr/local/lib/python3* /usr/local/lib/python3*
|
||||
COPY --from=builder /usr/local/bin/poetry /usr/local/bin/poetry
|
||||
# Copy Node.js installation for Prisma
|
||||
COPY --from=builder /usr/bin/node /usr/bin/node
|
||||
COPY --from=builder /usr/lib/node_modules /usr/lib/node_modules
|
||||
COPY --from=builder /usr/bin/npm /usr/bin/npm
|
||||
COPY --from=builder /usr/bin/npx /usr/bin/npx
|
||||
COPY --from=builder /root/.cache/prisma-python/binaries /root/.cache/prisma-python/binaries
|
||||
|
||||
WORKDIR /app/autogpt_platform/backend
|
||||
|
||||
# Copy only the .venv from builder (not the entire /app directory)
|
||||
# The .venv includes the generated Prisma client
|
||||
COPY --from=builder /app/autogpt_platform/backend/.venv ./.venv
|
||||
ENV PATH="/app/autogpt_platform/backend/.venv/bin:$PATH"
|
||||
|
||||
# Copy dependency files + autogpt_libs (path dependency)
|
||||
COPY autogpt_platform/autogpt_libs /app/autogpt_platform/autogpt_libs
|
||||
COPY autogpt_platform/backend/poetry.lock autogpt_platform/backend/pyproject.toml ./
|
||||
|
||||
# Copy backend code + docs (for Copilot docs search)
|
||||
COPY autogpt_platform/backend ./
|
||||
COPY docs /app/docs
|
||||
# Install the project package to create entry point scripts in .venv/bin/
|
||||
# (e.g., rest, executor, ws, db, scheduler, notification - see [tool.poetry.scripts])
|
||||
RUN POETRY_VIRTUALENVS_CREATE=true POETRY_VIRTUALENVS_IN_PROJECT=true \
|
||||
poetry install --no-ansi --only-root
|
||||
|
||||
ENV PORT=8000
|
||||
|
||||
CMD ["rest"]
|
||||
|
||||
@@ -23,6 +23,7 @@ from .model import (
|
||||
ChatSession,
|
||||
append_and_save_message,
|
||||
create_chat_session,
|
||||
delete_chat_session,
|
||||
get_chat_session,
|
||||
get_user_sessions,
|
||||
)
|
||||
@@ -211,6 +212,43 @@ async def create_session(
|
||||
)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/sessions/{session_id}",
|
||||
dependencies=[Security(auth.requires_user)],
|
||||
status_code=204,
|
||||
responses={404: {"description": "Session not found or access denied"}},
|
||||
)
|
||||
async def delete_session(
|
||||
session_id: str,
|
||||
user_id: Annotated[str, Security(auth.get_user_id)],
|
||||
) -> Response:
|
||||
"""
|
||||
Delete a chat session.
|
||||
|
||||
Permanently removes a chat session and all its messages.
|
||||
Only the owner can delete their sessions.
|
||||
|
||||
Args:
|
||||
session_id: The session ID to delete.
|
||||
user_id: The authenticated user's ID.
|
||||
|
||||
Returns:
|
||||
204 No Content on success.
|
||||
|
||||
Raises:
|
||||
HTTPException: 404 if session not found or not owned by user.
|
||||
"""
|
||||
deleted = await delete_chat_session(session_id, user_id)
|
||||
|
||||
if not deleted:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Session {session_id} not found or access denied",
|
||||
)
|
||||
|
||||
return Response(status_code=204)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/sessions/{session_id}",
|
||||
)
|
||||
|
||||
@@ -53,7 +53,7 @@ services:
|
||||
|
||||
rabbitmq:
|
||||
<<: *agpt-services
|
||||
image: rabbitmq:management
|
||||
image: rabbitmq:4.1.4
|
||||
container_name: rabbitmq
|
||||
healthcheck:
|
||||
test: rabbitmq-diagnostics -q ping
|
||||
@@ -66,7 +66,6 @@ services:
|
||||
- RABBITMQ_DEFAULT_PASS=k0VMxyIJF9S35f3x2uaw5IWAl6Y536O7
|
||||
ports:
|
||||
- "5672:5672"
|
||||
- "15672:15672"
|
||||
clamav:
|
||||
image: clamav/clamav-debian:latest
|
||||
ports:
|
||||
|
||||
@@ -75,7 +75,7 @@ services:
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
rabbitmq:
|
||||
image: rabbitmq:management
|
||||
image: rabbitmq:4.1.4
|
||||
container_name: rabbitmq
|
||||
healthcheck:
|
||||
test: rabbitmq-diagnostics -q ping
|
||||
@@ -88,14 +88,13 @@ services:
|
||||
<<: *backend-env
|
||||
ports:
|
||||
- "5672:5672"
|
||||
- "15672:15672"
|
||||
|
||||
rest_server:
|
||||
build:
|
||||
context: ../
|
||||
dockerfile: autogpt_platform/backend/Dockerfile
|
||||
target: server
|
||||
command: ["python", "-m", "backend.rest"]
|
||||
command: ["rest"] # points to entry in [tool.poetry.scripts] in pyproject.toml
|
||||
develop:
|
||||
watch:
|
||||
- path: ./
|
||||
@@ -128,7 +127,7 @@ services:
|
||||
context: ../
|
||||
dockerfile: autogpt_platform/backend/Dockerfile
|
||||
target: server
|
||||
command: ["python", "-m", "backend.exec"]
|
||||
command: ["executor"] # points to entry in [tool.poetry.scripts] in pyproject.toml
|
||||
develop:
|
||||
watch:
|
||||
- path: ./
|
||||
@@ -163,7 +162,7 @@ services:
|
||||
context: ../
|
||||
dockerfile: autogpt_platform/backend/Dockerfile
|
||||
target: server
|
||||
command: ["python", "-m", "backend.ws"]
|
||||
command: ["ws"] # points to entry in [tool.poetry.scripts] in pyproject.toml
|
||||
develop:
|
||||
watch:
|
||||
- path: ./
|
||||
@@ -196,7 +195,7 @@ services:
|
||||
context: ../
|
||||
dockerfile: autogpt_platform/backend/Dockerfile
|
||||
target: server
|
||||
command: ["python", "-m", "backend.db"]
|
||||
command: ["db"] # points to entry in [tool.poetry.scripts] in pyproject.toml
|
||||
develop:
|
||||
watch:
|
||||
- path: ./
|
||||
@@ -225,7 +224,7 @@ services:
|
||||
context: ../
|
||||
dockerfile: autogpt_platform/backend/Dockerfile
|
||||
target: server
|
||||
command: ["python", "-m", "backend.scheduler"]
|
||||
command: ["scheduler"] # points to entry in [tool.poetry.scripts] in pyproject.toml
|
||||
develop:
|
||||
watch:
|
||||
- path: ./
|
||||
@@ -273,7 +272,7 @@ services:
|
||||
context: ../
|
||||
dockerfile: autogpt_platform/backend/Dockerfile
|
||||
target: server
|
||||
command: ["python", "-m", "backend.notification"]
|
||||
command: ["notification"] # points to entry in [tool.poetry.scripts] in pyproject.toml
|
||||
develop:
|
||||
watch:
|
||||
- path: ./
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
// TODO: Replace with modern Dialog component when available
|
||||
import DeleteConfirmDialog from "@/components/__legacy__/delete-confirm-dialog";
|
||||
import { ChatContainer } from "./components/ChatContainer/ChatContainer";
|
||||
import { ChatSidebar } from "./components/ChatSidebar/ChatSidebar";
|
||||
import { MobileDrawer } from "./components/MobileDrawer/MobileDrawer";
|
||||
@@ -31,6 +33,12 @@ export function CopilotPage() {
|
||||
handleDrawerOpenChange,
|
||||
handleSelectSession,
|
||||
handleNewChat,
|
||||
// Delete functionality
|
||||
sessionToDelete,
|
||||
isDeleting,
|
||||
handleDeleteClick,
|
||||
handleConfirmDelete,
|
||||
handleCancelDelete,
|
||||
} = useCopilotPage();
|
||||
|
||||
if (isUserLoading || !isLoggedIn) {
|
||||
@@ -48,7 +56,19 @@ export function CopilotPage() {
|
||||
>
|
||||
{!isMobile && <ChatSidebar />}
|
||||
<div className="relative flex h-full w-full flex-col overflow-hidden bg-[#f8f8f9] px-0">
|
||||
{isMobile && <MobileHeader onOpenDrawer={handleOpenDrawer} />}
|
||||
{isMobile && (
|
||||
<MobileHeader
|
||||
onOpenDrawer={handleOpenDrawer}
|
||||
showDelete={!!sessionId}
|
||||
isDeleting={isDeleting}
|
||||
onDelete={() => {
|
||||
const session = sessions.find((s) => s.id === sessionId);
|
||||
if (session) {
|
||||
handleDeleteClick(session.id, session.title);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<ChatContainer
|
||||
messages={messages}
|
||||
@@ -75,6 +95,16 @@ export function CopilotPage() {
|
||||
onOpenChange={handleDrawerOpenChange}
|
||||
/>
|
||||
)}
|
||||
{/* Delete confirmation dialog - rendered at top level for proper z-index on mobile */}
|
||||
{isMobile && (
|
||||
<DeleteConfirmDialog
|
||||
entityType="chat"
|
||||
entityName={sessionToDelete?.title || "Untitled chat"}
|
||||
open={!!sessionToDelete}
|
||||
onOpenChange={(open) => !open && handleCancelDelete()}
|
||||
onDoDelete={handleConfirmDelete}
|
||||
/>
|
||||
)}
|
||||
</SidebarProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
"use client";
|
||||
import { useGetV2ListSessions } from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import {
|
||||
getGetV2ListSessionsQueryKey,
|
||||
useDeleteV2DeleteSession,
|
||||
useGetV2ListSessions,
|
||||
} from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner";
|
||||
import { Text } from "@/components/atoms/Text/Text";
|
||||
import { toast } from "@/components/molecules/Toast/use-toast";
|
||||
// TODO: Replace with modern Dialog component when available
|
||||
import DeleteConfirmDialog from "@/components/__legacy__/delete-confirm-dialog";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
@@ -12,18 +19,52 @@ import {
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { PlusCircleIcon, PlusIcon } from "@phosphor-icons/react";
|
||||
import { PlusCircleIcon, PlusIcon, TrashIcon } from "@phosphor-icons/react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { motion } from "framer-motion";
|
||||
import { useState } from "react";
|
||||
import { parseAsString, useQueryState } from "nuqs";
|
||||
|
||||
export function ChatSidebar() {
|
||||
const { state } = useSidebar();
|
||||
const isCollapsed = state === "collapsed";
|
||||
const [sessionId, setSessionId] = useQueryState("sessionId", parseAsString);
|
||||
const [sessionToDelete, setSessionToDelete] = useState<{
|
||||
id: string;
|
||||
title: string | null | undefined;
|
||||
} | null>(null);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: sessionsResponse, isLoading: isLoadingSessions } =
|
||||
useGetV2ListSessions({ limit: 50 });
|
||||
|
||||
const { mutate: deleteSession, isPending: isDeleting } =
|
||||
useDeleteV2DeleteSession({
|
||||
mutation: {
|
||||
onSuccess: () => {
|
||||
// Invalidate sessions list to refetch
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getGetV2ListSessionsQueryKey(),
|
||||
});
|
||||
// If we deleted the current session, clear selection
|
||||
if (sessionToDelete?.id === sessionId) {
|
||||
setSessionId(null);
|
||||
}
|
||||
setSessionToDelete(null);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: "Failed to delete chat",
|
||||
description:
|
||||
error instanceof Error ? error.message : "An error occurred",
|
||||
variant: "destructive",
|
||||
});
|
||||
setSessionToDelete(null);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const sessions =
|
||||
sessionsResponse?.status === 200 ? sessionsResponse.data.sessions : [];
|
||||
|
||||
@@ -35,6 +76,22 @@ export function ChatSidebar() {
|
||||
setSessionId(id);
|
||||
}
|
||||
|
||||
function handleDeleteClick(
|
||||
e: React.MouseEvent,
|
||||
id: string,
|
||||
title: string | null | undefined,
|
||||
) {
|
||||
e.stopPropagation(); // Prevent session selection
|
||||
if (isDeleting) return; // Prevent double-click during deletion
|
||||
setSessionToDelete({ id, title });
|
||||
}
|
||||
|
||||
function handleConfirmDelete() {
|
||||
if (sessionToDelete) {
|
||||
deleteSession({ sessionId: sessionToDelete.id });
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(dateString: string) {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
@@ -61,6 +118,7 @@ export function ChatSidebar() {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sidebar
|
||||
variant="inset"
|
||||
collapsible="icon"
|
||||
@@ -130,15 +188,18 @@ export function ChatSidebar() {
|
||||
</p>
|
||||
) : (
|
||||
sessions.map((session) => (
|
||||
<button
|
||||
<div
|
||||
key={session.id}
|
||||
onClick={() => handleSelectSession(session.id)}
|
||||
className={cn(
|
||||
"w-full rounded-lg px-3 py-2.5 text-left transition-colors",
|
||||
"group relative w-full rounded-lg transition-colors",
|
||||
session.id === sessionId
|
||||
? "bg-zinc-100"
|
||||
: "hover:bg-zinc-50",
|
||||
)}
|
||||
>
|
||||
<button
|
||||
onClick={() => handleSelectSession(session.id)}
|
||||
className="w-full px-3 py-2.5 pr-10 text-left"
|
||||
>
|
||||
<div className="flex min-w-0 max-w-full flex-col overflow-hidden">
|
||||
<div className="min-w-0 max-w-full">
|
||||
@@ -159,6 +220,17 @@ export function ChatSidebar() {
|
||||
</Text>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) =>
|
||||
handleDeleteClick(e, session.id, session.title)
|
||||
}
|
||||
disabled={isDeleting}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 rounded p-1.5 text-zinc-400 opacity-0 transition-all group-hover:opacity-100 hover:bg-red-100 hover:text-red-600 focus-visible:opacity-100 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
aria-label="Delete chat"
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</motion.div>
|
||||
@@ -184,5 +256,14 @@ export function ChatSidebar() {
|
||||
</SidebarFooter>
|
||||
)}
|
||||
</Sidebar>
|
||||
|
||||
<DeleteConfirmDialog
|
||||
entityType="chat"
|
||||
entityName={sessionToDelete?.title || "Untitled chat"}
|
||||
open={!!sessionToDelete}
|
||||
onOpenChange={(open) => !open && setSessionToDelete(null)}
|
||||
onDoDelete={handleConfirmDelete}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,46 @@
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { NAVBAR_HEIGHT_PX } from "@/lib/constants";
|
||||
import { ListIcon } from "@phosphor-icons/react";
|
||||
import { ListIcon, TrashIcon } from "@phosphor-icons/react";
|
||||
|
||||
interface Props {
|
||||
onOpenDrawer: () => void;
|
||||
showDelete?: boolean;
|
||||
isDeleting?: boolean;
|
||||
onDelete?: () => void;
|
||||
}
|
||||
|
||||
export function MobileHeader({ onOpenDrawer }: Props) {
|
||||
export function MobileHeader({
|
||||
onOpenDrawer,
|
||||
showDelete,
|
||||
isDeleting,
|
||||
onDelete,
|
||||
}: Props) {
|
||||
return (
|
||||
<div
|
||||
className="fixed z-50 flex gap-2"
|
||||
style={{ left: "1rem", top: `${NAVBAR_HEIGHT_PX + 20}px` }}
|
||||
>
|
||||
<Button
|
||||
variant="icon"
|
||||
size="icon"
|
||||
aria-label="Open sessions"
|
||||
onClick={onOpenDrawer}
|
||||
className="fixed z-50 bg-white shadow-md"
|
||||
style={{ left: "1rem", top: `${NAVBAR_HEIGHT_PX + 20}px` }}
|
||||
className="bg-white shadow-md"
|
||||
>
|
||||
<ListIcon width="1.25rem" height="1.25rem" />
|
||||
</Button>
|
||||
{showDelete && onDelete && (
|
||||
<Button
|
||||
variant="icon"
|
||||
size="icon"
|
||||
aria-label="Delete current chat"
|
||||
onClick={onDelete}
|
||||
disabled={isDeleting}
|
||||
className="bg-white text-red-500 shadow-md hover:bg-red-50 hover:text-red-600 disabled:opacity-50"
|
||||
>
|
||||
<TrashIcon width="1.25rem" height="1.25rem" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import { useGetV2ListSessions } from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import {
|
||||
getGetV2ListSessionsQueryKey,
|
||||
useDeleteV2DeleteSession,
|
||||
useGetV2ListSessions,
|
||||
} from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import { toast } from "@/components/molecules/Toast/use-toast";
|
||||
import { useBreakpoint } from "@/lib/hooks/useBreakpoint";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { useChat } from "@ai-sdk/react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { DefaultChatTransport } from "ai";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useChatSession } from "./useChatSession";
|
||||
import { useLongRunningToolPolling } from "./hooks/useLongRunningToolPolling";
|
||||
|
||||
@@ -14,6 +19,11 @@ export function useCopilotPage() {
|
||||
const { isUserLoading, isLoggedIn } = useSupabase();
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
const [pendingMessage, setPendingMessage] = useState<string | null>(null);
|
||||
const [sessionToDelete, setSessionToDelete] = useState<{
|
||||
id: string;
|
||||
title: string | null | undefined;
|
||||
} | null>(null);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const {
|
||||
sessionId,
|
||||
@@ -24,6 +34,30 @@ export function useCopilotPage() {
|
||||
isCreatingSession,
|
||||
} = useChatSession();
|
||||
|
||||
const { mutate: deleteSessionMutation, isPending: isDeleting } =
|
||||
useDeleteV2DeleteSession({
|
||||
mutation: {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getGetV2ListSessionsQueryKey(),
|
||||
});
|
||||
if (sessionToDelete?.id === sessionId) {
|
||||
setSessionId(null);
|
||||
}
|
||||
setSessionToDelete(null);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: "Failed to delete chat",
|
||||
description:
|
||||
error instanceof Error ? error.message : "An error occurred",
|
||||
variant: "destructive",
|
||||
});
|
||||
setSessionToDelete(null);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const breakpoint = useBreakpoint();
|
||||
const isMobile =
|
||||
breakpoint === "base" || breakpoint === "sm" || breakpoint === "md";
|
||||
@@ -143,6 +177,24 @@ export function useCopilotPage() {
|
||||
if (isMobile) setIsDrawerOpen(false);
|
||||
}
|
||||
|
||||
const handleDeleteClick = useCallback(
|
||||
(id: string, title: string | null | undefined) => {
|
||||
if (isDeleting) return;
|
||||
setSessionToDelete({ id, title });
|
||||
},
|
||||
[isDeleting],
|
||||
);
|
||||
|
||||
const handleConfirmDelete = useCallback(() => {
|
||||
if (sessionToDelete) {
|
||||
deleteSessionMutation({ sessionId: sessionToDelete.id });
|
||||
}
|
||||
}, [sessionToDelete, deleteSessionMutation]);
|
||||
|
||||
const handleCancelDelete = useCallback(() => {
|
||||
setSessionToDelete(null);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
sessionId,
|
||||
messages,
|
||||
@@ -165,5 +217,11 @@ export function useCopilotPage() {
|
||||
handleDrawerOpenChange,
|
||||
handleSelectSession,
|
||||
handleNewChat,
|
||||
// Delete functionality
|
||||
sessionToDelete,
|
||||
isDeleting,
|
||||
handleDeleteClick,
|
||||
handleConfirmDelete,
|
||||
handleCancelDelete,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1151,6 +1151,36 @@
|
||||
}
|
||||
},
|
||||
"/api/chat/sessions/{session_id}": {
|
||||
"delete": {
|
||||
"tags": ["v2", "chat", "chat"],
|
||||
"summary": "Delete Session",
|
||||
"description": "Delete a chat session.\n\nPermanently removes a chat session and all its messages.\nOnly the owner can delete their sessions.\n\nArgs:\n session_id: The session ID to delete.\n user_id: The authenticated user's ID.\n\nReturns:\n 204 No Content on success.\n\nRaises:\n HTTPException: 404 if session not found or not owned by user.",
|
||||
"operationId": "deleteV2DeleteSession",
|
||||
"security": [{ "HTTPBearerJWT": [] }],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "session_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": { "type": "string", "title": "Session Id" }
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": { "description": "Successful Response" },
|
||||
"401": {
|
||||
"$ref": "#/components/responses/HTTP401NotAuthenticatedError"
|
||||
},
|
||||
"404": { "description": "Session not found or access denied" },
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"tags": ["v2", "chat", "chat"],
|
||||
"summary": "Get Session",
|
||||
|
||||
@@ -115,7 +115,7 @@ const DialogFooter = ({
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
## Advanced Setup
|
||||
|
||||
* [Advanced Setup](advanced_setup.md)
|
||||
* [Deployment Environment Variables](deployment-environment-variables.md)
|
||||
|
||||
## Building Blocks
|
||||
|
||||
|
||||
@@ -1,397 +0,0 @@
|
||||
# Deployment Environment Variables
|
||||
|
||||
This guide documents **all environment variables that must be configured** when deploying AutoGPT to a new server or environment. Use this as a checklist to ensure your deployment works correctly.
|
||||
|
||||
## Quick Reference: What MUST Change
|
||||
|
||||
When deploying to a new server, these variables **must** be updated from their localhost defaults:
|
||||
|
||||
| Variable | Location | Default | Purpose |
|
||||
|----------|----------|---------|---------|
|
||||
| `SITE_URL` | `.env` | `http://localhost:3000` | Frontend URL for auth redirects |
|
||||
| `API_EXTERNAL_URL` | `.env` | `http://localhost:8000` | Public Supabase API URL |
|
||||
| `SUPABASE_PUBLIC_URL` | `.env` | `http://localhost:8000` | Studio dashboard URL |
|
||||
| `PLATFORM_BASE_URL` | `backend/.env` | `http://localhost:8000` | Backend platform URL |
|
||||
| `FRONTEND_BASE_URL` | `backend/.env` | `http://localhost:3000` | Frontend URL for webhooks/OAuth |
|
||||
| `NEXT_PUBLIC_SUPABASE_URL` | `frontend/.env` | `http://localhost:8000` | Client-side Supabase URL |
|
||||
| `NEXT_PUBLIC_AGPT_SERVER_URL` | `frontend/.env` | `http://localhost:8006/api` | Client-side backend API URL |
|
||||
| `NEXT_PUBLIC_AGPT_WS_SERVER_URL` | `frontend/.env` | `ws://localhost:8001/ws` | Client-side WebSocket URL |
|
||||
| `NEXT_PUBLIC_FRONTEND_BASE_URL` | `frontend/.env` | `http://localhost:3000` | Client-side frontend URL |
|
||||
|
||||
---
|
||||
|
||||
## Configuration Files
|
||||
|
||||
AutoGPT uses multiple `.env` files across different components:
|
||||
|
||||
```text
|
||||
autogpt_platform/
|
||||
├── .env # Supabase/infrastructure config
|
||||
├── backend/
|
||||
│ ├── .env.default # Backend defaults (DO NOT EDIT)
|
||||
│ └── .env # Your backend overrides
|
||||
└── frontend/
|
||||
├── .env.default # Frontend defaults (DO NOT EDIT)
|
||||
└── .env # Your frontend overrides
|
||||
```
|
||||
|
||||
**Loading Order** (later overrides earlier):
|
||||
|
||||
1. `*.env.default` - Base defaults
|
||||
2. `*.env` - Your overrides
|
||||
3. Docker `environment:` section
|
||||
4. Shell environment variables
|
||||
|
||||
---
|
||||
|
||||
## 1. URL Configuration (REQUIRED)
|
||||
|
||||
These URLs must be updated to match your deployment domain/IP.
|
||||
|
||||
### Root `.env` (Supabase)
|
||||
|
||||
```bash
|
||||
# Auth redirects - where users return after login
|
||||
SITE_URL=https://your-domain.com:3000
|
||||
|
||||
# Public API URL - exposed to clients
|
||||
API_EXTERNAL_URL=https://your-domain.com:8000
|
||||
|
||||
# Studio dashboard URL
|
||||
SUPABASE_PUBLIC_URL=https://your-domain.com:8000
|
||||
```
|
||||
|
||||
### Backend `.env`
|
||||
|
||||
```bash
|
||||
# Platform URLs for webhooks and OAuth callbacks
|
||||
PLATFORM_BASE_URL=https://your-domain.com:8000
|
||||
FRONTEND_BASE_URL=https://your-domain.com:3000
|
||||
|
||||
# Internal Supabase URL (use Docker service name if containerized)
|
||||
SUPABASE_URL=http://kong:8000 # Docker
|
||||
# SUPABASE_URL=https://your-domain.com:8000 # External
|
||||
```
|
||||
|
||||
### Frontend `.env`
|
||||
|
||||
```bash
|
||||
# Client-side URLs (used in browser)
|
||||
NEXT_PUBLIC_SUPABASE_URL=https://your-domain.com:8000
|
||||
NEXT_PUBLIC_AGPT_SERVER_URL=https://your-domain.com:8006/api
|
||||
NEXT_PUBLIC_AGPT_WS_SERVER_URL=wss://your-domain.com:8001/ws
|
||||
NEXT_PUBLIC_FRONTEND_BASE_URL=https://your-domain.com:3000
|
||||
```
|
||||
|
||||
!!! warning "HTTPS Note"
|
||||
For production, use HTTPS URLs and `wss://` for WebSocket. You'll need a reverse proxy (nginx, Caddy) with SSL certificates.
|
||||
|
||||
!!! info "Port Numbers"
|
||||
The port numbers shown (`:3000`, `:8000`, `:8001`, `:8006`) are internal Docker service ports. In production with a reverse proxy, your public URLs typically won't include port numbers (e.g., `https://your-domain.com` instead of `https://your-domain.com:3000`). Configure your reverse proxy to route external traffic to the internal service ports.
|
||||
|
||||
---
|
||||
|
||||
## 2. Security Keys (MUST REGENERATE)
|
||||
|
||||
These default values are **public** and **must be changed** for production.
|
||||
|
||||
### Root `.env`
|
||||
|
||||
```bash
|
||||
# Database password
|
||||
POSTGRES_PASSWORD=<generate-strong-password>
|
||||
|
||||
# JWT secret for Supabase auth (min 32 chars)
|
||||
JWT_SECRET=<generate-random-string>
|
||||
|
||||
# Supabase keys (regenerate with matching JWT_SECRET)
|
||||
ANON_KEY=<regenerate>
|
||||
SERVICE_ROLE_KEY=<regenerate>
|
||||
|
||||
# Studio dashboard credentials
|
||||
DASHBOARD_USERNAME=<your-username>
|
||||
DASHBOARD_PASSWORD=<strong-password>
|
||||
|
||||
# Encryption keys
|
||||
SECRET_KEY_BASE=<generate-random-string>
|
||||
VAULT_ENC_KEY=<generate-32-char-key> # Run: openssl rand -hex 16
|
||||
```
|
||||
|
||||
### Backend `.env`
|
||||
|
||||
```bash
|
||||
# Must match root POSTGRES_PASSWORD
|
||||
DB_PASS=<same-as-POSTGRES_PASSWORD>
|
||||
|
||||
# Must match root SERVICE_ROLE_KEY
|
||||
SUPABASE_SERVICE_ROLE_KEY=<same-as-SERVICE_ROLE_KEY>
|
||||
|
||||
# Must match root JWT_SECRET
|
||||
JWT_VERIFY_KEY=<same-as-JWT_SECRET>
|
||||
|
||||
# Generate new encryption keys
|
||||
# Run: python -c "from cryptography.fernet import Fernet;print(Fernet.generate_key().decode())"
|
||||
ENCRYPTION_KEY=<generated-fernet-key>
|
||||
UNSUBSCRIBE_SECRET_KEY=<generated-fernet-key>
|
||||
```
|
||||
|
||||
### Generating Keys
|
||||
|
||||
```bash
|
||||
# Generate Fernet encryption key (for ENCRYPTION_KEY, UNSUBSCRIBE_SECRET_KEY)
|
||||
python -c "from cryptography.fernet import Fernet;print(Fernet.generate_key().decode())"
|
||||
|
||||
# Generate random string (for JWT_SECRET, SECRET_KEY_BASE)
|
||||
openssl rand -base64 32
|
||||
|
||||
# Generate 32-character key (for VAULT_ENC_KEY)
|
||||
openssl rand -hex 16
|
||||
|
||||
# Generate Supabase keys (requires matching JWT_SECRET)
|
||||
# Use: https://supabase.com/docs/guides/self-hosting/docker#generate-api-keys
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Database Configuration
|
||||
|
||||
### Root `.env`
|
||||
|
||||
```bash
|
||||
POSTGRES_HOST=db # Docker service name or external host
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_PASSWORD=<your-password>
|
||||
```
|
||||
|
||||
### Backend `.env`
|
||||
|
||||
```bash
|
||||
DB_USER=postgres
|
||||
DB_PASS=<your-password>
|
||||
DB_NAME=postgres
|
||||
DB_PORT=5432
|
||||
DB_HOST=localhost # Default is localhost; use 'db' in Docker
|
||||
DB_SCHEMA=platform
|
||||
|
||||
# Connection pooling
|
||||
DB_CONNECTION_LIMIT=12
|
||||
DB_CONNECT_TIMEOUT=60
|
||||
DB_POOL_TIMEOUT=300
|
||||
|
||||
# Full connection URL (auto-constructed from above in .env.default)
|
||||
# Variable substitution is handled automatically; only override if you need custom parameters
|
||||
DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=${DB_SCHEMA}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Service Dependencies
|
||||
|
||||
### Redis
|
||||
|
||||
```bash
|
||||
REDIS_HOST=redis # Docker: 'redis', External: hostname/IP
|
||||
REDIS_PORT=6379
|
||||
# REDIS_PASSWORD= # Uncomment if using authentication
|
||||
```
|
||||
|
||||
### RabbitMQ
|
||||
|
||||
```bash
|
||||
RABBITMQ_DEFAULT_USER=<username>
|
||||
RABBITMQ_DEFAULT_PASS=<strong-password>
|
||||
# In Docker, host is 'rabbitmq'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Default Ports
|
||||
|
||||
| Service | Port | Purpose |
|
||||
|---------|------|---------|
|
||||
| Frontend | 3000 | Next.js web UI |
|
||||
| Kong (Supabase API) | 8000 | API gateway |
|
||||
| WebSocket Server | 8001 | Real-time updates |
|
||||
| Executor | 8002 | Agent execution |
|
||||
| Scheduler | 8003 | Scheduled tasks |
|
||||
| Database Manager | 8005 | DB operations |
|
||||
| REST Server | 8006 | Main API |
|
||||
| Notification Server | 8007 | Notifications |
|
||||
| PostgreSQL | 5432 | Database |
|
||||
| Redis | 6379 | Cache/queue |
|
||||
| RabbitMQ | 5672/15672 | Message queue |
|
||||
| ClamAV | 3310 | Antivirus scanning |
|
||||
|
||||
---
|
||||
|
||||
## 6. OAuth Callbacks
|
||||
|
||||
When configuring OAuth providers, use this callback URL format:
|
||||
|
||||
```text
|
||||
https://your-domain.com/auth/integrations/oauth_callback
|
||||
# Or with explicit port if not using a reverse proxy:
|
||||
# https://your-domain.com:3000/auth/integrations/oauth_callback
|
||||
```
|
||||
|
||||
### Supported OAuth Providers
|
||||
|
||||
| Provider | Env Variables | Setup URL |
|
||||
|----------|---------------|-----------|
|
||||
| GitHub | `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` | [github.com/settings/developers](https://github.com/settings/developers) |
|
||||
| Google | `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` | [console.cloud.google.com](https://console.cloud.google.com/apis/credentials) |
|
||||
| Discord | `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET` | [discord.com/developers](https://discord.com/developers/applications) |
|
||||
| Twitter/X | `TWITTER_CLIENT_ID`, `TWITTER_CLIENT_SECRET` | [developer.x.com](https://developer.x.com) |
|
||||
| Notion | `NOTION_CLIENT_ID`, `NOTION_CLIENT_SECRET` | [developers.notion.com](https://developers.notion.com) |
|
||||
| Linear | `LINEAR_CLIENT_ID`, `LINEAR_CLIENT_SECRET` | [linear.app/settings/api](https://linear.app/settings/api/applications/new) |
|
||||
| Reddit | `REDDIT_CLIENT_ID`, `REDDIT_CLIENT_SECRET` | [reddit.com/prefs/apps](https://reddit.com/prefs/apps) |
|
||||
| Todoist | `TODOIST_CLIENT_ID`, `TODOIST_CLIENT_SECRET` | [developer.todoist.com](https://developer.todoist.com/appconsole.html) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Optional Services
|
||||
|
||||
### AI/LLM Providers
|
||||
|
||||
```bash
|
||||
OPENAI_API_KEY=
|
||||
ANTHROPIC_API_KEY=
|
||||
GROQ_API_KEY=
|
||||
OPEN_ROUTER_API_KEY=
|
||||
NVIDIA_API_KEY=
|
||||
```
|
||||
|
||||
### Email (SMTP)
|
||||
|
||||
```bash
|
||||
# Supabase auth emails
|
||||
SMTP_HOST=smtp.example.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=<username>
|
||||
SMTP_PASS=<password>
|
||||
SMTP_ADMIN_EMAIL=admin@example.com
|
||||
|
||||
# Application emails (Postmark)
|
||||
POSTMARK_SERVER_API_TOKEN=
|
||||
POSTMARK_SENDER_EMAIL=noreply@your-domain.com
|
||||
```
|
||||
|
||||
### Payments (Stripe)
|
||||
|
||||
```bash
|
||||
STRIPE_API_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
```
|
||||
|
||||
### Error Tracking (Sentry)
|
||||
|
||||
```bash
|
||||
SENTRY_DSN=
|
||||
```
|
||||
|
||||
### Analytics (PostHog)
|
||||
|
||||
```bash
|
||||
POSTHOG_API_KEY=
|
||||
POSTHOG_HOST=https://eu.i.posthog.com
|
||||
|
||||
# Frontend
|
||||
NEXT_PUBLIC_POSTHOG_KEY=
|
||||
NEXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Deployment Checklist
|
||||
|
||||
Use this checklist when deploying to a new environment:
|
||||
|
||||
### Pre-deployment
|
||||
|
||||
- [ ] Clone repository and navigate to `autogpt_platform/`
|
||||
- [ ] Copy all `.env.default` files to `.env`
|
||||
- [ ] Determine your deployment domain/IP
|
||||
|
||||
### URL Configuration
|
||||
|
||||
- [ ] Update `SITE_URL` in root `.env`
|
||||
- [ ] Update `API_EXTERNAL_URL` in root `.env`
|
||||
- [ ] Update `SUPABASE_PUBLIC_URL` in root `.env`
|
||||
- [ ] Update `PLATFORM_BASE_URL` in `backend/.env`
|
||||
- [ ] Update `FRONTEND_BASE_URL` in `backend/.env`
|
||||
- [ ] Update all `NEXT_PUBLIC_*` URLs in `frontend/.env`
|
||||
|
||||
### Security
|
||||
|
||||
- [ ] Generate new `POSTGRES_PASSWORD`
|
||||
- [ ] Generate new `JWT_SECRET` (min 32 chars)
|
||||
- [ ] Regenerate `ANON_KEY` and `SERVICE_ROLE_KEY`
|
||||
- [ ] Change `DASHBOARD_USERNAME` and `DASHBOARD_PASSWORD`
|
||||
- [ ] Generate new `ENCRYPTION_KEY` (backend)
|
||||
- [ ] Generate new `UNSUBSCRIBE_SECRET_KEY` (backend)
|
||||
- [ ] Update `DB_PASS` to match `POSTGRES_PASSWORD`
|
||||
- [ ] Update `JWT_VERIFY_KEY` to match `JWT_SECRET`
|
||||
- [ ] Update `SUPABASE_SERVICE_ROLE_KEY` to match
|
||||
|
||||
### Services
|
||||
|
||||
- [ ] Configure Redis connection (if external)
|
||||
- [ ] Configure RabbitMQ credentials
|
||||
- [ ] Configure SMTP for emails (if needed)
|
||||
|
||||
### OAuth (if using integrations)
|
||||
|
||||
- [ ] Register OAuth apps with your callback URL
|
||||
- [ ] Add client IDs and secrets to `backend/.env`
|
||||
|
||||
### Post-deployment
|
||||
|
||||
- [ ] Run `docker compose up -d --build`
|
||||
- [ ] Verify frontend loads at your URL
|
||||
- [ ] Test authentication flow
|
||||
- [ ] Test WebSocket connection (real-time updates)
|
||||
|
||||
---
|
||||
|
||||
## 9. Docker vs External Services
|
||||
|
||||
### Running Everything in Docker (Default)
|
||||
|
||||
The docker-compose files automatically set internal hostnames:
|
||||
|
||||
```yaml
|
||||
# Internal Docker service names (container-to-container communication)
|
||||
# These are set automatically in docker-compose.platform.yml
|
||||
DB_HOST: db
|
||||
REDIS_HOST: redis
|
||||
RABBITMQ_HOST: rabbitmq
|
||||
SUPABASE_URL: http://kong:8000
|
||||
```
|
||||
|
||||
### Using External Services
|
||||
|
||||
If using managed services (AWS RDS, Redis Cloud, etc.), override in your `.env`:
|
||||
|
||||
```bash
|
||||
# External PostgreSQL
|
||||
DB_HOST=your-rds-instance.region.rds.amazonaws.com
|
||||
DB_PORT=5432
|
||||
|
||||
# External Redis
|
||||
REDIS_HOST=your-redis.cache.amazonaws.com
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=<if-required>
|
||||
|
||||
# External Supabase (hosted)
|
||||
SUPABASE_URL=https://your-project.supabase.co
|
||||
SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Getting Started](getting-started.md) - Basic setup guide
|
||||
- [Advanced Setup](advanced_setup.md) - Development configuration
|
||||
- [OAuth & SSO](integrating/oauth-guide.md) - Integration setup
|
||||
Reference in New Issue
Block a user