ืคืืืคืืจืื ืงืืืืชืืช ืืฉืืชืืฃ, ืืืคืืฉ ืื ืืืื ืืชืืื ืื ืืืืืื ืืืชืืืคื.
ืืืขืจืืช ื ืื ืชื ืืื ืืฉืืจ ืืืข ืงืืืื ืจื, ืืืคืฉืจ ืืืฉืชืืฉืื ืืืขืืืช ืืชืืื ืื ืขื ืชืืื ืืช, ืืื ืื ืชืืืื ืืืฉืืจ ืืคื ื ืคืจืกืื ืืืชืืื ืื ืืืื ืืืฉืชืืฉืื.
- ืขื ืืคืจืืืงื
- ืชืฆืืื ืืืืคืืืงืฆืื
- ืืืืืืช ืืจืืืืืช
- ืืื ืืืืืืืช
- ืืื ื ืืคืจืืืงื
- ืืชืงื ื ืืืจืฆื ืืงืืืืช
- ืืฉืชื ื ืกืืืื
- API ืืจืืื
- ืืืืงืืช ืืืืืืช
- ืคืจืืกื
- ืฆืืืช ืืคืืชืื
Ethio Food ืืื ืืืฉืื Full Stack ืืืืืกืก ืขื React ืืฆื ืืืงืื ื-Express ืืฆื ืืฉืจืช.
ืืืขืจืืช ืืืคืฉืจืช ืฆืคืืื ืืืชืืื ืื, ืกืื ืื ืืคื ืงืืืืจืืืช, ืืืคืืฉ, ืืจืฉืื ืืืชืืืจืืช, ืืขืืืช ืืชืืื ืื ืืืฉืืื, ืืชืืืช ืชืืืืืช ืื ืืืื ืืชืืื ืื ืขื ืืื ืื ืื.
ืืคืจืืืงื ืฉื ืืืฉ ืขื:
- ืฉืืืืจ ืืชืืื ืื ืืืกืืจืช ืงืืืื ืจืืช ืฉื ืืงืืืื ืืืชืืืคืืช.
- ืืืืืืช ืืฉืชืืฉ ืคืฉืืื ืืขืืจืืช.
- ืืคืจืื ืืื ืืงืื, ืฉืจืช, ืืกืืก ื ืชืื ืื ืืืืืืช ืืฉืชืืฉืื.
- ืืจืฉืืืช ืืกืืกืืืช ืืืฉืชืืฉืื ืจืืืืื ืืืื ืืื ืืขืจืืช.
ืืฃ ืืืืช ืฉื ืืืขืจืืช, ืืืื ืชืฆืืืช ืืืื ืืกืืจืชืืช ืืื ืืกื ืืืืจื ืืงืืืืจืืืช ืืืชืืื ืื.
ืกืื ืื ืืชืืื ืื ืืคื ืงืืืืจืืืช ืืจืืืืืช: ืืฉืจื, ืืืื, ืืืขืื ื ืืฆืืืื ื.
- ืฆืคืืื ืืื ืืืชืืื ืื ืฉืืืฉืจื ืืคืจืกืื.
- ืืืคืืฉ ืืชืืื ืื ืืคื ืฉื, ืืงืืจ, ืืฆืจืืื, ืืืจืืืช ืืืขืจืืช.
- ืกืื ืื ืืชืืื ืื ืืคื ืงืืืืจืืืช: ืืฉืจื, ืืืื, ืืืขืื ื ืืฆืืืื ื.
- ืขืืื ืคืจืืื ืืื ืืื ืืชืืื, ืืืื ืชืืื ื, ืืฆืจืืื, ืืืจืืืช ืืื ื, ืืขืจืืช ืืชืืืืืช.
- ืชืฆืืืช ืชืืืืืช ืืกืื ืื ืฆ'ืื: ืื ืชืืืื ืืืฆืืช ืืืกืืจืช ื ืคืจืืช ืขื ืฉื ืืืืื, ืชืืจืื ืืฉืขืช ืืชืืื.
- ืืจืฉืื ืืืชืืืจืืช ืืืืฆืขืืช Firebase Authentication.
- ืืขืืืช ืืชืืื ืืืฉ ืขื ืชืืื ื, ืงืืืืจืื ืืืื ื ืืืืื ืืืืืฆืื.
- ืืืืจ ืืืฉื ืืืฉืชืืฉืื: ืฆืคืืื, ืขืจืืื ืืืืืงื ืฉื ืืืชืืื ืื ืฉืืื.
- ืืืืจ ื ืืืื ืืื ืืืื: ืฆืคืืื ืืื ืืืชืืื ืื, ืืืฉืืจ ืืชืืื ืื ืฉืืืชืื ืื ืืคืจืกืื ืืืืืงื ืืื ืชืคืจืื.
- ืฉืืืจืช ื ืชืื ืื ื-MongoDB.
- ืืขืืืช ืชืืื ืืช ืืฉืจืช ืขื ืืืืงืืช ืกืื ืงืืืฅ ืืืืื ืงืืืฅ.
- ืขืืื 404 ืืืืืืชื ืืขืืจืืช ืขืืืจ ืืชืืืืช ืืงืื ืฉืื ืงืืืืืช.
- React 17
- Vite
- React Router ืขื HashRouter ืืฉืืืจืช ื ืชืืืื ืืืื ืจืขื ืื
- Axios
- React Icons
- React Spinners
- Node.js
- Express
- MongoDB
- Firebase Identity Toolkit
- Multer
- CORS
- dotenv
ethio-food-main/
โโโ app.js # ืืืืจืช ืฉืจืช Express, CORS ืื ืชืืื API
โโโ auth.js # ืืืืืช Firebase ืืืจืฉืืืช ืืฉืชืืฉืื
โโโ db.js # ืืืืืจ ื-MongoDB
โโโ uploadConfig.js # ืืืืจืช ืชืืงืืืช ืืขืืืืช, ืืืื ืชืืืื ื-UPLOAD_DIR
โโโ utilies.js # ืืืืืงืช ืืชืืื ืื, ืชืืื ืืช, ืชืืืืืช ืืืืฉืืจืื
โโโ render.yaml # Blueprint ืืคืจืืกืช API ื-Static Site ื-Render
โโโ routes/
โ โโโ index.js # ื ืชืืื ืืืชืืื ืื, ืืชืืื ืืช, ืืชืืืืืช ืืื ืืืื
โโโ uploads/ # ืชืืื ืืช ืฉืืืขืื ืืจื ืืืขืจืืช
โโโ client/
โ โโโ src/
โ โ โโโ pages/ # ืขืืืื ืืืคืืืงืฆืื
โ โ โโโ components/ # ืจืืืื ืืืฉืง ืืฉืชืืฉ
โ โ โโโ api.js # ืืืืจืช API ืืืืืืช ืืฆื ืืืงืื
โ โโโ public/
โ โโโ package.json
โโโ package.json # ืชืืืช ืืคืงืืืืช ืฆื ืฉืจืช
- Node.js ืืืจืกื
16.20.0ืืืขืื. - npm.
- MongoDB ืืืื ืืขื ื ืื ืืงืืืืช.
- ืคืจืืืงื Firebase ืคืขืื ืขืืืจ ืืจืฉืื ืืืชืืืจืืช.
npm installืฆืจื ืงืืืฅ .env ืืชืืงืืืช ืืฉืืจืฉ ืืืืืืจื ืืช ืืฉืชื ื ืืกืืืื ืืืจืืฉืื. ืคืืจืื ืืื ืืืคืืข ืืกืขืืฃ ืืฉืชื ื ืกืืืื.
ืืจืฆืช ืืฉืจืช:
npm run devืืจืืจืช ืืืืื ืฉื ืืฉืจืช:
http://localhost:3001
ืืืืงืช ืชืงืื ืืช:
http://localhost:3001/health
ืคืชืื ืืจืืื ื ื ืืกืฃ:
cd client
npm installืฆืจื ืงืืืฅ .env ืืชืื ืชืืงืืืช client ืืืืืืจื ืืช ืืชืืืช ื-API:
VITE_API_URL=http://localhost:3001ืืจืฆืช ืืืงืื:
npm startืืจืืจืช ืืืืื ืฉื Vite:
http://localhost:5173
# Server
npm start
npm run dev
# Client
cd client
npm start
npm run build
npm test
npm run previewPORT=3001
MONGODB_URL=<your-mongodb-connection-string>
MONGODB_DB_NAME=ethyopianfood
CLIENT_ORIGINS=http://localhost:5173
FIREBASE_API_KEY=<your-firebase-api-key>
ADMIN_EMAILS=admin@example.com,another-admin@example.com
UPLOAD_DIR=/opt/render/project/src/uploads| ืืฉืชื ื | ืืืื | ืืกืืจ |
|---|---|---|
PORT |
ืื | ืืคืืจื ืฉืขืืื ืฉืจืช ื-API ืืจืืฅ. ืืจืืจืช ืืืื: 3001. |
MONGODB_URL |
ืื | ืืชืืืช ืืชืืืจืืช ื-MongoDB. |
MONGODB_DB_NAME |
ืื | ืฉื ืืกืืก ืื ืชืื ืื. ืืจืืจืช ืืืื: ethyopianfood. |
CLIENT_ORIGINS |
ืืืืืฅ | ืจืฉืืืช ืืชืืืืช ืืงืื ืฉืืืจืฉืืช ืืคื ืืช ืืฉืจืช, ืืืคืจืืืช ืืคืกืืงืื. |
FIREBASE_API_KEY |
ืื | ืืคืชื Firebase ืืืฉืืฉ ืืืืืืช ืืกืืืื ื ืืฉืชืืฉืื. |
ADMIN_EMAILS |
ืื | ืจืฉืืืช ืืชืืืืช ืืืืืื ืฉื ืื ืืืื, ืืืคืจืืืช ืืคืกืืงืื. |
UPLOAD_DIR |
ืื | ืชืืงืืืช ืฉืืืจืช ืชืืื ืืช ืฉืืืขืื. ืืจืืจืช ืืืื: uploads ืืชืื ืืฉืจืช. ื-Render ืืืืืฅ ืืืืจ ืืชืืงืืื ืื Persistent Disk. |
VITE_API_URL=http://localhost:3001
VITE_FIREBASE_API_KEY=<your-firebase-api-key>ืืคืจืืืงื ืชืืื ืื ืืฉืืืช ืืืฉื ืื REACT_APP_API_URL ื-REACT_APP_FIREBASE_API_KEY, ืื ืืคืจืืืงื Vite ืืืืืฅ ืืืฉืชืืฉ ืืืฉืชื ืื ืฉืืชืืืืื ื-VITE_.
| Method | Endpoint | ืืจืฉืื | ืชืืืืจ |
|---|---|---|---|
GET |
/health |
ืฆืืืืจื | ืืืืงืช ืชืงืื ืืช ืืฉืจืช. |
GET |
/recipes |
ืฆืืืืจื | ืฉืืืคืช ืืชืืื ืื ืฉืืืฉืจื ืืคืจืกืื. |
GET |
/recipes?includePending=true |
ืื ืื | ืฉืืืคืช ืื ืืืชืืื ืื, ืืืื ืืชืืื ืื ืฉืืืชืื ืื ืืืืฉืืจ. |
GET |
/recipe/:id |
ืฆืืืืจื / ืืขืืื / ืื ืื | ืฉืืืคืช ืืชืืื ืืืื. |
GET |
/categories/:category |
ืฆืืืืจื | ืฉืืืคืช ืืชืืื ืื ืืคื ืงืืืืจืื. |
GET |
/image/:newFileName |
ืฆืืืืจื | ืฉืืืคืช ืชืืื ื ืฉืืืขืืชื ืืฉืจืช. |
POST |
/recipe |
ืืฉืชืืฉ ืืืืืจ | ืืฆืืจืช ืืชืืื ืืืฉ ืขื ืชืืื ื. |
PATCH |
/recipe/:id |
ืืฉืชืืฉ ืืืืืจ | ืขืืืื ืืชืืื ืื ืืืกืคืช ืชืืืื. ืชืืืืืช ืืืชืืื ืฉืืืชืื ืืืืฉืืจ ืืืชืจืืช ืจืง ืืืขืืื ืื ืืื ืื. |
DELETE |
/recipe/:id |
ืืขืืื / ืื ืื | ืืืืงืช ืืชืืื. |
GET |
/recipe/user/:localId |
ืืขืืื / ืื ืื | ืฉืืืคืช ืืืชืืื ืื ืฉื ืืฉืชืืฉ ืืกืืื. |
PATCH |
/recipeApprove/:id |
ืื ืื | ืืืฉืืจ ืืชืืื ืืคืจืกืื. |
ืืงืฉืืช ืฉืืฆืจืืืืช ืืฉืชืืฉ ืืืืืจ ืฆืจืืืืช ืืืืื ืืืชืจืช:
Authorization: Bearer <firebase-id-token>ืชืืืืืช ืืืฉืืช ื ืฉืืจืืช ืืืชืืื ืืืขืจื ืฉื ืืืืืืงืืื. ืื ืืคืฉืจ ืืืฆืื ืืื ืชืืืื ืื ืืช ืืชืืื, ืื ืืช ืฉื ืืืืื ืืื ืืช ืืื ืืืชืืื:
comments: [
{
text: "ืชืืืื ืืืืืื",
authorName: "yakov133",
authorId: "firebase-user-id",
createdAt: "2026-06-21T19:59:19.796Z"
}
]ืืฉืจืช ืืืฆืจ ืืช ืืฉืืืช ืืืื ืืืื ืืืกืคืช ืชืืืื:
textืืื ืชืืื ืืชืืืื ืฉืืืฉืชืืฉ ืืชื.authorNameื ืืฆืจ ืืืืืง ืืจืืฉืื ืฉื ืืชืืืช ืืืืื ืืคื ื ืืกืืื@.authorIdื ืฉืืจ ืืคื ืืืื ืืืฉืชืืฉ ืืืืืืช.createdAtื ืืฆืจ ืืฆื ืืฉืจืช ืืื ืฉืืืื ืื ืืืงืืข ืขื ืืื ืืืคืืคื.
ืขืืื ืคืจืื ืืืชืืื ืชืืื ืื ืืชืืืืืช ืืฉื ืืช ืฉื ืฉืืจื ืืขืืจ ืืืงืกื ืคืฉืื, ืืื ืืื ืืข ืฉืืืจื ืื ื ืฉืืจ ืืืืข ืืฉื ืืืกื ืื ืชืื ืื.
ืืืขืจืืช ืชืืืืช ืืืขืืืช ืชืืื ื ืืืช ืืื ืืชืืื:
- ืกืืื ืงืืฆืื ืืืชืจืื:
jpg,png,webp,gif. - ืืืื ืืงืกืืืื:
5MB. - ืฉืืืช ืืงืืฆืื ื ืืฆืจืื ืืฆื ืืฉืจืช ืืื ืืื ืืข ืฉืืืืฉ ืืฉื ืงืืืฅ ืื ืืืื.
- ืื ืืืืืจืื
UPLOAD_DIR, ืืฉืจืช ืืฉืืืจ ืืืงืจื ืชืืื ืืช ืืืืชื ืชืืงืืื ืืืืืจืช, ืืื ืืฉื ืืช ืืช ืืชืืืืช ื-API.
ืืคืจืืืงื ืืืื ืืืืงืืช ืืกืืกืืืช ืืฆื ืืืงืื:
- ืืืืงื ืฉืื ืืืื ืืฆืืืืจื ื ืืขื.
- ืืืืงื ืฉื ืชืื ืืงืื ืื ืงืืื ืืฆืื ืืช ืขืืื
PageNotFound. - ืืืืงื ืฉืืคืชืืจ ืืืืงื ืฉื ืื ืื ืืืกืชืจ ืืืฉืชืืฉ ืจืืื.
- ืืืืงื ืฉืืคืชืืจ ืืืืงื ืฉื ืื ืื ืืืฆื ืืืฉืชืืฉ ืื ืื.
- ืืืืงื ืฉืขืืื ืคืจืื ืืชืืื ืืฆืื ืชืืืื ืขื ืฉื ืืืื, ืชืืจืื ืืฉืขืช ืืชืืื.
ืคืงืืืืช ืืืืงื ืืืืืฆืืช:
# Client tests
cd client
npm test
npm run build
# Server syntax checks
cd ..
node --check app.js
node --check routes/index.js
node --check utilies.js
node --check auth.jsื ืืชื ืืคืจืืก ืืช ืืคืจืืืงื ืืฉื ื ืฉืืจืืชืื ื ืคืจืืื:
ืืืืจื ืืืืืฆืช ืืฉืืจืืช ืขื ื ืืื Render ืื Heroku:
npm install
npm startืืฉ ืืืืืืจ ืืกืืืืช ืืขื ื ืืช ืืฉืชื ื ืืกืืืื ืฉื ืฆื ืืฉืจืช, ืืืืืื:
MONGODB_URLCLIENT_ORIGINSFIREBASE_API_KEYADMIN_EMAILSUPLOAD_DIRืื ืืืืจืื Persistent Disk ืืฉืืืจืช ืชืืื ืืช ืืืืจื ืืื
ืืืืจื ืืืืืฆืช ื-Static Site:
cd client
npm install
npm run buildืชืืงืืืช ืืคืจืกืื:
client/build
ืืืงืื ืืฉืชืืฉ ื-HashRouter, ืืืื ืืชืืืืช ืคื ืืืืืช ื ืฉืืจืืช ืืืจื ืืกืืื #. ืืืืืื:
https://ethio-food.onrender.com/#/Details/<recipe-id>
https://ethio-food.onrender.com/#/Categories/Meat
ืืฆืืจื ืืืืช ืจืขื ืื ืืืคืืคื ืืืงืฉ ืืืฉืจืช ืจืง ืืช /, ื-React Router ืืืฉืื ืืืขืื ืืช ืืขืืื ืื ืืื ืืฆื ืืืงืื.
ืื ืขืืืจืื ืืขืชืื ืืืืจื ื-BrowserRouter, ืฆืจืื ืฉืืชืืืืช ืคื ืืืืืช ืืื /Details/:id, /Categories/:category ืื ืชืืืื ืื ืงืืืืื ืืืืขื ื ืืจื React Router. ืืืงืจื ืืื ืืฉ ืืืืืืจ Rewrite ื-Static Site:
Source: /*
Destination: /index.html
ืื ืืฉืืจืืช ื-Render ืื ื ืืฆืจ ืืชืื render.yaml, ืฆืจืื ืืืืกืืฃ ืืช ืืืชื ืืื ืืื ืืช ืืืฉืืืจื ืฉื Render ืชืืช ืืืืจืืช ื-Static Site. ืืื ืืืื ืืื, BrowserRouter ืขืืื ืืืืืืจ Not Found ืืื ืืกื ืืฉืืจื ืื ืชืื ืืื /fssdasd. ืืฉืืืืฉ ืื ืืืื ื-HashRouter ืืื ืข ืืช ืืืขืื ืืืืช ืืจืขื ืื, ืื ืื ืชืื ื ืฉืืจ ืืฆื ืืืคืืคื ืืืจื #.
ืืคืจืืกื ืืฉ ืืืืืืจ:
VITE_API_URL=<production-api-url>
VITE_FIREBASE_API_KEY=<firebase-api-key>- Yakov Kassa
- Ofek Saadon
ืืคืจืืืงื ื ืื ื ืืืืง ืืชืืืื ืืืืื ืืคืืชืื Full Stack, ืขื ืืืฉ ืขื ืฉืืืืจ ืืฉืืชืืฃ ืืชืืื ืื ืืืืืื ืืืชืืืคื.

