Add frontend access instructions to README

Added instructions to access the frontend after running the container.
This commit is contained in:
Zimeng Xiong
2025-11-22 13:57:13 -08:00
parent 79bbeabb29
commit c8971e62d2
4 changed files with 3 additions and 92 deletions
-3
View File
@@ -1,3 +0,0 @@
[submodule "excalidraw"]
path = excalidraw
url = git@github.com:ZimengXiong/excalidraw.git
-84
View File
@@ -1,84 +0,0 @@
# ExcaliDash Docker Setup
This Docker setup containerizes the ExcaliDash application with a multi-container architecture.
## Architecture
- **Frontend**: React/Vite app served by Nginx
- **Backend**: Express.js API with Socket.IO
- **Database**: SQLite (persisted in Docker volume)
## Single Port Exposure
The application exposes only **port 6767** externally, which serves the frontend. The frontend's Nginx acts as a reverse proxy to route:
- `/api/*` requests to the backend container
- `/socket.io/*` WebSocket connections to the backend container
All inter-container communication happens on an internal Docker network.
## Quick Start
### Option 1: Use Pre-built Images from Docker Hub (Recommended)
Pull and run the latest multi-platform images:
```bash
docker compose -f docker-compose.prod.yml up -d
```
### Option 2: Build Locally
Build and run all services locally:
```bash
docker compose up -d --build
```
### Access the application:
[http://localhost:6767](http://localhost:6767)
## Publishing to Docker Hub
### Build and Push Multi-Platform Images
The `publish-docker.sh` script builds images for multiple platforms (amd64, arm64) and pushes them to Docker Hub:
```bash
# Build and push with 'latest' tag
./publish-docker.sh
# Build and push with a specific version
./publish-docker.sh v1.0.0
```
## Database
The SQLite database is stored in a Docker volume named `backend-data` which persists data across container restarts. Database migrations run automatically when the backend container starts.
## Environment Variables
Default configuration works out of the box. To customize:
Create `.env` files in `backend/` or `frontend/` directories:
**Backend `.env`:**
```
PORT=8000
NODE_ENV=production
```
**Frontend `.env`:**
```
VITE_API_URL=/api
```
## Port Mapping
- **6767** (external) → **80** (frontend nginx) → Routes to backend on internal network
- **8000** (internal only) - Backend API server
Only port 6767 is accessible from outside the Docker network.
+3 -1
View File
@@ -2,7 +2,7 @@
# ExcaliDash v0.1.0 # ExcaliDash v0.1.0
A beautiful, self hosted dashboard and organizer for [Excalidraw](https://github.com/excalidraw/excalidraw) with live collaboration. A self hosted dashboard and organizer for [Excalidraw](https://github.com/excalidraw/excalidraw) with live collaboration.
![](dashboard.png) ![](dashboard.png)
![](demo.gif) ![](demo.gif)
@@ -52,6 +52,8 @@ docker compose -f docker-compose.prod.yml pull
# Run container # Run container
docker compose -f docker-compose.prod.yml up -d docker compose -f docker-compose.prod.yml up -d
# Access the frontend at localhost:6767
``` ```
## Docker build ## Docker build
-4
View File
@@ -93,7 +93,6 @@ export const Dashboard: React.FC = () => {
type SortField = 'name' | 'createdAt' | 'updatedAt'; type SortField = 'name' | 'createdAt' | 'updatedAt';
type SortDirection = 'asc' | 'desc'; type SortDirection = 'asc' | 'desc';
// ... (rest of existing state)
const searchInputRef = useRef<HTMLInputElement>(null); const searchInputRef = useRef<HTMLInputElement>(null);
@@ -126,7 +125,6 @@ export const Dashboard: React.FC = () => {
refreshData(); refreshData();
}, [refreshData]); }, [refreshData]);
// ... (Drag selection logic remains same)
// Drag File State // Drag File State
const [isDraggingFile, setIsDraggingFile] = useState(false); const [isDraggingFile, setIsDraggingFile] = useState(false);
const dragCounter = useRef(0); const dragCounter = useRef(0);
@@ -222,7 +220,6 @@ export const Dashboard: React.FC = () => {
setDragCurrent({ x: e.clientX, y: e.clientY }); setDragCurrent({ x: e.clientX, y: e.clientY });
}; };
// ... (Sorting logic remains same)
const sortedDrawings = React.useMemo(() => { const sortedDrawings = React.useMemo(() => {
return [...drawings].sort((a, b) => { return [...drawings].sort((a, b) => {
const { field, direction } = sortConfig; const { field, direction } = sortConfig;
@@ -488,7 +485,6 @@ export const Dashboard: React.FC = () => {
} }
}; };
// ... (rest of handlers like Create/Edit/Delete Collection remain same)
const handleMoveToCollection = async (id: string, collectionId: string | null) => { const handleMoveToCollection = async (id: string, collectionId: string | null) => {
setDrawings(prev => { setDrawings(prev => {
return prev.map(d => d.id === id ? { ...d, collectionId } : d) return prev.map(d => d.id === id ? { ...d, collectionId } : d)