feat: Add initial local Docker Swarm deployment setup and frontend application structure with project state management.
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
This commit is contained in:
52
deploy/local/README.md
Normal file
52
deploy/local/README.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Local Development with Docker Swarm
|
||||||
|
|
||||||
|
This directory contains the configuration to run the Evrak application locally using Docker Swarm on Windows 11.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. **Docker Desktop**: Ensure Docker Desktop is installed and running.
|
||||||
|
2. **Swarm Mode**: Enable Swarm mode if not already enabled:
|
||||||
|
```powershell
|
||||||
|
docker swarm init
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Deploy
|
||||||
|
|
||||||
|
### 1. Build Images
|
||||||
|
First, build the Docker images locally. `docker stack deploy` does not build images, so this step is required.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
docker compose -f deploy/local/docker-compose.yml build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Deploy to Swarm
|
||||||
|
Deploy the stack to your local Swarm cluster.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
docker stack deploy -c deploy/local/docker-compose.yml evrak
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Verify
|
||||||
|
Check if the services are running:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
docker service ls
|
||||||
|
docker stack ps evrak
|
||||||
|
```
|
||||||
|
|
||||||
|
Access the application:
|
||||||
|
* **Frontend**: http://localhost
|
||||||
|
* **Backend API**: http://localhost:3000
|
||||||
|
* **Database**: localhost:5432
|
||||||
|
|
||||||
|
### 4. Remove Stack
|
||||||
|
To stop and remove the application:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
docker stack rm evrak
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
* **Image not found**: Make sure you ran the build step.
|
||||||
|
* **Ports occupied**: Ensure ports 80, 3000, and 5432 are free on your host machine.
|
||||||
68
deploy/local/docker-compose.yml
Normal file
68
deploy/local/docker-compose.yml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: evrak_user
|
||||||
|
POSTGRES_PASSWORD: evrak_password
|
||||||
|
POSTGRES_DB: evrak
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- evrak-net
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
|
||||||
|
backend:
|
||||||
|
# Note: 'docker stack deploy' ignores 'build'. You must run 'docker compose build' first.
|
||||||
|
build:
|
||||||
|
context: ../../backend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: evrak-backend:local
|
||||||
|
environment:
|
||||||
|
DB_HOST: postgres
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USERNAME: evrak_user
|
||||||
|
DB_PASSWORD: evrak_password
|
||||||
|
DB_DATABASE: evrak
|
||||||
|
PORT: 3000
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
networks:
|
||||||
|
- evrak-net
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ../../frontend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: evrak-frontend:local
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- evrak-net
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
evrak-net:
|
||||||
|
driver: overlay
|
||||||
|
attachable: true
|
||||||
@@ -2,17 +2,24 @@ import React from 'react';
|
|||||||
import { Layout } from 'antd';
|
import { Layout } from 'antd';
|
||||||
import Sidebar from './components/Sidebar';
|
import Sidebar from './components/Sidebar';
|
||||||
import MindMap from './components/MindMap';
|
import MindMap from './components/MindMap';
|
||||||
|
import { useProjectStore } from './store/useProjectStore';
|
||||||
|
|
||||||
const { Sider, Content } = Layout;
|
const { Sider, Content } = Layout;
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
|
const { fetchProjects } = useProjectStore();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
fetchProjects();
|
||||||
|
}, [fetchProjects]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout style={{ height: '100vh' }}>
|
<Layout style={{ height: '100vh' }}>
|
||||||
<Sider width={300} theme="light">
|
<Sider width={300} theme="light" style={{ borderRight: '1px solid #f0f0f0' }}>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
</Sider>
|
</Sider>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Content>
|
<Content style={{ background: '#fff' }}>
|
||||||
<MindMap />
|
<MindMap />
|
||||||
</Content>
|
</Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -16,8 +16,17 @@ interface ProjectState {
|
|||||||
setExpandedKeys: (keys: string[]) => void;
|
setExpandedKeys: (keys: string[]) => void;
|
||||||
setSelectedKey: (key: string | null) => void;
|
setSelectedKey: (key: string | null) => void;
|
||||||
expandNode: (key: string) => void;
|
expandNode: (key: string) => void;
|
||||||
|
fetchProjects: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DUMMY_PROJECTS: Project[] = [
|
||||||
|
{ id: '1', name: 'Genel Merkez', path: 'root', parentId: null },
|
||||||
|
{ id: '2', name: 'Yazılım Departmanı', path: 'root.software', parentId: '1' },
|
||||||
|
{ id: '3', name: 'İnsan Kaynakları', path: 'root.hr', parentId: '1' },
|
||||||
|
{ id: '4', name: 'Evrak Projesi', path: 'root.software.evrak', parentId: '2' },
|
||||||
|
{ id: '5', name: 'Website Yenileme', path: 'root.software.website', parentId: '2' },
|
||||||
|
];
|
||||||
|
|
||||||
export const useProjectStore = create<ProjectState>((set) => ({
|
export const useProjectStore = create<ProjectState>((set) => ({
|
||||||
projects: [],
|
projects: [],
|
||||||
expandedKeys: [],
|
expandedKeys: [],
|
||||||
@@ -31,4 +40,19 @@ export const useProjectStore = create<ProjectState>((set) => ({
|
|||||||
? state.expandedKeys
|
? state.expandedKeys
|
||||||
: [...state.expandedKeys, key],
|
: [...state.expandedKeys, key],
|
||||||
})),
|
})),
|
||||||
|
fetchProjects: async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:3000/projects');
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
set({ projects: data });
|
||||||
|
} else {
|
||||||
|
console.error('Failed to fetch projects');
|
||||||
|
set({ projects: DUMMY_PROJECTS });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching projects:', error);
|
||||||
|
set({ projects: DUMMY_PROJECTS });
|
||||||
|
}
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user