Convert to full-stack app with Docker support
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- Restructured app with backend/ and public/ directories - Created Express backend with /api/search endpoint - Added health check endpoint at /api/health - Optimized Dockerfile with multi-stage build - Added docker-compose.yml for easy deployment - Updated README with comprehensive documentation - Added .dockerignore for optimized builds - Backend listens on 0.0.0.0 for Docker compatibility
This commit is contained in:
parent
20f41d6030
commit
5a7585f755
50
.dockerignore
Normal file
50
.dockerignore
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Kubernetes
|
||||||
|
oramap/
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Other
|
||||||
|
old-project/
|
||||||
|
frontend/node_modules/
|
||||||
|
README copy.md
|
||||||
|
*.md
|
||||||
|
!backend/
|
||||||
|
!public/
|
||||||
|
run_ora_map.sh
|
||||||
|
nfsshare/
|
||||||
|
nul
|
||||||
33
Dockerfile
33
Dockerfile
@ -1,10 +1,35 @@
|
|||||||
FROM node:24-slim
|
# Multi-stage build for Ora Map Application
|
||||||
|
FROM node:20-alpine AS base
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM base AS production
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json ./
|
# Copy backend package files
|
||||||
RUN npm install
|
COPY backend/package*.json ./backend/
|
||||||
|
WORKDIR /app/backend
|
||||||
|
RUN npm install --production
|
||||||
|
|
||||||
COPY . .
|
# Copy backend source and data
|
||||||
|
COPY backend/ ./
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy public frontend files
|
||||||
|
COPY public/ ./public/
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Set environment variable
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
WORKDIR /app/backend
|
||||||
CMD ["node", "server.js"]
|
CMD ["node", "server.js"]
|
||||||
|
|
||||||
|
|||||||
180
README.md
180
README.md
@ -0,0 +1,180 @@
|
|||||||
|
# 🗺️ Ora Map - Family Location Mapping Application
|
||||||
|
|
||||||
|
A full-stack web application for mapping and searching family locations in Yemen using interactive maps.
|
||||||
|
|
||||||
|
## 📋 Table of Contents
|
||||||
|
- [Features](#features)
|
||||||
|
- [Tech Stack](#tech-stack)
|
||||||
|
- [Project Structure](#project-structure)
|
||||||
|
- [Getting Started](#getting-started)
|
||||||
|
- [Docker Deployment](#docker-deployment)
|
||||||
|
- [Development](#development)
|
||||||
|
- [API Endpoints](#api-endpoints)
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- 🔍 **Family Search**: Search for families by name with autocomplete suggestions
|
||||||
|
- 🗺️ **Interactive Map**: Leaflet-based map with multiple tile layer options
|
||||||
|
- 📍 **Location Markers**: View family locations with city information
|
||||||
|
- 🎨 **Modern UI**: Clean and responsive design
|
||||||
|
- 🐳 **Docker Ready**: Containerized for easy deployment
|
||||||
|
- 💚 **Health Checks**: Built-in health monitoring
|
||||||
|
|
||||||
|
## 🛠️ Tech Stack
|
||||||
|
|
||||||
|
**Backend:**
|
||||||
|
- Node.js
|
||||||
|
- Express.js
|
||||||
|
- JSON data storage
|
||||||
|
|
||||||
|
**Frontend:**
|
||||||
|
- HTML5/CSS3
|
||||||
|
- JavaScript (ES6+)
|
||||||
|
- Leaflet.js (interactive maps)
|
||||||
|
- Fuse.js (fuzzy search)
|
||||||
|
|
||||||
|
**DevOps:**
|
||||||
|
- Docker
|
||||||
|
- Docker Compose
|
||||||
|
|
||||||
|
## 📁 Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
oramap/
|
||||||
|
├── backend/
|
||||||
|
│ ├── server.js # Express server
|
||||||
|
│ ├── package.json # Backend dependencies
|
||||||
|
│ └── data/
|
||||||
|
│ └── families.json # Family location data
|
||||||
|
├── public/
|
||||||
|
│ ├── index.html # Frontend HTML
|
||||||
|
│ ├── script.js # Frontend JavaScript
|
||||||
|
│ └── style.css # Styles
|
||||||
|
├── Dockerfile # Multi-stage Docker build
|
||||||
|
├── docker-compose.yml # Docker Compose configuration
|
||||||
|
└── .dockerignore # Docker ignore rules
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Node.js (v18 or higher)
|
||||||
|
- Docker & Docker Compose (optional, for containerized deployment)
|
||||||
|
|
||||||
|
### Local Development
|
||||||
|
|
||||||
|
1. **Install backend dependencies:**
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Start the server:**
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Open your browser:**
|
||||||
|
Navigate to `http://localhost:3000`
|
||||||
|
|
||||||
|
## 🐳 Docker Deployment
|
||||||
|
|
||||||
|
### Using Docker Compose (Recommended)
|
||||||
|
|
||||||
|
1. **Build and start the application:**
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **View logs:**
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Stop the application:**
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Docker directly
|
||||||
|
|
||||||
|
1. **Build the image:**
|
||||||
|
```bash
|
||||||
|
docker build -t oramap:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run the container:**
|
||||||
|
```bash
|
||||||
|
docker run -d -p 3000:3000 --name oramap-app oramap:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check health:**
|
||||||
|
```bash
|
||||||
|
docker ps
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💻 Development
|
||||||
|
|
||||||
|
### Running in Development Mode
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New Families
|
||||||
|
|
||||||
|
Edit `backend/data/families.json` and add entries in the following format:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"family": "Family Name (Hebrew)",
|
||||||
|
"city": "City Name (Hebrew)",
|
||||||
|
"lat": 15.3545,
|
||||||
|
"lng": 44.2064
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📡 API Endpoints
|
||||||
|
|
||||||
|
### Search Families
|
||||||
|
```
|
||||||
|
GET /api/search?family={familyName}
|
||||||
|
```
|
||||||
|
Returns matching family records with location data.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```bash
|
||||||
|
curl "http://localhost:3000/api/search?family=Kafe"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
```
|
||||||
|
GET /api/health
|
||||||
|
```
|
||||||
|
Returns server health status.
|
||||||
|
|
||||||
|
**Example Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"timestamp": "2026-03-24T10:30:00.000Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🗺️ Available Family Names
|
||||||
|
|
||||||
|
- Kafe (קאפח)
|
||||||
|
- Shiheb (שחב-שבח)
|
||||||
|
- Uzeyri (עזירי-עוזרי)
|
||||||
|
- Salumi (סלומי-שלומי)
|
||||||
|
- Afgin (עפג'ין)
|
||||||
|
- Eraki (עראקי)
|
||||||
|
|
||||||
|
## 📝 License
|
||||||
|
|
||||||
|
ISC
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
Contributions, issues, and feature requests are welcome!
|
||||||
10
backend/data/families.json
Normal file
10
backend/data/families.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{ "family": "Kafe (קאפח)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 },
|
||||||
|
{ "family": "Shiheb (שחב-שבח)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 },
|
||||||
|
{ "family": "Uzeyri (עזירי-עוזרי)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 },
|
||||||
|
{ "family": "Uzeyri (עזירי-עוזרי)", "city": "Manakhah (מנאכה)", "lat": 15.3019, "lng": 43.5983 },
|
||||||
|
{ "family": "Uzeyri (עזירי-עוזרי)", "city": "Dhamar (ד'מאר)", "lat": 14.5424, "lng": 44.4056 },
|
||||||
|
{ "family": "Salumi (סלומי-שלומי)", "city": "Al Kafla (אל קפלה)", "lat": 16.0240, "lng": 43.9790 },
|
||||||
|
{ "family": "Afgin (עפג'ין)", "city": "Sa'dah (צעדה)", "lat": 16.9402, "lng": 43.7639 },
|
||||||
|
{ "family": "Eraki (עראקי)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 }
|
||||||
|
]
|
||||||
28
backend/server.js
Normal file
28
backend/server.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
const app = express();
|
||||||
|
const families = require('./data/families.json');
|
||||||
|
|
||||||
|
// Serve static files from the public directory
|
||||||
|
app.use(express.static(path.join(__dirname, '../public')));
|
||||||
|
|
||||||
|
// API endpoint for family search
|
||||||
|
app.get('/api/search', (req, res) => {
|
||||||
|
const query = req.query.family?.toLowerCase();
|
||||||
|
if (!query) {
|
||||||
|
return res.json([]);
|
||||||
|
}
|
||||||
|
const matches = families.filter(fam => fam.family.toLowerCase().includes(query));
|
||||||
|
res.json(matches);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Health check endpoint
|
||||||
|
app.get('/api/health', (req, res) => {
|
||||||
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||||
|
});
|
||||||
|
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
app.listen(port, '0.0.0.0', () => {
|
||||||
|
console.log(`🗺️ Ora Map Server running at http://localhost:${port}`);
|
||||||
|
console.log(`📍 API endpoint: http://localhost:${port}/api/search`);
|
||||||
|
});
|
||||||
27
docker-compose.yml
Normal file
27
docker-compose.yml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
oramap:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: oramap:latest
|
||||||
|
container_name: oramap-app
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PORT=3000
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
start_period: 5s
|
||||||
|
networks:
|
||||||
|
- oramap-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
oramap-network:
|
||||||
|
driver: bridge
|
||||||
@ -32,7 +32,7 @@ async function searchFamily() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/search?family=${encodeURIComponent(familyName)}`);
|
const response = await fetch(`/api/search?family=${encodeURIComponent(familyName)}`);
|
||||||
const familyResult = await response.json();
|
const familyResult = await response.json();
|
||||||
|
|
||||||
if (!familyResult.length) {
|
if (!familyResult.length) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user