├── src
├── web
│ ├── public
│ │ ├── icons
│ │ │ ├── icon-384x384.png
│ │ │ ├── icon-512x512.png
│ │ │ ├── icon-72x72.png
│ │ │ ├── icon-192x192.png
│ │ │ ├── icon-96x96.png
│ │ │ ├── icon-152x152.png
│ │ │ ├── icon-128x128.png
│ │ │ └── icon-144x144.png
│ │ ├── robots.txt
│ │ ├── favicon.ico
│ │ └── locales
│ │ │ ├── en
│ │ │ └── messages.json
│ │ │ └── ar
│ │ │ ├── payment.json
│ │ │ └── messages.json
│ ├── .prettierrc
│ ├── .env.example
│ ├── .dockerignore
│ ├── next-env.d.ts
│ ├── tsconfig.json
│ ├── src
│ │ ├── types
│ │ │ └── environment.d.ts
│ │ ├── constants
│ │ │ └── categories.ts
│ │ ├── interfaces
│ │ │ └── location.interface.ts
│ │ └── pages
│ │ │ └── categories
│ │ │ └── index.tsx
│ └── .eslintrc.json
└── backend
│ ├── lerna.json
│ ├── nodemon.json
│ ├── messaging-service
│ ├── tsconfig.json
│ ├── Dockerfile
│ ├── src
│ │ └── interfaces
│ │ │ └── message.interface.ts
│ └── package.json
│ ├── .prettierrc
│ ├── payment-service
│ ├── tsconfig.json
│ └── Dockerfile
│ ├── location-service
│ ├── tsconfig.json
│ └── Dockerfile
│ ├── api-gateway
│ ├── package.json
│ ├── tsconfig.json
│ ├── Dockerfile
│ └── src
│ │ └── config
│ │ └── cors.config.ts
│ ├── .eslintrc.json
│ ├── marketplace-service
│ ├── tsconfig.json
│ └── Dockerfile
│ ├── auth-service
│ ├── tsconfig.json
│ └── package.json
│ ├── tsconfig.json
│ ├── shared
│ ├── interfaces
│ │ └── base.interface.ts
│ └── constants
│ │ └── languages.ts
│ ├── .dockerignore
│ ├── Dockerfile
│ └── .env.example
├── frontend
├── .env
├── src
│ ├── App.css
│ ├── App.js
│ ├── features
│ │ ├── MultiLanguage
│ │ │ ├── LanguageSelector.css
│ │ │ ├── LanguageSelector.js
│ │ │ └── i18n.js
│ │ ├── ARShopping
│ │ │ ├── ARService.js
│ │ │ ├── ARShopping.js
│ │ │ ├── ARShopping.css
│ │ │ └── ARViewer.js
│ │ ├── SocialCommerce
│ │ │ ├── SocialService.js
│ │ │ ├── SocialFeed.css
│ │ │ ├── ShareButton.js
│ │ │ └── SocialFeed.js
│ │ ├── Recommendations
│ │ │ ├── RecommendationService.js
│ │ │ ├── RecommendationList.css
│ │ │ └── RecommendationList.js
│ │ ├── Delivery
│ │ │ ├── DeliveryService.js
│ │ │ ├── DeliveryTracker.css
│ │ │ └── DeliveryTracker.js
│ │ ├── Chatbot
│ │ │ ├── ChatbotService.js
│ │ │ ├── Chatbot.css
│ │ │ └── Chatbot.js
│ │ ├── Escrow
│ │ │ ├── EscrowService.js
│ │ │ ├── EscrowPayment.css
│ │ │ └── EscrowPayment.js
│ │ ├── Gamification
│ │ │ ├── GamificationService.js
│ │ │ ├── GamificationDashboard.css
│ │ │ └── GamificationDashboard.js
│ │ ├── EducationalContent
│ │ │ ├── EducationalService.js
│ │ │ ├── EducationalArticle.css
│ │ │ └── EducationalArticle.js
│ │ ├── Sustainability
│ │ │ ├── SustainabilityService.js
│ │ │ ├── SustainabilityList.css
│ │ │ └── SustainabilityList.js
│ │ ├── Subscription
│ │ │ ├── SubscriptionService.js
│ │ │ ├── SubscriptionForm.css
│ │ │ └── SubscriptionForm.js
│ │ ├── LoyaltyProgram
│ │ │ ├── LoyaltyProgram.css
│ │ │ ├── LoyaltyService.js
│ │ │ └── LoyaltyProgram.js
│ │ ├── Events
│ │ │ ├── EventList.css
│ │ │ ├── EventService.js
│ │ │ ├── EventDetail.js
│ │ │ └── EventList.js
│ │ ├── Reviews
│ │ │ ├── ReviewService.js
│ │ │ ├── ReviewList.js
│ │ │ └── ReviewForm.js
│ │ └── UserGeneratedContent
│ │ │ ├── UserContentService.js
│ │ │ ├── UserContentList.css
│ │ │ ├── UserContentForm.js
│ │ │ └── UserContentList.js
│ ├── index.js
│ └── routes.js
└── package.json
├── .github
├── ISSUE_TEMPLATE
│ ├── custom.md
│ └── bug_report.md
├── dependabot.yml
└── CODEOWNERS
├── .whitesource
├── documentation
└── Input Prompt.md
├── LICENSE
└── infrastructure
├── terraform
├── modules
│ ├── cdn
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── s3
│ │ └── outputs.tf
│ └── eks
│ │ └── outputs.tf
├── backend.tf
└── providers.tf
└── kubernetes
├── namespaces.yaml
├── services.yaml
├── autoscaling
├── vpa.yaml
└── hpa.yaml
├── storage
└── persistent-volumes.yaml
├── secrets.yaml
└── configmaps.yaml
/src/web/public/icons/icon-384x384.png:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/.env:
--------------------------------------------------------------------------------
1 | # .env
2 |
3 | REACT_APP_API_BASE_URL=http://localhost:5000/api
4 | REACT_APP_GOOGLE_MAPS_API_KEY=your_google_maps_api_key
5 | REACT_APP_STRIPE_PUBLIC_KEY=your_stripe_public_key
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/frontend/src/App.css:
--------------------------------------------------------------------------------
1 | /* src/App.css */
2 |
3 | .app {
4 | font-family: Arial, sans-serif;
5 | margin: 0;
6 | padding: 0;
7 | background-color: #f0f0f0;
8 | min-height: 100vh;
9 | }
10 |
--------------------------------------------------------------------------------
/.whitesource:
--------------------------------------------------------------------------------
1 | {
2 | "scanSettings": {
3 | "baseBranches": []
4 | },
5 | "checkRunSettings": {
6 | "vulnerableCheckRunConclusionLevel": "failure",
7 | "displayMode": "diff",
8 | "useMendCheckNames": true
9 | },
10 | "issueSettings": {
11 | "minSeverityLevel": "LOW",
12 | "issueType": "DEPENDENCY"
13 | }
14 | }
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | // src/App.js
2 |
3 | import React from 'react';
4 | import { BrowserRouter as Router } from 'react-router-dom';
5 | import routes from './routes';
6 | import './App.css';
7 |
8 | const App = () => {
9 | return (
10 |
11 |
12 | {routes}
13 |
14 |
15 | );
16 | };
17 |
18 | export default App;
19 |
--------------------------------------------------------------------------------
/frontend/src/features/MultiLanguage/LanguageSelector.css:
--------------------------------------------------------------------------------
1 | /* src/features/MultiLanguage/LanguageSelector.css */
2 |
3 | .language-selector {
4 | margin: 20px 0;
5 | }
6 |
7 | .language-selector label {
8 | margin-right: 10px;
9 | font-weight: bold;
10 | }
11 |
12 | .language-selector select {
13 | padding: 5px;
14 | border: 1px solid #ccc;
15 | border-radius: 4px;
16 | font-size: 16px;
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | // src/index.js
2 |
3 | import React from 'react';
4 | import ReactDOM from 'react-dom';
5 | import App from './App';
6 | import './index.css'; // Global styles
7 | import './features/MultiLanguage/i18n'; // Import i18n configuration for multi-language support
8 |
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | );
15 |
--------------------------------------------------------------------------------
/frontend/src/features/ARShopping/ARService.js:
--------------------------------------------------------------------------------
1 | // src/features/ARShopping/ARService.js
2 |
3 | const API_BASE_URL = '/api/ar'; // Adjust this to your actual API base URL
4 |
5 | export const fetchProducts = async () => {
6 | const response = await fetch(`${API_BASE_URL}/products`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch products');
15 | }
16 | const data = await response.json();
17 | return data.products;
18 | };
19 |
--------------------------------------------------------------------------------
/frontend/src/features/SocialCommerce/SocialService.js:
--------------------------------------------------------------------------------
1 | // src/features/SocialCommerce/SocialService.js
2 |
3 | const API_BASE_URL = '/api/social'; // Adjust this to your actual API base URL
4 |
5 | export const fetchSocialPosts = async () => {
6 | const response = await fetch(`${API_BASE_URL}/posts`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch social posts');
15 | }
16 | const data = await response.json();
17 | return data.posts;
18 | };
19 |
--------------------------------------------------------------------------------
/frontend/src/features/Recommendations/RecommendationService.js:
--------------------------------------------------------------------------------
1 | // src/features/Recommendations/RecommendationService.js
2 |
3 | const API_BASE_URL = '/api/recommendations'; // Adjust this to your actual API base URL
4 |
5 | export const fetchRecommendations = async () => {
6 | const response = await fetch(API_BASE_URL, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch recommendations');
15 | }
16 | const data = await response.json();
17 | return data.recommendations;
18 | };
19 |
--------------------------------------------------------------------------------
/frontend/src/features/Delivery/DeliveryService.js:
--------------------------------------------------------------------------------
1 | // src/features/Delivery/DeliveryService.js
2 |
3 | const API_BASE_URL = '/api/delivery'; // Adjust this to your actual API base URL
4 |
5 | export const trackDelivery = async (trackingNumber) => {
6 | const response = await fetch(`${API_BASE_URL}/track`, {
7 | method: 'POST',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | body: JSON.stringify({ trackingNumber }),
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Failed to track delivery');
16 | }
17 |
18 | const data = await response.json();
19 | return data.status; // Assuming the response contains a status field
20 | };
21 |
--------------------------------------------------------------------------------
/frontend/src/features/Chatbot/ChatbotService.js:
--------------------------------------------------------------------------------
1 | // src/features/Chatbot/ChatbotService.js
2 |
3 | const API_BASE_URL = '/api/chatbot'; // Adjust this to your actual API base URL
4 |
5 | export const sendMessage = async (message) => {
6 | const response = await fetch(`${API_BASE_URL}/send`, {
7 | method: 'POST',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | body: JSON.stringify({ message }),
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Failed to send message to the chatbot');
16 | }
17 |
18 | const data = await response.json();
19 | return { text: data.response, sender: 'bot' }; // Assuming the response structure
20 | };
21 |
--------------------------------------------------------------------------------
/frontend/src/features/Escrow/EscrowService.js:
--------------------------------------------------------------------------------
1 | // src/features/Escrow/EscrowService.js
2 |
3 | const API_BASE_URL = '/api/escrow'; // Adjust this to your actual API base URL
4 |
5 | export const createEscrowPayment = async ({ amount, recipient }) => {
6 | const response = await fetch(`${API_BASE_URL}/create`, {
7 | method: 'POST',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | body: JSON.stringify({ amount, recipient }),
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Failed to create escrow payment');
16 | }
17 |
18 | const data = await response.json();
19 | return data; // Assuming the response contains payment details
20 | };
21 |
--------------------------------------------------------------------------------
/frontend/src/features/Gamification/GamificationService.js:
--------------------------------------------------------------------------------
1 | // src/features/Gamification/GamificationService.js
2 |
3 | const API_BASE_URL = '/api/gamification'; // Adjust this to your actual API base URL
4 |
5 | export const fetchUserProgress = async () => {
6 | const response = await fetch(`${API_BASE_URL}/progress`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Failed to fetch user progress');
16 | }
17 |
18 | const data = await response.json();
19 | return data; // Assuming the response contains user progress details
20 | };
21 |
--------------------------------------------------------------------------------
/frontend/src/features/EducationalContent/EducationalService.js:
--------------------------------------------------------------------------------
1 | // src/features/EducationalContent/EducationalService.js
2 |
3 | const API_BASE_URL = '/api/educational'; // Adjust this to your actual API base URL
4 |
5 | export const fetchEducationalArticles = async () => {
6 | const response = await fetch(`${API_BASE_URL}/articles`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch educational articles');
15 | }
16 | const data = await response.json();
17 | return data.articles; // Assuming the response contains an articles array
18 | };
19 |
--------------------------------------------------------------------------------
/frontend/src/features/Sustainability/SustainabilityService.js:
--------------------------------------------------------------------------------
1 | // src/features/Sustainability/SustainabilityService.js
2 |
3 | const API_BASE_URL = '/api/sustainability'; // Adjust this to your actual API base URL
4 |
5 | export const fetchSustainableProducts = async () => {
6 | const response = await fetch(`${API_BASE_URL}/products`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch sustainable products');
15 | }
16 | const data = await response.json();
17 | return data.products; // Assuming the response contains a products array
18 | };
19 |
--------------------------------------------------------------------------------
/src/web/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "singleQuote": true,
4 | "trailingComma": "es5",
5 | "printWidth": 100,
6 | "tabWidth": 2,
7 | "useTabs": false,
8 | "bracketSpacing": true,
9 | "jsxBracketSameLine": false,
10 | "arrowParens": "always",
11 | "endOfLine": "lf",
12 | "jsxSingleQuote": true,
13 | "quoteProps": "as-needed",
14 | "htmlWhitespaceSensitivity": "css",
15 | "embeddedLanguageFormatting": "auto",
16 | "proseWrap": "preserve",
17 | "overrides": [
18 | {
19 | "files": ["*.ts", "*.tsx"],
20 | "options": {
21 | "parser": "typescript"
22 | }
23 | },
24 | {
25 | "files": ["*.json", "*.jsonc"],
26 | "options": {
27 | "parser": "json"
28 | }
29 | }
30 | ]
31 | }
--------------------------------------------------------------------------------
/frontend/src/features/Subscription/SubscriptionService.js:
--------------------------------------------------------------------------------
1 | // src/features/Subscription/SubscriptionService.js
2 |
3 | const API_BASE_URL = '/api/subscription'; // Adjust this to your actual API base URL
4 |
5 | export const createSubscription = async ({ plan, paymentInfo }) => {
6 | const response = await fetch(`${API_BASE_URL}/create`, {
7 | method: 'POST',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | body: JSON.stringify({ plan, paymentInfo }),
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Failed to create subscription');
16 | }
17 |
18 | const data = await response.json();
19 | return data; // Assuming the response contains subscription details
20 | };
21 |
--------------------------------------------------------------------------------
/src/backend/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0",
3 | "npmClient": "npm",
4 | "useWorkspaces": true,
5 | "packages": [
6 | "api-gateway",
7 | "auth-service",
8 | "location-service",
9 | "marketplace-service",
10 | "messaging-service",
11 | "payment-service",
12 | "shared"
13 | ],
14 | "command": {
15 | "bootstrap": {
16 | "hoist": true,
17 | "npmClientArgs": [
18 | "--no-package-lock"
19 | ]
20 | },
21 | "publish": {
22 | "conventionalCommits": true,
23 | "message": "chore(release): publish %s",
24 | "registry": "https://registry.npmjs.org/"
25 | },
26 | "version": {
27 | "conventionalCommits": true,
28 | "message": "chore(release): version %s",
29 | "changelogPreset": "angular"
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/documentation/Input Prompt.md:
--------------------------------------------------------------------------------
1 | EGYPTIAN Map Of Pi is a Pi ecosystem app. USED Pi Browser to access it and more in the Pi ecosystem. WANT DO IT FOR EGYPT PIONEERS LOCAL MARKER SELLERS AND BUYER
2 |
3 | Works:
4 |
5 | Map of Pi is an innovative phone app designed for pioneers within the Pi Network. Here's a brief overview of Map of Pi and how it functions:
6 |
7 | Map of Pi allows pioneers to Search, Buy & Sell goods and services using Pi directly between Pi Wallets.
8 |
9 | It was selected as the winner of the 2024 Commerce Hackathon by the Pi Core Team.
10 |
11 | To access Map of Pi, you can visit mapofpi.pinet.com in the Pi Browser.
12 |
13 | Additional Resource:
14 |
15 | You can learn more about Map of Pi and its features by exploring the app in the Pi Browser. Feel free to ask more specific questions for detailed information!
--------------------------------------------------------------------------------
/src/backend/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch": [
3 | "src/**/*.ts",
4 | "src/**/*.json",
5 | "shared/**/*.ts",
6 | "shared/**/*.json",
7 | "config/**/*.ts",
8 | "config/**/*.json"
9 | ],
10 | "ignore": [
11 | "**/*.test.ts",
12 | "**/*.spec.ts",
13 | "**/__tests__/**",
14 | "**/__mocks__/**",
15 | "node_modules",
16 | "dist",
17 | "coverage",
18 | ".git",
19 | "logs"
20 | ],
21 | "exec": "ts-node --project tsconfig.json",
22 | "ext": ".ts,.js,.json,.mjs",
23 | "delay": 2000,
24 | "verbose": true,
25 | "legacyWatch": false,
26 | "polling": false,
27 | "restartable": "rs",
28 | "colours": true,
29 | "env": {
30 | "NODE_ENV": "development",
31 | "TS_NODE_PROJECT": "tsconfig.json",
32 | "TS_NODE_TRANSPILE_ONLY": "false",
33 | "DEBUG": "egyptian-map-pi:*"
34 | }
35 | }
--------------------------------------------------------------------------------
/frontend/src/features/MultiLanguage/LanguageSelector.js:
--------------------------------------------------------------------------------
1 | // src/features/MultiLanguage/LanguageSelector.js
2 |
3 | import React from 'react';
4 | import { useTranslation } from 'react-i18next';
5 | import './LanguageSelector.css';
6 |
7 | const LanguageSelector = () => {
8 | const { i18n } = useTranslation();
9 |
10 | const handleLanguageChange = (event) => {
11 | i18n.changeLanguage(event.target.value);
12 | };
13 |
14 | return (
15 |
16 |
17 |
23 |
24 | );
25 | };
26 |
27 | export default LanguageSelector;
28 |
--------------------------------------------------------------------------------
/frontend/src/features/SocialCommerce/SocialFeed.css:
--------------------------------------------------------------------------------
1 | /* src/features/SocialCommerce/SocialFeed.css */
2 |
3 | .social-feed {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .social-feed h2 {
11 | color: #333;
12 | }
13 |
14 | .social-post {
15 | background-color: white;
16 | border: 1px solid #ddd;
17 | border-radius: 8px;
18 | padding: 10px;
19 | margin-bottom: 20px;
20 | }
21 |
22 | .social-post img {
23 | max-width: 100%;
24 | border-radius: 4px;
25 | }
26 |
27 | .social-post h3 {
28 | color: #555;
29 | }
30 |
31 | .social-post p {
32 | color: #777;
33 | }
34 |
35 | .share-button {
36 | background-color: #4CAF50;
37 | color: white;
38 | border: none;
39 | border-radius: 4px;
40 | padding: 10px 15px;
41 | cursor: pointer;
42 | }
43 |
44 | .share-button:hover {
45 | background-color: #45a049;
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/src/features/Gamification/GamificationDashboard.css:
--------------------------------------------------------------------------------
1 | /* src/features/Gamification/GamificationDashboard.css */
2 |
3 | .gamification-dashboard {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | max-width: 400px;
9 | margin: auto;
10 | }
11 |
12 | .gamification-dashboard h2 {
13 | color: #333;
14 | }
15 |
16 | .points {
17 | font-size: 24px;
18 | font-weight: bold;
19 | margin-bottom: 20px;
20 | }
21 |
22 | .achievements {
23 | margin-bottom: 20px;
24 | }
25 |
26 | .achievements ul {
27 | list-style-type: none;
28 | padding: 0;
29 | }
30 |
31 | .progress {
32 | margin-top: 20px;
33 | }
34 |
35 | .progress-bar {
36 | width: 100%;
37 | background-color: #ddd;
38 | border-radius: 4px;
39 | overflow: hidden;
40 | }
41 |
42 | .progress-fill {
43 | height: 10px;
44 | background-color: #4CAF50;
45 | transition: width 0.3s ease;
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/src/features/LoyaltyProgram/LoyaltyProgram.css:
--------------------------------------------------------------------------------
1 | /* src/features/LoyaltyProgram/LoyaltyProgram.css */
2 |
3 | .loyalty-program {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .loyalty-program h2 {
11 | color: #333;
12 | }
13 |
14 | .loyalty-program h3 {
15 | margin-top: 20px;
16 | color: #555;
17 | }
18 |
19 | .loyalty-program ul {
20 | list-style-type: none;
21 | padding: 0;
22 | }
23 |
24 | .loyalty-program li {
25 | display: flex;
26 | justify-content: space-between;
27 | align-items: center;
28 | padding: 10px;
29 | border-bottom: 1px solid #ddd;
30 | }
31 |
32 | .loyalty-program button {
33 | background-color: #4CAF50;
34 | color: white;
35 | border: none;
36 | border-radius: 4px;
37 | padding: 5px 10px;
38 | cursor: pointer;
39 | }
40 |
41 | .loyalty-program button:hover {
42 | background-color: #45a049;
43 | }
44 |
--------------------------------------------------------------------------------
/frontend/src/features/Events/EventList.css:
--------------------------------------------------------------------------------
1 | /* src/features/Events/EventList.css */
2 |
3 | .event-list {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .event-list h2 {
11 | color: #333;
12 | margin-bottom: 20px;
13 | }
14 |
15 | .event-list ul {
16 | list-style-type: none;
17 | padding: 0;
18 | }
19 |
20 | .event-list li {
21 | background-color: white;
22 | border: 1px solid #ddd;
23 | border-radius: 8px;
24 | padding: 15px;
25 | margin-bottom: 15px;
26 | transition: box-shadow 0.3s ease;
27 | }
28 |
29 | .event-list li:hover {
30 | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
31 | }
32 |
33 | .event-list h3 {
34 | color: #555;
35 | margin: 0;
36 | }
37 |
38 | .event-list p {
39 | color: #777;
40 | margin: 5px 0 0;
41 | }
42 |
43 | .event-list a {
44 | text-decoration: none;
45 | color: inherit; /* Inherit color from parent */
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/src/features/EducationalContent/EducationalArticle.css:
--------------------------------------------------------------------------------
1 | /* src/features/EducationalContent/EducationalArticle.css */
2 |
3 | .educational-article {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .educational-article h2 {
11 | color: #333;
12 | }
13 |
14 | .educational-article ul {
15 | list-style-type: none;
16 | padding: 0;
17 | }
18 |
19 | .educational-article li {
20 | padding: 10px;
21 | border-bottom: 1px solid #ddd;
22 | }
23 |
24 | .educational-article li h3 {
25 | margin: 0;
26 | color: #007BFF;
27 | }
28 |
29 | .educational-article li p {
30 | color: #777;
31 | margin: 5px 0 0;
32 | }
33 |
34 | .educational-article button {
35 | background-color: #4CAF50;
36 | color: white;
37 | border: none;
38 | border-radius: 4px;
39 | padding: 10px;
40 | cursor: pointer;
41 | }
42 |
43 | .educational-article button:hover {
44 | background-color: #45a049;
45 | }
46 |
--------------------------------------------------------------------------------
/frontend/src/features/Escrow/EscrowPayment.css:
--------------------------------------------------------------------------------
1 | /* src/features/Escrow/EscrowPayment.css */
2 |
3 | .escrow-payment {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | max-width: 400px;
9 | margin: auto;
10 | }
11 |
12 | .escrow-payment h2 {
13 | color: #333;
14 | }
15 |
16 | .escrow-payment label {
17 | display: block;
18 | margin: 10px 0 5px;
19 | }
20 |
21 | .escrow-payment input {
22 | width: 100%;
23 | padding: 10px;
24 | border: 1px solid #ccc;
25 | border-radius: 4px;
26 | margin-bottom: 10px;
27 | }
28 |
29 | .escrow-payment button {
30 | background-color: #4CAF50;
31 | color: white;
32 | border: none;
33 | border-radius: 4px;
34 | padding: 10px;
35 | cursor: pointer;
36 | }
37 |
38 | .escrow-payment button:hover {
39 | background-color: #45a049;
40 | }
41 |
42 | .error {
43 | color: red;
44 | margin-bottom: 10px;
45 | }
46 |
47 | .success {
48 | color: green;
49 | margin-bottom: 10px;
50 | }
51 |
--------------------------------------------------------------------------------
/src/backend/messaging-service/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "./src",
5 | "outDir": "./dist",
6 | "baseUrl": "./src",
7 | "paths": {
8 | "@shared/*": ["../../shared/*"],
9 | "@models/*": ["models/*"],
10 | "@services/*": ["services/*"],
11 | "@controllers/*": ["controllers/*"],
12 | "@interfaces/*": ["interfaces/*"],
13 | "@config/*": ["config/*"],
14 | "@utils/*": ["utils/*"]
15 | },
16 | "typeRoots": [
17 | "./node_modules/@types",
18 | "./src/types"
19 | ],
20 | "types": [
21 | "node",
22 | "jest",
23 | "socket.io"
24 | ]
25 | },
26 | "include": [
27 | "src/**/*.ts",
28 | "src/**/*.json"
29 | ],
30 | "exclude": [
31 | "node_modules",
32 | "dist",
33 | "coverage",
34 | "**/*.test.ts",
35 | "**/*.spec.ts"
36 | ],
37 | "references": [
38 | {
39 | "path": "../shared"
40 | }
41 | ],
42 | "ts-node": {
43 | "transpileOnly": true,
44 | "files": true
45 | }
46 | }
--------------------------------------------------------------------------------
/frontend/src/features/Delivery/DeliveryTracker.css:
--------------------------------------------------------------------------------
1 | /* src/features/Delivery/DeliveryTracker.css */
2 |
3 | .delivery-tracker {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | max-width: 400px;
9 | margin: auto;
10 | }
11 |
12 | .delivery-tracker h2 {
13 | color: #333;
14 | }
15 |
16 | .delivery-tracker input {
17 | width: 100%;
18 | padding: 10px;
19 | border: 1px solid #ccc;
20 | border-radius: 4px;
21 | margin-bottom: 10px;
22 | }
23 |
24 | .delivery-tracker button {
25 | background-color: #4CAF50;
26 | color: white;
27 | border: none;
28 | border-radius: 4px;
29 | padding: 10px;
30 | cursor: pointer;
31 | }
32 |
33 | .delivery-tracker button:hover {
34 | background-color: #45a049;
35 | }
36 |
37 | .error {
38 | color: red;
39 | margin-top: 10px;
40 | }
41 |
42 | .delivery-status {
43 | margin-top: 20px;
44 | padding: 10px;
45 | border: 1px solid #ddd;
46 | border-radius: 4px;
47 | background-color: #e7f3fe;
48 | }
49 |
--------------------------------------------------------------------------------
/src/web/.env.example:
--------------------------------------------------------------------------------
1 | # Core API communication settings for backend services
2 | # Version: v1.0.0
3 | NEXT_PUBLIC_API_BASE_URL=http://localhost:3000/api/v1
4 | NEXT_PUBLIC_API_TIMEOUT=30000
5 |
6 | # Maps Configuration
7 | # Mapbox integration settings for location services and geospatial features
8 | # Version: v2.0.0
9 | NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_access_token_here
10 |
11 | # Pi Network Configuration
12 | # Pi Network integration settings for authentication and transactions
13 | # Version: v1.0.0
14 | NEXT_PUBLIC_PI_API_KEY=your_pi_network_api_key_here
15 | NEXT_PUBLIC_PI_NETWORK_URL=https://api.minepi.com
16 |
17 | # Application Configuration
18 | # General application settings including environment and localization
19 | NEXT_PUBLIC_ENVIRONMENT=development
20 | NEXT_PUBLIC_DEFAULT_LANGUAGE=ar
21 | NEXT_PUBLIC_FALLBACK_LANGUAGE=en
22 | NEXT_PUBLIC_APP_NAME=Egyptian Map of Pi
23 |
24 | # Upload Configuration
25 | # File upload constraints and configurations
26 | NEXT_PUBLIC_MAX_UPLOAD_SIZE=5242880
27 | NEXT_PUBLIC_SUPPORTED_IMAGE_TYPES=image/jpeg,image/png,image/webp
28 | NEXT_PUBLIC_MAX_LISTING_IMAGES=5
--------------------------------------------------------------------------------
/frontend/src/features/Events/EventService.js:
--------------------------------------------------------------------------------
1 | // src/features/Events/EventService.js
2 |
3 | const API_BASE_URL = '/api/events'; // Adjust this to your actual API base URL
4 |
5 | export const fetchEvents = async () => {
6 | const response = await fetch(API_BASE_URL, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch events');
15 | }
16 | const data = await response.json();
17 | return data.events;
18 | };
19 |
20 | export const fetchEventDetails = async (eventId) => {
21 | const response = await fetch(`${API_BASE_URL}/${eventId}`, {
22 | method: 'GET',
23 | headers: {
24 | 'Content-Type': 'application/json',
25 | // Add authorization headers if needed
26 | },
27 | });
28 | if (!response.ok) {
29 | throw new Error('Failed to fetch event details');
30 | }
31 | const data = await response.json();
32 | return data.event;
33 | };
34 |
--------------------------------------------------------------------------------
/frontend/src/features/Subscription/SubscriptionForm.css:
--------------------------------------------------------------------------------
1 | /* src/features/Subscription/SubscriptionForm.css */
2 |
3 | .subscription-form {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | max-width: 400px;
9 | margin: auto;
10 | }
11 |
12 | .subscription-form h2 {
13 | color: #333;
14 | }
15 |
16 | .subscription-form label {
17 | display: block;
18 | margin: 10px 0 5px;
19 | }
20 |
21 | .subscription-form select,
22 | .subscription-form input {
23 | width: 100%;
24 | padding: 10px;
25 | border: 1px solid #ccc;
26 | border-radius: 4px;
27 | margin-bottom: 10px;
28 | }
29 |
30 | .subscription-form button {
31 | background-color: #4CAF50;
32 | color: white;
33 | border: none;
34 | border-radius: 4px;
35 | padding: 10px;
36 | cursor: pointer;
37 | }
38 |
39 | .subscription-form button:hover {
40 | background-color: #45a049;
41 | }
42 |
43 | .error {
44 | color: red;
45 | margin-bottom: 10px;
46 | }
47 |
48 | .success {
49 | color: green;
50 | margin-bottom: 10px;
51 | }
52 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Egyptian Map of Pi Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/frontend/src/features/SocialCommerce/ShareButton.js:
--------------------------------------------------------------------------------
1 | // src/features/SocialCommerce/ShareButton.js
2 |
3 | import React from 'react';
4 |
5 | const ShareButton = ({ post }) => {
6 | const handleShare = () => {
7 | const shareUrl = `https://www.example.com/products/${post.id}`; // Replace with actual product URL
8 | const shareText = `Check out this product: ${post.productName}`;
9 | const shareData = {
10 | title: post.productName,
11 | text: shareText,
12 | url: shareUrl,
13 | };
14 |
15 | if (navigator.share) {
16 | navigator.share(shareData)
17 | .then(() => console.log('Share successful'))
18 | .catch((error) => console.error('Error sharing:', error));
19 | } else {
20 | // Fallback for browsers that do not support the Web Share API
21 | alert(`Share this link: ${shareUrl}`);
22 | }
23 | };
24 |
25 | return (
26 |
29 | );
30 | };
31 |
32 | export default ShareButton;
33 |
--------------------------------------------------------------------------------
/src/backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": true,
7 | "quoteProps": "as-needed",
8 | "trailingComma": "es5",
9 | "bracketSpacing": true,
10 | "bracketSameLine": false,
11 | "arrowParens": "always",
12 | "endOfLine": "lf",
13 | "parser": "typescript",
14 | "proseWrap": "preserve",
15 | "htmlWhitespaceSensitivity": "css",
16 | "embeddedLanguageFormatting": "auto",
17 | "overrides": [
18 | {
19 | "files": "*.{ts,tsx}",
20 | "options": {
21 | "parser": "typescript"
22 | }
23 | },
24 | {
25 | "files": "*.json",
26 | "options": {
27 | "parser": "json"
28 | }
29 | },
30 | {
31 | "files": "*.graphql",
32 | "options": {
33 | "parser": "graphql"
34 | }
35 | }
36 | ],
37 | "ignore": [
38 | "dist",
39 | "node_modules",
40 | "*.generated.ts",
41 | "*.min.js",
42 | "*.d.ts"
43 | ],
44 | "editorconfig": true,
45 | "requireConfig": true,
46 | "vscode": {
47 | "formatOnSave": true,
48 | "packageManager": "npm"
49 | }
50 | }
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "egyptian-map-of-pi--eiweuo",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "react-scripts start",
7 | "build": "react-scripts build",
8 | "test": "react-scripts test",
9 | "eject": "react-scripts eject"
10 | },
11 | "dependencies": {
12 | "react": "^17.0.2",
13 | "react-dom": "^17.0.2",
14 | "react-scripts": "4.0.3",
15 | "react-router-dom": "^5.2.0",
16 | "i18next": "^21.6.3",
17 | "react-i18next": "^11.8.5",
18 | "axios": "^0.21.1",
19 | "redux": "^4.1.0",
20 | "react-redux": "^7.2.4",
21 | "styled-components": "^5.3.0"
22 | },
23 | "devDependencies": {
24 | "eslint": "^7.32.0",
25 | "eslint-plugin-react": "^7.27.1"
26 | },
27 | "eslintConfig": {
28 | "extends": [
29 | "react-app",
30 | "react-app/jest"
31 | ]
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/frontend/src/features/MultiLanguage/i18n.js:
--------------------------------------------------------------------------------
1 | // src/features/MultiLanguage/i18n.js
2 |
3 | import i18n from 'i18next';
4 | import { initReactI18next } from 'react-i18next';
5 |
6 | const resources = {
7 | en: {
8 | translation: {
9 | welcome: "Welcome to the Egyptian Map of Pi",
10 | // Add more English translations here
11 | },
12 | },
13 | ar: {
14 | translation: {
15 | welcome: "مرحبًا بكم في خريطة بي المصرية",
16 | // Add more Arabic translations here
17 | },
18 | },
19 | fr: {
20 | translation: {
21 | welcome: "Bienvenue sur la carte égyptienne de Pi",
22 | // Add more French translations here
23 | },
24 | },
25 | // Add more languages as needed
26 | };
27 |
28 | i18n
29 | .use(initReactI18next) // Passes i18n down to react-i18next
30 | .init({
31 | resources,
32 | lng: "en", // Default language
33 | fallbackLng: "en", // Fallback language
34 | interpolation: {
35 | escapeValue: false, // React already escapes values
36 | },
37 | });
38 |
39 | export default i18n;
40 |
--------------------------------------------------------------------------------
/frontend/src/features/Recommendations/RecommendationList.css:
--------------------------------------------------------------------------------
1 | /* src/features/Recommendations/RecommendationList.css */
2 |
3 | .recommendation-list {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .recommendation-list h2 {
11 | color: #333;
12 | }
13 |
14 | .recommendation-items {
15 | display: flex;
16 | flex-wrap: wrap;
17 | gap: 20px;
18 | }
19 |
20 | .recommendation-item {
21 | background-color: white;
22 | border: 1px solid #ddd;
23 | border-radius: 8px;
24 | padding: 10px;
25 | text-align: center;
26 | width: 200px;
27 | }
28 |
29 | .recommendation-item img {
30 | max-width: 100%;
31 | border-radius: 4px;
32 | }
33 |
34 | .recommendation-item h3 {
35 | color: #555;
36 | }
37 |
38 | .recommendation-item p {
39 | color: #777;
40 | }
41 |
42 | .recommendation-item button {
43 | background-color: #4CAF50;
44 | color: white;
45 | border: none;
46 | border-radius: 4px;
47 | padding: 5px 10px;
48 | cursor: pointer;
49 | }
50 |
51 | .recommendation-item button:hover {
52 | background-color: #45a049;
53 | }
54 |
--------------------------------------------------------------------------------
/frontend/src/features/Reviews/ReviewService.js:
--------------------------------------------------------------------------------
1 | // src/features/Reviews/ReviewService.js
2 |
3 | const API_BASE_URL = '/api/reviews'; // Adjust this to your actual API base URL
4 |
5 | export const fetchReviews = async (productId) => {
6 | const response = await fetch(`${API_BASE_URL}?productId=${productId}`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch reviews');
15 | }
16 | const data = await response.json();
17 | return data.reviews;
18 | };
19 |
20 | export const submitReview = async ({ productId, content, rating }) => {
21 | const response = await fetch(`${API_BASE_URL}`, {
22 | method: 'POST',
23 | headers: {
24 | 'Content-Type': 'application/json',
25 | // Add authorization headers if needed
26 | },
27 | body: JSON.stringify({ productId, content, rating }),
28 | });
29 | if (!response.ok) {
30 | throw new Error('Failed to submit review');
31 | }
32 | const data = await response.json();
33 | return data.review;
34 | };
35 |
--------------------------------------------------------------------------------
/frontend/src/features/Sustainability/SustainabilityList.css:
--------------------------------------------------------------------------------
1 | /* src/features/Sustainability/SustainabilityList.css */
2 |
3 | .sustainability-list {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .sustainability-list h2 {
11 | color: #333;
12 | }
13 |
14 | .sustainability-list ul {
15 | list-style-type: none;
16 | padding: 0;
17 | }
18 |
19 | .sustainability-list li {
20 | background-color: white;
21 | border: 1px solid #ddd;
22 | border-radius: 8px;
23 | padding: 15px;
24 | margin-bottom: 15px;
25 | transition: box-shadow 0.3s ease;
26 | }
27 |
28 | .sustainability-list li:hover {
29 | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
30 | }
31 |
32 | .sustainability-list h3 {
33 | color: #555;
34 | margin: 0;
35 | }
36 |
37 | .sustainability-list p {
38 | color: #777;
39 | margin: 5px 0 0;
40 | }
41 |
42 | .sustainability-list button {
43 | background-color: #4CAF50;
44 | color: white;
45 | border: none;
46 | border-radius: 4px;
47 | padding: 10px;
48 | cursor: pointer;
49 | }
50 |
51 | .sustainability-list button:hover {
52 | background-color: #45a049;
53 | }
54 |
--------------------------------------------------------------------------------
/src/web/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | .gitignore
3 |
4 | # Dependencies
5 | node_modules
6 |
7 | # Build Outputs
8 | .next
9 | out
10 | coverage
11 |
12 | # Environment & Configuration
13 | .env*.local
14 | pi-network*.json
15 |
16 | # Test Files
17 | tests
18 | cypress
19 | *.test.ts
20 | *.test.tsx
21 | *.spec.ts
22 | *.spec.tsx
23 |
24 | # Documentation
25 | README*.md
26 |
27 | # Development Configurations
28 | .eslintrc*
29 | .prettierrc*
30 | tsconfig*.json
31 |
32 | # Logs
33 | *.log
34 |
35 | # IDE and Editor Files
36 | .idea
37 | .vscode
38 | *.swp
39 | *.swo
40 | .DS_Store
41 |
42 | # Cache Directories
43 | .cache
44 | .npm
45 | .yarn
46 |
47 | # Temporary Files
48 | tmp
49 | temp
50 | *.tmp
51 |
52 | # Development Assets
53 | __mocks__
54 | __tests__
55 | .storybook
56 | storybook-static
57 |
58 | # Build Analysis
59 | bundle-analysis
60 | stats.json
61 |
62 | # Development Scripts
63 | scripts
64 | dev-tools
65 |
66 | # Backup Files
67 | *.bak
68 | *.backup
69 |
70 | # Local Development Certificates
71 | *.pem
72 | *.crt
73 | *.key
74 |
75 | # Dependency Lock Files (will be regenerated)
76 | yarn.lock
77 | package-lock.json
78 | pnpm-lock.yaml
79 |
80 | # Miscellaneous
81 | .dockerignore
82 | Dockerfile*
83 | docker-compose*
84 | CHANGELOG.md
85 | CONTRIBUTING.md
86 | LICENSE
--------------------------------------------------------------------------------
/src/web/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 |
5 | // NOTE: This file is auto-generated by Next.js
6 | // Version: next@13.0.0
7 | // Do not modify this file manually
8 |
9 | declare global {
10 | namespace NodeJS {
11 | interface ProcessEnv {
12 | // Environment
13 | NEXT_PUBLIC_APP_ENV: 'development' | 'staging' | 'production'
14 |
15 | // API Configuration
16 | NEXT_PUBLIC_API_URL: string
17 | NEXT_PUBLIC_SOCKET_URL: string
18 | NEXT_PUBLIC_CDN_URL: string
19 |
20 | // Map Configuration
21 | NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN: string
22 | NEXT_PUBLIC_MAP_STYLE_URL: string
23 |
24 | // Pi Network Configuration
25 | NEXT_PUBLIC_PI_API_KEY: string
26 |
27 | // App Configuration
28 | NEXT_PUBLIC_DEFAULT_LANGUAGE: 'ar' | 'en'
29 | NEXT_PUBLIC_DEFAULT_THEME: 'light' | 'dark'
30 | }
31 | }
32 |
33 | // Augment JSX namespace for Next.js specific elements
34 | namespace JSX {
35 | interface IntrinsicElements {
36 | // Allow Next.js specific elements in JSX
37 | }
38 | }
39 | }
40 |
41 | // Ensure this is treated as a module
42 | export {}
--------------------------------------------------------------------------------
/frontend/src/features/Chatbot/Chatbot.css:
--------------------------------------------------------------------------------
1 | /* src/features/Chatbot/Chatbot.css */
2 |
3 | .chatbot {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | max-width: 400px;
9 | margin: auto;
10 | }
11 |
12 | .chat-window {
13 | height: 300px;
14 | overflow-y: auto;
15 | border: 1px solid #ddd;
16 | border-radius: 4px;
17 | padding: 10px;
18 | margin-bottom: 10px;
19 | background-color: white;
20 | }
21 |
22 | .message {
23 | margin: 5px 0;
24 | padding: 8px;
25 | border-radius: 4px;
26 | }
27 |
28 | .message.user {
29 | background-color: #d1e7dd;
30 | text-align: right;
31 | }
32 |
33 | .message.bot {
34 | background-color: #f8d7da;
35 | text-align: left;
36 | }
37 |
38 | .chat-input {
39 | display: flex;
40 | }
41 |
42 | .chat-input input {
43 | flex: 1;
44 | padding: 10px;
45 | border: 1px solid #ccc;
46 | border-radius: 4px;
47 | }
48 |
49 | .chat-input button {
50 | padding: 10px;
51 | border: none;
52 | border-radius: 4px;
53 | background-color: #4CAF50;
54 | color: white;
55 | margin-left: 5px;
56 | cursor: pointer;
57 | }
58 |
59 | .chat-input button:hover {
60 | background-color: #45a049;
61 | }
62 |
--------------------------------------------------------------------------------
/frontend/src/features/UserGeneratedContent/UserContentService.js:
--------------------------------------------------------------------------------
1 | // src/features/UserGeneratedContent/UserContentService.js
2 |
3 | const API_BASE_URL = '/api/user-content'; // Adjust this to your actual API base URL
4 |
5 | export const fetchUser Content = async () => {
6 | const response = await fetch(`${API_BASE_URL}`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch user-generated content');
15 | }
16 | const data = await response.json();
17 | return data.content; // Assuming the response contains a content array
18 | };
19 |
20 | export const submitUser Content = async (content) => {
21 | const response = await fetch(`${API_BASE_URL}/submit`, {
22 | method: 'POST',
23 | headers: {
24 | 'Content-Type': 'application/json',
25 | },
26 | body: JSON.stringify(content),
27 | });
28 |
29 | if (!response.ok) {
30 | throw new Error('Failed to submit user-generated content');
31 | }
32 |
33 | const data = await response.json();
34 | return data; // Assuming the response contains the submitted content details
35 | };
36 |
--------------------------------------------------------------------------------
/frontend/src/features/UserGeneratedContent/UserContentList.css:
--------------------------------------------------------------------------------
1 | /* src/features/UserGeneratedContent/UserContentList.css */
2 |
3 | .user-content-list {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
8 | max-width: 600px;
9 | margin: auto;
10 | }
11 |
12 | .user-content-list h2 {
13 | color: #333;
14 | }
15 |
16 | .user-content-list ul {
17 | list-style-type: none;
18 | padding: 0;
19 | }
20 |
21 | .user-content-list li {
22 | padding: 10px;
23 | border-bottom: 1px solid #ddd;
24 | }
25 |
26 | .user-content-list li h3 {
27 | margin: 0;
28 | color: #007BFF;
29 | }
30 |
31 | .user-content-form {
32 | margin-bottom: 20px;
33 | }
34 |
35 | .user-content-form input,
36 | .user-content-form textarea {
37 | width: 100%;
38 | padding: 10px;
39 | border: 1px solid #ccc;
40 | border-radius: 4px;
41 | margin-bottom: 10px;
42 | }
43 |
44 | .user-content-form button {
45 | background-color: #4CAF50;
46 | color: white;
47 | border: none;
48 | border-radius: 4px;
49 | padding: 10px;
50 | cursor: pointer;
51 | }
52 |
53 | .user-content-form button:hover {
54 | background-color: #45a049;
55 | }
56 |
57 | .error {
58 | color: red;
59 | margin-top: 10px;
60 | }
61 |
62 | .success {
63 | color: green;
64 | margin-top: 10px;
65 | }
66 |
--------------------------------------------------------------------------------
/src/web/public/robots.txt:
--------------------------------------------------------------------------------
1 | # Egyptian Map of Pi - Robots.txt Configuration
2 | # Last Updated: 2023
3 | # Review Frequency: Monthly
4 |
5 | # Default rules for all crawlers
6 | User-agent: *
7 | # Allow public marketplace sections
8 | Allow: /
9 | Allow: /categories
10 | Allow: /listings
11 | Allow: /search
12 |
13 | # Protect sensitive endpoints and private data
14 | Disallow: /api/
15 | Disallow: /messages/
16 | Disallow: /payments/
17 | Disallow: /profile/
18 | Disallow: /*.json$
19 | Disallow: /admin/
20 | Disallow: /auth/
21 |
22 | # Implement rate control for server stability
23 | Crawl-delay: 10
24 |
25 | # Reference to complete sitemap
26 | Sitemap: https://egyptianmapofpi.com/sitemap.xml
27 |
28 | # Block AI training bots
29 | User-agent: GPTBot
30 | Disallow: /
31 |
32 | User-agent: ChatGPT-User
33 | Disallow: /
34 |
35 | User-agent: GoogleBot-Extended
36 | Disallow: /
37 |
38 | User-agent: CCBot
39 | Disallow: /
40 |
41 | # Block potential data harvesting bots
42 | User-agent: PetalBot
43 | Disallow: /
44 |
45 | User-agent: Bytespider
46 | Disallow: /
47 |
48 | # Regional search engine support
49 | User-agent: Arabbot
50 | Allow: /
51 | Allow: /categories
52 | Allow: /listings
53 | Allow: /search
54 | Disallow: /api/
55 | Disallow: /messages/
56 | Disallow: /payments/
57 | Disallow: /profile/
58 | Disallow: /*.json$
59 | Disallow: /admin/
60 | Disallow: /auth/
61 | Crawl-delay: 5
62 |
63 | # Host-specific directive
64 | Host: egyptianmapofpi.com
--------------------------------------------------------------------------------
/frontend/src/features/Events/EventDetail.js:
--------------------------------------------------------------------------------
1 | // src/features/Events/EventDetail.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchEventDetails } from './EventService';
5 | import { useParams } from 'react-router-dom';
6 | import './EventDetail.css';
7 |
8 | const EventDetail = () => {
9 | const { eventId } = useParams();
10 | const [event, setEvent] = useState(null);
11 | const [loading, setLoading] = useState(true);
12 | const [error, setError] = useState(null);
13 |
14 | useEffect(() => {
15 | const loadEventDetails = async () => {
16 | try {
17 | const fetchedEvent = await fetchEventDetails(eventId);
18 | setEvent(fetchedEvent);
19 | } catch (err) {
20 | setError('Failed to fetch event details');
21 | } finally {
22 | setLoading(false);
23 | }
24 | };
25 | loadEventDetails();
26 | }, [eventId]);
27 |
28 | if (loading) return Loading event details...
;
29 | if (error) return {error}
;
30 |
31 | return (
32 |
33 |
{event.title}
34 |
Date: {event.date}
35 |
Location: {event.location}
36 |
Description: {event.description}
37 |
38 |
39 | );
40 | };
41 |
42 | export default EventDetail;
43 |
--------------------------------------------------------------------------------
/frontend/src/routes.js:
--------------------------------------------------------------------------------
1 | // src/routes.js
2 |
3 | import React from 'react';
4 | import { Route, Switch } from 'react-router-dom';
5 | import Home from './features/Home/Home'; // Example home component
6 | import EducationalArticle from './features/EducationalContent/EducationalArticle';
7 | import UserContentList from './features/UserGeneratedContent/UserContentList';
8 | import DeliveryTracker from './features/Delivery/DeliveryTracker';
9 | import SubscriptionForm from './features/Subscription/SubscriptionForm';
10 | import SustainabilityList from './features/Sustainability/SustainabilityList';
11 | import Chatbot from './features/Chatbot/Chatbot';
12 | import ARShopping from './features/ARShopping/ARShopping';
13 | import LoyaltyProgram from './features/LoyaltyProgram/LoyaltyProgram';
14 |
15 | const routes = (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {/* Add more routes as needed */}
27 |
28 | );
29 |
30 | export default routes;
31 |
--------------------------------------------------------------------------------
/src/web/public/icons/icon-512x512.png:
--------------------------------------------------------------------------------
1 | Dimensions: 512x512 pixels
2 | Format: PNG
3 | MIME type: image/png
4 | Color Profile: sRGB
5 | Purpose: any maskable
6 |
7 | Design Elements:
8 | 1. Primary Color: #1B4D89 (Pi Network Blue)
9 | 2. Secondary Color: #D4AF37 (Egyptian Gold)
10 | 3. Background: #F5F5F5 (Light Gray)
11 |
12 | Key Design Components:
13 | 1. Center Safe Area (409.6x409.6px with 51.2px margin)
14 | 2. Material Design Principles
15 | 3. Egyptian Design Motifs
16 | 4. Pi Network Symbol Integration
17 | 5. RTL-Compatible Layout
18 |
19 | Technical Requirements:
20 | - File size target: < 100KB
21 | - Lossless compression
22 | - High DPI support
23 | - Maskable icon support
24 | - Minimum contrast ratio: 4.5:1
25 |
26 | Usage Contexts:
27 | - PWA installation
28 | - App splash screen
29 | - App store listings
30 | - High-resolution displays
31 | - Marketplace listings
32 | - Social media sharing
33 |
34 | Implementation Notes:
35 | 1. The icon should be created from the SVG source file at src/assets/icons/source/icon-512x512.svg
36 | 2. Export with lossless PNG compression
37 | 3. Verify color accuracy in sRGB color space
38 | 4. Test visibility at multiple sizes (16x16 to 512x512)
39 | 5. Validate maskable icon compliance
40 | 6. Ensure cultural sensitivity in design elements
41 |
42 | Legal Requirements:
43 | © 2024 Egyptian Map of Pi
44 | All rights reserved
45 | Trademark verified
46 |
47 | The icon should be implemented by a professional graphic designer following these exact specifications to create the actual PNG file.
--------------------------------------------------------------------------------
/src/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | // ES2022 target as specified in requirements for modern JavaScript features
4 | "target": "es2022",
5 |
6 | // Include necessary lib files for web development
7 | "lib": [
8 | "dom",
9 | "dom.iterable",
10 | "esnext"
11 | ],
12 |
13 | // Module configuration
14 | "module": "esnext",
15 | "moduleResolution": "node",
16 | "resolveJsonModule": true,
17 | "isolatedModules": true,
18 | "esModuleInterop": true,
19 |
20 | // React configuration
21 | "jsx": "preserve",
22 |
23 | // Strict type checking
24 | "strict": true,
25 | "forceConsistentCasingInFileNames": true,
26 | "skipLibCheck": true,
27 |
28 | // Build configuration
29 | "noEmit": true,
30 | "incremental": true,
31 | "allowJs": true,
32 |
33 | // Path aliases for cleaner imports
34 | "baseUrl": ".",
35 | "paths": {
36 | "@/*": ["src/*"]
37 | },
38 |
39 | // Type definitions
40 | "types": [
41 | "node",
42 | "jest",
43 | "react",
44 | "react-dom"
45 | ]
46 | },
47 |
48 | // Files to include in compilation
49 | "include": [
50 | "next-env.d.ts",
51 | "src/types/environment.d.ts",
52 | "src/**/*.ts",
53 | "src/**/*.tsx"
54 | ],
55 |
56 | // Files to exclude from compilation
57 | "exclude": [
58 | "node_modules",
59 | ".next",
60 | "out",
61 | "coverage",
62 | "**/*.test.ts",
63 | "**/*.test.tsx"
64 | ]
65 | }
--------------------------------------------------------------------------------
/frontend/src/features/SocialCommerce/SocialFeed.js:
--------------------------------------------------------------------------------
1 | // src/features/SocialCommerce/SocialFeed.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchSocialPosts } from './SocialService';
5 | import ShareButton from './ShareButton';
6 | import './SocialFeed.css';
7 |
8 | const SocialFeed = () => {
9 | const [posts, setPosts] = useState([]);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 |
13 | useEffect(() => {
14 | const loadPosts = async () => {
15 | try {
16 | const fetchedPosts = await fetchSocialPosts();
17 | setPosts(fetchedPosts);
18 | } catch (err) {
19 | setError('Failed to fetch social posts');
20 | } finally {
21 | setLoading(false);
22 | }
23 | };
24 | loadPosts();
25 | }, []);
26 |
27 | if (loading) return Loading...
;
28 | if (error) return {error}
;
29 |
30 | return (
31 |
32 |
Social Commerce Feed
33 | {posts.map((post) => (
34 |
35 |

36 |
{post.productName}
37 |
{post.description}
38 |
39 |
40 | ))}
41 |
42 | );
43 | };
44 |
45 | export default SocialFeed;
46 |
--------------------------------------------------------------------------------
/src/web/public/icons/icon-72x72.png:
--------------------------------------------------------------------------------
1 | Image Specifications:
2 | - Dimensions: 72x72 pixels
3 | - Format: PNG with transparency
4 | - Color Depth: 32-bit
5 | - Max File Size: 5KB
6 | - Purpose: any maskable
7 |
8 | Design Elements:
9 | 1. Base Shape:
10 | - Material Design square with 12px rounded corners
11 | - Primary color: #1B4D89 (Egyptian Map of Pi brand blue)
12 | - Background: #F5F5F5 with transparency support
13 |
14 | 2. Icon Design:
15 | - Centered "π" symbol in modern geometric style
16 | - Egyptian cultural elements:
17 | - Subtle pyramid silhouette overlay
18 | - Hieroglyphic-inspired decorative border
19 | - 8px minimum padding from edges
20 | - High contrast for visibility
21 | - Optimized for small size display
22 |
23 | 3. Technical Optimizations:
24 | - Lossless PNG compression
25 | - Web-safe color palette
26 | - Essential PWA metadata preserved
27 | - Maskable icon support
28 | - Dark mode compatible
29 |
30 | 4. Accessibility Features:
31 | - High contrast ratio > 4.5:1
32 | - Color-blind friendly design
33 | - Recognizable at 72px size
34 | - Clear silhouette for adaptive icons
35 |
36 | Browser Support:
37 | - Pi Browser (latest): Maskable support
38 | - Chrome Mobile 80+: Adaptive icon
39 | - Safari iOS 12+: Retina optimized
40 | - Firefox Mobile 95+: Standard support
41 | - Opera Mobile 60+: Standard support
42 |
43 | Performance:
44 | - Load time < 100ms
45 | - Cache-first strategy
46 | - 30-day cache duration
47 | - Compressed size < 5KB
48 |
49 | [Note: The actual binary image file would be created according to these specifications using appropriate image creation tools]
--------------------------------------------------------------------------------
/frontend/src/features/LoyaltyProgram/LoyaltyService.js:
--------------------------------------------------------------------------------
1 | // src/features/LoyaltyProgram/LoyaltyService.js
2 |
3 | const API_BASE_URL = '/api/loyalty'; // Adjust this to your actual API base URL
4 |
5 | export const getLoyaltyPoints = async () => {
6 | const response = await fetch(`${API_BASE_URL}/points`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | // Add authorization headers if needed
11 | },
12 | });
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch loyalty points');
15 | }
16 | const data = await response.json();
17 | return data.points;
18 | };
19 |
20 | export const getRewards = async () => {
21 | const response = await fetch(`${API_BASE_URL}/rewards`, {
22 | method: 'GET',
23 | headers: {
24 | 'Content-Type': 'application/json',
25 | // Add authorization headers if needed
26 | },
27 | });
28 | if (!response.ok) {
29 | throw new Error('Failed to fetch rewards');
30 | }
31 | const data = await response.json();
32 | return data.rewards;
33 | };
34 |
35 | export const redeemReward = async (rewardId) => {
36 | const response = await fetch(`${API_BASE_URL}/redeem`, {
37 | method: 'POST',
38 | headers: {
39 | 'Content-Type': 'application/json',
40 | // Add authorization headers if needed
41 | },
42 | body: JSON.stringify({ rewardId }),
43 | });
44 | if (!response.ok) {
45 | throw new Error('Failed to redeem reward');
46 | }
47 | return await response.json();
48 | };
49 |
--------------------------------------------------------------------------------
/src/backend/payment-service/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | // Root directories and output configuration
5 | "rootDir": "./src",
6 | "outDir": "./dist",
7 | "baseUrl": "./src",
8 |
9 | // Strict type checking for payment processing security
10 | "strict": true,
11 | "noImplicitAny": true,
12 | "strictNullChecks": true,
13 | "strictFunctionTypes": true,
14 | "strictBindCallApply": true,
15 | "strictPropertyInitialization": true,
16 | "noImplicitThis": true,
17 | "alwaysStrict": true,
18 |
19 | // Path aliases for payment service modules
20 | "paths": {
21 | "@interfaces/*": ["interfaces/*"],
22 | "@config/*": ["config/*"],
23 | "@models/*": ["models/*"],
24 | "@services/*": ["services/*"],
25 | "@controllers/*": ["controllers/*"],
26 | "@utils/*": ["utils/*"],
27 | "@shared/*": ["../../shared/*"]
28 | },
29 |
30 | // Types and module resolution
31 | "types": ["node", "jest"],
32 | "moduleResolution": "node",
33 | "esModuleInterop": true,
34 | "resolveJsonModule": true,
35 | "sourceMap": true,
36 | "declaration": true
37 | },
38 |
39 | // Project references
40 | "references": [
41 | {
42 | "path": "../shared"
43 | }
44 | ],
45 |
46 | // Source files
47 | "include": [
48 | "src/**/*.ts",
49 | "src/**/*.json"
50 | ],
51 | "exclude": [
52 | "node_modules",
53 | "dist",
54 | "coverage",
55 | "**/*.test.ts",
56 | "**/*.spec.ts"
57 | ],
58 |
59 | // ts-node configuration for development
60 | "ts-node": {
61 | "transpileOnly": true,
62 | "files": true
63 | }
64 | }
--------------------------------------------------------------------------------
/src/web/public/favicon.ico:
--------------------------------------------------------------------------------
1 | Multi-resolution ICO file containing 3 sizes:
2 | - 16x16 pixels
3 | - 32x32 pixels
4 | - 48x48 pixels
5 |
6 | Design Elements:
7 | 1. Base Icon:
8 | - Pi Network symbol (π) as the central element
9 | - Primary color: #1B4D89 (Pi Network blue)
10 | - Background color: #F5F5F5 (Light gray)
11 |
12 | 2. Cultural Elements:
13 | - Egyptian hieroglyphic-inspired decorative border
14 | - Subtle integration that maintains clarity at small sizes
15 | - Border elements simplified at 16x16 size
16 |
17 | 3. Material Design Features:
18 | - Subtle shadow depth for elevation effect
19 | - Crisp, defined boundaries
20 | - Flat design principles with minimal gradients
21 | - High contrast for visibility
22 |
23 | Technical Requirements:
24 | - Format: 32-bit RGBA ICO
25 | - Optimization: Size-specific detail levels
26 | - High-DPI support for modern displays
27 | - Clear rendering at all specified sizes
28 | - Cache-Control header: public, max-age=604800
29 |
30 | Size-Specific Optimizations:
31 | 16x16:
32 | - Simplified design
33 | - Enhanced edges
34 | - Basic Pi symbol only
35 | - Minimal cultural elements
36 |
37 | 32x32:
38 | - Balanced detail
39 | - Clear border elements
40 | - Full Pi symbol
41 | - Basic cultural accents
42 |
43 | 48x48:
44 | - Full detail
45 | - Complete cultural elements
46 | - Rich shadow depth
47 | - Maximum clarity
48 |
49 | The favicon should be created using professional image editing software that supports ICO format with multiple resolutions. The file should be optimized for web use while maintaining visual quality.
50 |
51 | Note: This is a binary file format and the actual implementation requires image creation in graphics software rather than code generation.
--------------------------------------------------------------------------------
/frontend/src/features/ARShopping/ARShopping.js:
--------------------------------------------------------------------------------
1 | // src/features/ARShopping/ARShopping.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchProducts } from './ARService';
5 | import ARViewer from './ARViewer';
6 | import './ARShopping.css';
7 |
8 | const ARShopping = () => {
9 | const [products, setProducts] = useState([]);
10 | const [selectedProduct, setSelectedProduct] = useState(null);
11 | const [showAR, setShowAR] = useState(false);
12 |
13 | useEffect(() => {
14 | const loadProducts = async () => {
15 | const productList = await fetchProducts();
16 | setProducts(productList);
17 | };
18 | loadProducts();
19 | }, []);
20 |
21 | const handleARLaunch = (product) => {
22 | setSelectedProduct(product);
23 | setShowAR(true);
24 | };
25 |
26 | const handleCloseAR = () => {
27 | setShowAR(false);
28 | setSelectedProduct(null);
29 | };
30 |
31 | return (
32 |
33 |
Augmented Reality Shopping
34 |
35 | {products.map((product) => (
36 |
37 |

38 |
{product.name}
39 |
40 |
41 | ))}
42 |
43 | {showAR &&
}
44 |
45 | );
46 | };
47 |
48 | export default ARShopping;
49 |
--------------------------------------------------------------------------------
/src/backend/location-service/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "./src",
5 | "outDir": "./dist",
6 | "composite": true,
7 | "declaration": true,
8 | "sourceMap": true,
9 | "strict": true,
10 | "esModuleInterop": true,
11 | "skipLibCheck": true,
12 | "forceConsistentCasingInFileNames": true,
13 | "moduleResolution": "node",
14 | "target": "es2022",
15 | "module": "commonjs",
16 | "lib": [
17 | "es2022",
18 | "dom"
19 | ],
20 | "baseUrl": ".",
21 | "paths": {
22 | "@shared/*": ["../shared/*"],
23 | "@models/*": ["src/models/*"],
24 | "@config/*": ["src/config/*"],
25 | "@controllers/*": ["src/controllers/*"],
26 | "@services/*": ["src/services/*"],
27 | "@utils/*": ["src/utils/*"],
28 | "@interfaces/*": ["src/interfaces/*"],
29 | "@geospatial/*": ["src/geospatial/*"]
30 | }
31 | },
32 | "include": [
33 | "src/**/*.ts",
34 | "src/**/*.json"
35 | ],
36 | "exclude": [
37 | "node_modules",
38 | "dist",
39 | "coverage",
40 | "**/*.test.ts",
41 | "**/*.spec.ts"
42 | ],
43 | "references": [
44 | {
45 | "path": "../shared"
46 | }
47 | ],
48 | "ts-node": {
49 | "transpileOnly": true,
50 | "files": true,
51 | "compilerOptions": {
52 | "module": "commonjs"
53 | }
54 | },
55 | "watchOptions": {
56 | "watchFile": "useFsEvents",
57 | "watchDirectory": "useFsEvents",
58 | "fallbackPolling": "dynamicPriority",
59 | "synchronousWatchDirectory": true,
60 | "excludeDirectories": [
61 | "**/node_modules",
62 | "**/dist",
63 | "**/coverage"
64 | ]
65 | }
66 | }
--------------------------------------------------------------------------------
/frontend/src/features/Events/EventList.js:
--------------------------------------------------------------------------------
1 | // src/features/Events/EventList.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchEvents } from './EventService';
5 | import { Link } from 'react-router-dom';
6 | import './EventList.css';
7 |
8 | const EventList = () => {
9 | const [events, setEvents] = useState([]);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 |
13 | useEffect(() => {
14 | const loadEvents = async () => {
15 | try {
16 | const fetchedEvents = await fetchEvents();
17 | setEvents(fetchedEvents);
18 | } catch (err) {
19 | setError('Failed to fetch events');
20 | } finally {
21 | setLoading(false);
22 | }
23 | };
24 | loadEvents();
25 | }, []);
26 |
27 | if (loading) return Loading events...
;
28 | if (error) return {error}
;
29 |
30 | return (
31 |
32 |
Upcoming Events
33 | {events.length === 0 ? (
34 |
No upcoming events.
35 | ) : (
36 |
37 | {events.map((event) => (
38 | -
39 |
40 |
{event.title}
41 | {event.date}
42 |
43 |
44 | ))}
45 |
46 | )}
47 |
48 | );
49 | };
50 |
51 | export default EventList;
52 |
--------------------------------------------------------------------------------
/frontend/src/features/ARShopping/ARShopping.css:
--------------------------------------------------------------------------------
1 | /* src/features/ARShopping/ARShopping.css */
2 |
3 | .ar-shopping {
4 | padding: 20px;
5 | background-color: #f ```css
6 | /* src/features/ARShopping/ARShopping.css */
7 |
8 | .ar-shopping {
9 | padding: 20px;
10 | background-color: #f9f9f9;
11 | border-radius: 8px;
12 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
13 | }
14 |
15 | .ar-shopping h2 {
16 | color: #333;
17 | }
18 |
19 | .product-list {
20 | display: flex;
21 | flex-wrap: wrap;
22 | gap: 20px;
23 | }
24 |
25 | .product-item {
26 | background-color: white;
27 | border: 1px solid #ddd;
28 | border-radius: 8px;
29 | padding: 10px;
30 | text-align: center;
31 | width: 200px;
32 | }
33 |
34 | .product-item img {
35 | max-width: 100%;
36 | border-radius: 4px;
37 | }
38 |
39 | .product-item button {
40 | background-color: #4CAF50;
41 | color: white;
42 | border: none;
43 | border-radius: 4px;
44 | padding: 5px 10px;
45 | cursor: pointer;
46 | }
47 |
48 | .product-item button:hover {
49 | background-color: #45a049;
50 | }
51 |
52 | .ar-viewer {
53 | position: fixed;
54 | top: 0;
55 | left: 0;
56 | width: 100%;
57 | height: 100%;
58 | background-color: rgba(0, 0, 0, 0.8);
59 | display: flex;
60 | justify-content: center;
61 | align-items: center;
62 | z-index: 1000;
63 | }
64 |
65 | .close-button {
66 | position: absolute;
67 | top: 20px;
68 | right: 20px;
69 | background-color: #ff4d4d;
70 | color: white;
71 | border: none;
72 | border-radius: 4px;
73 | padding: 10px;
74 | cursor: pointer;
75 | }
76 |
77 | .close-button:hover {
78 | background-color: #ff1a1a;
79 | }
80 |
--------------------------------------------------------------------------------
/src/web/public/icons/icon-192x192.png:
--------------------------------------------------------------------------------
1 | Format: PNG (image/png)
2 | Dimensions: 192x192 pixels
3 | Color Profile: sRGB
4 | Bit Depth: 32-bit (with alpha channel)
5 | Maximum File Size: 32KB
6 |
7 | Design Specifications:
8 | 1. Layout:
9 | - Safe Zone: 77px centered square (40% of total dimensions)
10 | - Internal Padding: 16px on all sides
11 | - Background: #F5F5F5 (light gray)
12 | - Primary Color: #1B4D89 (deep blue)
13 |
14 | 2. Design Elements:
15 | - Primary Icon: Stylized map marker incorporating Pi symbol
16 | - Egyptian Elements: Subtle hieroglyphic-inspired decorative elements
17 | - Material Design: Flat design with subtle elevation shadows
18 | - Maskable Support: All critical elements within safe zone
19 |
20 | 3. Technical Requirements:
21 | - Transparent background for flexible platform display
22 | - Anti-aliased edges for crisp rendering
23 | - Optimized paths for pixel-perfect display
24 | - High-DPI support for retina displays
25 |
26 | 4. Platform-Specific Considerations:
27 | - Android: Maskable icon format support
28 | - Chrome Web Store: Optimized for store listing
29 | - Pi Browser: Enhanced visibility in platform context
30 | - PWA: Standard compliant for home screen display
31 |
32 | 5. Optimization Guidelines:
33 | - PNG compression: Optimized for size/quality balance
34 | - Path optimization: Simplified vectors for clean scaling
35 | - Color optimization: Limited palette for file size reduction
36 | - Edge preservation: Maintain crispness after compression
37 |
38 | Implementation Notes:
39 | - Export with PNG-8 format where possible for size optimization
40 | - Use indexed color palette to reduce file size
41 | - Implement proper gamma correction for cross-platform display
42 | - Include metadata for PWA manifest compatibility
--------------------------------------------------------------------------------
/src/backend/api-gateway/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@egyptian-map-pi/api-gateway",
3 | "version": "1.0.0",
4 | "private": true,
5 | "engines": {
6 | "node": ">=18.0.0",
7 | "npm": "9.8.0"
8 | },
9 | "scripts": {
10 | "build": "tsc",
11 | "start": "node dist/app.js",
12 | "dev": "nodemon src/app.ts",
13 | "test": "jest",
14 | "test:coverage": "jest --coverage",
15 | "lint": "eslint . --ext .ts",
16 | "lint:fix": "eslint . --ext .ts --fix",
17 | "clean": "rimraf dist coverage"
18 | },
19 | "dependencies": {
20 | "@egyptian-map-pi/shared": "^1.0.0",
21 | "@pinetwork-js/sdk": "^2.0.0",
22 | "axios": "^1.5.0",
23 | "compression": "^1.7.4",
24 | "cors": "^2.8.5",
25 | "dotenv": "^16.3.1",
26 | "express": "4.18.2",
27 | "express-rate-limit": "^6.9.0",
28 | "express-validator": "^7.0.1",
29 | "helmet": "^7.0.0",
30 | "http-proxy-middleware": "2.0.6",
31 | "jsonwebtoken": "^9.0.1",
32 | "morgan": "^1.10.0",
33 | "winston": "^3.10.0",
34 | "winston-daily-rotate-file": "4.7.1"
35 | },
36 | "devDependencies": {
37 | "@types/express": "^4.17.17",
38 | "@types/jest": "29.5.3",
39 | "@types/node": "^18.0.0",
40 | "@typescript-eslint/eslint-plugin": "6.2.1",
41 | "@typescript-eslint/parser": "6.2.1",
42 | "eslint": "8.46.0",
43 | "eslint-config-prettier": "8.10.0",
44 | "eslint-plugin-import": "2.28.1",
45 | "eslint-plugin-jest": "27.2.3",
46 | "jest": "^29.0.0",
47 | "nodemon": "3.0.1",
48 | "prettier": "^3.0.0",
49 | "rimraf": "5.0.1",
50 | "ts-jest": "29.1.1",
51 | "ts-node": "10.9.1",
52 | "typescript": "5.1.6"
53 | },
54 | "author": "Egyptian Map of Pi Team",
55 | "license": "MIT"
56 | }
--------------------------------------------------------------------------------
/src/web/public/icons/icon-96x96.png:
--------------------------------------------------------------------------------
1 | Image Specifications:
2 | - Dimensions: 96x96 pixels
3 | - Format: PNG with transparency (32-bit with alpha channel)
4 | - File size: Optimized to <5KB
5 | - Color scheme:
6 | - Background: #F5F5F5
7 | - Theme color: #1B4D89
8 | - Color space: sRGB
9 | - Minimum contrast ratio: 4.5:1
10 |
11 | Design Elements:
12 | 1. Core Shape:
13 | - Circular base shape (80% of total width/height)
14 | - Material Design 3.0 elevation and shadow guidelines
15 | - 40% padding for maskable icon safe zone
16 |
17 | 2. Icon Elements:
18 | - Stylized "π" symbol in theme color #1B4D89
19 | - Egyptian pyramid silhouette overlay
20 | - Location marker integration
21 | - Material Design icon grid alignment
22 |
23 | 3. Safe Zone Implementation:
24 | - Primary content within 57.6x57.6 pixel central area
25 | - Edge padding following maskable icon guidelines
26 | - Pixel-perfect alignment at target resolution
27 |
28 | 4. Cultural Elements:
29 | - Egyptian architectural motifs
30 | - Modern minimalist interpretation
31 | - Balanced visual hierarchy
32 |
33 | Technical Implementation:
34 | 1. Image Optimization:
35 | - PNG compression with alpha channel
36 | - Optimized for <5KB file size
37 | - Pixel-perfect rendering at 96x96
38 |
39 | 2. Metadata:
40 | - Proper PNG chunks for web delivery
41 | - Color profile: sRGB
42 | - Transparency: Enabled
43 |
44 | 3. Cache Headers:
45 | Cache-Control: public, max-age=31536000, immutable
46 | Content-Type: image/png
47 | ETag: [Generated hash]
48 |
49 | Browser Support:
50 | - Pi Browser (latest): Full support
51 | - Chrome Mobile (80+): Maskable icon support
52 | - Safari iOS (12+): Standard icon support
53 | - Firefox Mobile (95+): Full maskable support
54 | - Opera Mobile (60+): Standard support
--------------------------------------------------------------------------------
/frontend/src/features/Reviews/ReviewList.js:
--------------------------------------------------------------------------------
1 | // src/features/Reviews/ReviewList.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchReviews } from './ReviewService';
5 | import ReviewForm from './ReviewForm';
6 | import './ReviewList.css';
7 |
8 | const ReviewList = ({ productId }) => {
9 | const [reviews, setReviews] = useState([]);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 |
13 | useEffect(() => {
14 | const loadReviews = async () => {
15 | try {
16 | const fetchedReviews = await fetchReviews(productId);
17 | setReviews(fetchedReviews);
18 | } catch (err) {
19 | setError('Failed to fetch reviews');
20 | } finally {
21 | setLoading(false);
22 | }
23 | };
24 | loadReviews();
25 | }, [productId]);
26 |
27 | if (loading) return Loading reviews...
;
28 | if (error) return {error}
;
29 |
30 | return (
31 |
32 |
Reviews
33 |
34 | {reviews.length === 0 ? (
35 |
No reviews yet.
36 | ) : (
37 | reviews.map((review) => (
38 |
39 |
{review.author}
40 |
{review.content}
41 |
Rating: {review.rating} ⭐
42 |
43 | ))
44 | )}
45 |
46 | );
47 | };
48 |
49 | export default ReviewList;
50 |
--------------------------------------------------------------------------------
/infrastructure/terraform/modules/cdn/outputs.tf:
--------------------------------------------------------------------------------
1 | # Output definitions for CloudFront CDN module
2 | # Version: 1.0
3 | # Provider compatibility: hashicorp/terraform ~> 1.5
4 |
5 | # CloudFront distribution ID output
6 | output "distribution_id" {
7 | description = "The ID of the CloudFront distribution for the Egyptian Map of Pi CDN"
8 | value = aws_cloudfront_distribution.main.id
9 | }
10 |
11 | # CloudFront distribution domain name output
12 | output "distribution_domain_name" {
13 | description = "The domain name of the CloudFront distribution for content delivery in Egypt"
14 | value = aws_cloudfront_distribution.main.domain_name
15 | }
16 |
17 | # CloudFront distribution hosted zone ID output
18 | output "distribution_hosted_zone_id" {
19 | description = "The Route 53 hosted zone ID for the CloudFront distribution enabling geolocation routing"
20 | value = aws_cloudfront_distribution.main.hosted_zone_id
21 | }
22 |
23 | # CloudFront Origin Access Identity path output
24 | output "origin_access_identity_path" {
25 | description = "The path for the CloudFront Origin Access Identity used in S3 bucket policies"
26 | value = aws_cloudfront_origin_access_identity.main.cloudfront_access_identity_path
27 | }
28 |
29 | # CloudFront distribution deployment status output
30 | output "distribution_status" {
31 | description = "The current status of the CloudFront distribution deployment"
32 | value = aws_cloudfront_distribution.main.status
33 | }
34 |
35 | # CloudFront Origin Access Identity IAM ARN output
36 | output "origin_access_identity_iam_arn" {
37 | description = "The IAM ARN of the Origin Access Identity for S3 bucket policy configuration"
38 | value = aws_cloudfront_origin_access_identity.main.iam_arn
39 | }
--------------------------------------------------------------------------------
/frontend/src/features/ARShopping/ARViewer.js:
--------------------------------------------------------------------------------
1 | // src/features/ARShopping/ARViewer.js
2 |
3 | import React, { useEffect } from 'react';
4 | import * as THREE from 'three';
5 | import { ARButton } from 'three/examples/jsm/webxr/ARButton';
6 | import './ARViewer.css';
7 |
8 | const ARViewer = ({ product, onClose }) => {
9 | useEffect(() => {
10 | const scene = new THREE.Scene();
11 | const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
12 | const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
13 | renderer.setSize(window.innerWidth, window.innerHeight);
14 | document.body.appendChild(renderer.domElement);
15 | document.body.appendChild(ARButton.createButton(renderer));
16 |
17 | const geometry = new THREE.BoxGeometry(1, 1, 1); // Placeholder for product model
18 | const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
19 | const cube = new THREE.Mesh(geometry, material);
20 | scene.add(cube);
21 |
22 | camera.position.z = 5;
23 |
24 | const animate = function () {
25 | requestAnimationFrame(animate);
26 | cube.rotation.x += 0.01;
27 | cube.rotation.y += 0.01;
28 | renderer.render(scene, camera);
29 | };
30 |
31 | animate();
32 |
33 | return () => {
34 | document.body.removeChild(renderer.domElement);
35 | };
36 | }, [product]);
37 |
38 | return (
39 |
40 |
41 | {/* AR content will be rendered here */}
42 |
43 | );
44 | };
45 |
46 | export default ARViewer;
47 |
--------------------------------------------------------------------------------
/frontend/src/features/Reviews/ReviewForm.js:
--------------------------------------------------------------------------------
1 | // src/features/Reviews/ReviewForm.js
2 |
3 | import React, { useState } from 'react';
4 | import { submitReview } from './ReviewService';
5 | import './ReviewForm.css';
6 |
7 | const ReviewForm = ({ productId, onReviewAdded }) => {
8 | const [content, setContent] = useState('');
9 | const [rating, setRating] = useState(5);
10 | const [error, setError] = useState(null);
11 |
12 | const handleSubmit = async (e) => {
13 | e.preventDefault();
14 | try {
15 | const newReview = await submitReview({ productId, content, rating });
16 | onReviewAdded((prevReviews) => [...prevReviews, newReview]);
17 | setContent('');
18 | setRating(5);
19 | } catch (err) {
20 | setError('Failed to submit review');
21 | }
22 | };
23 |
24 | return (
25 |
44 | );
45 | };
46 |
47 | export default ReviewForm;
48 |
--------------------------------------------------------------------------------
/src/web/public/icons/icon-152x152.png:
--------------------------------------------------------------------------------
1 | Technical Specifications for Icon Creation:
2 |
3 | 1. Dimensions:
4 | - Exact size: 152x152 pixels
5 | - Safe zone: 132x132 pixels (centered)
6 | - No scaling or padding allowed
7 |
8 | 2. Format:
9 | - File format: PNG
10 | - Color space: sRGB
11 | - Bit depth: 32-bit (24-bit color + 8-bit alpha)
12 | - Compression: Optimized lossless
13 | - Maximum file size: 32KB
14 |
15 | 3. Colors:
16 | - Background: #F5F5F5 (Light gray)
17 | - Primary theme color: #1B4D89 (Deep blue)
18 | - Ensure minimum contrast ratio of 4.5:1
19 | - Color-blind friendly palette
20 |
21 | 4. Design Elements:
22 | - Centered Pi symbol (π)
23 | - Egyptian visual motifs:
24 | * Simplified pyramid silhouette
25 | * Traditional geometric patterns
26 | * Cultural symbols integrated subtly
27 | - Material Design principles:
28 | * Clear hierarchy
29 | * Bold geometric shapes
30 | * Subtle shadows (if used)
31 |
32 | 5. Technical Requirements:
33 | - Full bleed design for iOS home screen
34 | - Implements maskable icon specification
35 | - No transparency for apple-touch-icon
36 | - Optimized for high-resolution displays
37 | - Sharp edges and clear details at 152px
38 |
39 | 6. Accessibility:
40 | - High contrast elements
41 | - Distinguishable without color
42 | - Clear silhouette
43 | - Recognizable at smaller sizes
44 |
45 | 7. Cultural Considerations:
46 | - Respectful use of Egyptian symbols
47 | - Appropriate cultural motifs
48 | - Modern interpretation of traditional elements
49 | - Balanced fusion of Pi Network and Egyptian identity
50 |
51 | 8. Export Settings:
52 | - PNG format
53 | - sRGB color profile
54 | - Optimized compression
55 | - No metadata
56 | - Clean pixel grid alignment
57 |
58 | This icon should be created by a professional designer using vector graphics software and exported according to these specifications.
--------------------------------------------------------------------------------
/frontend/src/features/EducationalContent/EducationalArticle.js:
--------------------------------------------------------------------------------
1 | // src/features/EducationalContent/EducationalArticle.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchEducationalArticles } from './EducationalService';
5 | import './EducationalArticle.css';
6 |
7 | const EducationalArticle = () => {
8 | const [articles, setArticles] = useState([]);
9 | const [loading, setLoading] = useState(true);
10 | const [error, setError] = useState(null);
11 |
12 | useEffect(() => {
13 | const loadArticles = async () => {
14 | try {
15 | const fetchedArticles = await fetchEducationalArticles();
16 | setArticles(fetchedArticles);
17 | } catch (err) {
18 | setError('Failed to fetch educational articles');
19 | } finally {
20 | setLoading(false);
21 | }
22 | };
23 | loadArticles();
24 | }, []);
25 |
26 | if (loading) return Loading educational articles...
;
27 | if (error) return {error}
;
28 |
29 | return (
30 |
31 |
Educational Articles
32 | {articles.length === 0 ? (
33 |
No educational articles available.
34 | ) : (
35 |
36 | {articles.map((article) => (
37 | -
38 |
{article.title}
39 | {article.summary}
40 |
41 |
42 | ))}
43 |
44 | )}
45 |
46 | );
47 | };
48 |
49 | export default EducationalArticle;
50 |
--------------------------------------------------------------------------------
/frontend/src/features/Sustainability/SustainabilityList.js:
--------------------------------------------------------------------------------
1 | // src/features/Sustainability/SustainabilityList.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchSustainableProducts } from './SustainabilityService';
5 | import './SustainabilityList.css';
6 |
7 | const SustainabilityList = () => {
8 | const [products, setProducts] = useState([]);
9 | const [loading, setLoading] = useState(true);
10 | const [error, setError] = useState(null);
11 |
12 | useEffect(() => {
13 | const loadProducts = async () => {
14 | try {
15 | const fetchedProducts = await fetchSustainableProducts();
16 | setProducts(fetchedProducts);
17 | } catch (err) {
18 | setError('Failed to fetch sustainable products');
19 | } finally {
20 | setLoading(false);
21 | }
22 | };
23 | loadProducts();
24 | }, []);
25 |
26 | if (loading) return Loading sustainable products...
;
27 | if (error) return {error}
;
28 |
29 | return (
30 |
31 |
Sustainable Products
32 | {products.length === 0 ? (
33 |
No sustainable products available.
34 | ) : (
35 |
36 | {products.map((product) => (
37 | -
38 |
{product.name}
39 | {product.description}
40 | Price: ${product.price}
41 |
42 |
43 | ))}
44 |
45 | )}
46 |
47 | );
48 | };
49 |
50 | export default SustainabilityList;
51 |
--------------------------------------------------------------------------------
/frontend/src/features/Delivery/DeliveryTracker.js:
--------------------------------------------------------------------------------
1 | // src/features/Delivery/DeliveryTracker.js
2 |
3 | import React, { useState } from 'react';
4 | import { trackDelivery } from './DeliveryService';
5 | import './DeliveryTracker.css';
6 |
7 | const DeliveryTracker = () => {
8 | const [trackingNumber, setTrackingNumber] = useState('');
9 | const [deliveryStatus, setDeliveryStatus] = useState(null);
10 | const [error, setError] = useState(null);
11 | const [loading, setLoading] = useState(false);
12 |
13 | const handleTrack = async (e) => {
14 | e.preventDefault();
15 | setError(null);
16 | setLoading(true);
17 |
18 | try {
19 | const status = await trackDelivery(trackingNumber);
20 | setDeliveryStatus(status);
21 | } catch (err) {
22 | setError('Failed to track delivery. Please check your tracking number.');
23 | } finally {
24 | setLoading(false);
25 | }
26 | };
27 |
28 | return (
29 |
30 |
Track Your Delivery
31 |
41 | {loading &&
Loading...
}
42 | {error &&
{error}
}
43 | {deliveryStatus && (
44 |
45 |
Delivery Status:
46 |
{deliveryStatus}
47 |
48 | )}
49 |
50 | );
51 | };
52 |
53 | export default DeliveryTracker;
54 |
--------------------------------------------------------------------------------
/frontend/src/features/UserGeneratedContent/UserContentForm.js:
--------------------------------------------------------------------------------
1 | // src/features/UserGeneratedContent/UserContentForm.js
2 |
3 | import React, { useState } from 'react';
4 | import { submitUser Content } from './User ContentService';
5 | import './User ContentForm.css';
6 |
7 | const UserContentForm = ({ onContentAdded }) => {
8 | const [title, setTitle] = useState('');
9 | const [description, setDescription] = useState('');
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 |
13 | const handleSubmit = async (e) => {
14 | e.preventDefault();
15 | setError(null);
16 | setSuccess(false);
17 |
18 | try {
19 | const newContent = await submitUser Content({ title, description });
20 | onContentAdded(newContent);
21 | setSuccess(true);
22 | setTitle('');
23 | setDescription('');
24 | } catch (err) {
25 | setError('Failed to submit content. Please try again.');
26 | }
27 | };
28 |
29 | return (
30 |
49 | );
50 | };
51 |
52 | export default UserContentForm;
53 |
--------------------------------------------------------------------------------
/src/web/public/icons/icon-128x128.png:
--------------------------------------------------------------------------------
1 | Dimensions: 128 x 128 pixels
2 | Format: PNG
3 | Color Space: sRGB
4 | Transparency: Enabled
5 | Purpose: any maskable
6 |
7 | Design Elements:
8 | 1. Primary Shape:
9 | - Circular base shape with 40% safe zone
10 | - Material Design elevation with subtle shadow
11 | - Adaptive icon support with maskable area
12 |
13 | 2. Colors:
14 | - Primary: #1B4D89 (Egyptian Map of Pi brand blue)
15 | - Background: #F5F5F5 (Light neutral)
16 | - Accent elements using brand color derivatives
17 | - Dark mode compatible with sufficient contrast
18 |
19 | 3. Icon Elements:
20 | - Stylized "Pi" symbol incorporating Arabic calligraphy
21 | - Egyptian map outline as a subtle background element
22 | - Material Design principles for depth and elevation
23 | - Minimum 1px stroke width at 128x128
24 |
25 | 4. Cultural Integration:
26 | - Arabic calligraphic influence in the Pi symbol
27 | - Traditional Egyptian patterns in background
28 | - Cultural color symbolism maintained
29 | - Balanced modern and traditional elements
30 |
31 | Technical Requirements:
32 | 1. File Optimization:
33 | - PNG format with 32-bit color depth
34 | - Compression level: 8 (optimized)
35 | - Target file size: < 10KB
36 | - No dithering or interlacing
37 | - Optimized for web delivery
38 |
39 | 2. Platform Support:
40 | - Maskable icon support for Android
41 | - Retina-ready for iOS
42 | - High contrast ratio (4.5:1 minimum)
43 | - Clear visibility at 128x128 size
44 | - Cross-browser compatible
45 |
46 | 3. Accessibility:
47 | - Color blind friendly design
48 | - High contrast elements
49 | - Recognizable at target size
50 | - Dark mode compatible
51 |
52 | 4. Quality Assurance:
53 | - Pixel-perfect alignment
54 | - Sharp edges at 1x and 2x
55 | - No artifacts from compression
56 | - Consistent appearance across platforms
57 |
58 | Asset Management:
59 | Source File: src/design/icons/source/icon-128x128.psd
60 | Version: 1.0.0
61 | Last Modified: [Current ISO Date]
62 | Modified By: [Designer ID]
--------------------------------------------------------------------------------
/infrastructure/terraform/backend.tf:
--------------------------------------------------------------------------------
1 | # Backend configuration for Egyptian Map of Pi Terraform state management
2 | # Version: 1.0.0
3 | # This configuration establishes a secure, encrypted, and regionally compliant
4 | # state storage solution with proper locking mechanisms for concurrent access
5 |
6 | terraform {
7 | backend "s3" {
8 | # Primary state bucket in AWS Bahrain region (me-south-1) for regional compliance
9 | bucket = "egyptian-map-of-pi-terraform-state"
10 |
11 | # Dynamic state file path based on environment workspace
12 | key = "environments/${terraform.workspace}/terraform.tfstate"
13 |
14 | # Middle East (Bahrain) region for primary deployment
15 | region = "me-south-1"
16 |
17 | # DynamoDB table for state locking and consistency
18 | dynamodb_table = "egyptian-map-of-pi-terraform-locks"
19 |
20 | # Security configurations
21 | encrypt = true
22 | acl = "private"
23 |
24 | # KMS encryption key for additional security
25 | kms_key_id = "arn:aws:kms:me-south-1:ACCOUNT_ID:key/KEY_ID"
26 |
27 | # Workspace configuration for environment separation
28 | workspace_key_prefix = "environments"
29 |
30 | # Additional S3 backend configurations
31 | force_path_style = false
32 |
33 | # Version 4 signature for improved security
34 | use_path_style = false
35 |
36 | # Enable versioning for state history
37 | versioning = true
38 |
39 | # Error handling and retry configuration
40 | skip_credentials_validation = false
41 | skip_region_validation = false
42 | skip_metadata_api_check = false
43 |
44 | # Lifecycle configurations
45 | lifecycle {
46 | prevent_destroy = true
47 | }
48 | }
49 | }
50 |
51 | # Backend configuration validation
52 | terraform {
53 | required_version = ">= 1.0.0"
54 |
55 | required_providers {
56 | aws = {
57 | source = "hashicorp/aws"
58 | version = "~> 4.0"
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/backend/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "parserOptions": {
5 | "ecmaVersion": 2022,
6 | "sourceType": "module",
7 | "project": "./tsconfig.json"
8 | },
9 | "extends": [
10 | "eslint:recommended",
11 | "plugin:@typescript-eslint/recommended",
12 | "plugin:@typescript-eslint/recommended-requiring-type-checking",
13 | "plugin:jest/recommended",
14 | "prettier"
15 | ],
16 | "plugins": [
17 | "@typescript-eslint",
18 | "jest",
19 | "import"
20 | ],
21 | "env": {
22 | "node": true,
23 | "es2022": true,
24 | "jest": true
25 | },
26 | "rules": {
27 | "@typescript-eslint/explicit-function-return-type": "error",
28 | "@typescript-eslint/no-explicit-any": "error",
29 | "@typescript-eslint/no-unused-vars": [
30 | "error",
31 | {
32 | "argsIgnorePattern": "^_"
33 | }
34 | ],
35 | "@typescript-eslint/strict-boolean-expressions": "error",
36 | "@typescript-eslint/no-floating-promises": "error",
37 | "@typescript-eslint/await-thenable": "error",
38 | "@typescript-eslint/no-misused-promises": "error",
39 | "import/order": [
40 | "error",
41 | {
42 | "groups": [
43 | "builtin",
44 | "external",
45 | "internal",
46 | "parent",
47 | "sibling",
48 | "index"
49 | ],
50 | "newlines-between": "always",
51 | "alphabetize": {
52 | "order": "asc"
53 | }
54 | }
55 | ],
56 | "no-console": [
57 | "warn",
58 | {
59 | "allow": [
60 | "warn",
61 | "error"
62 | ]
63 | }
64 | ],
65 | "prefer-const": "error",
66 | "no-var": "error",
67 | "eqeqeq": [
68 | "error",
69 | "always"
70 | ],
71 | "jest/no-disabled-tests": "warn",
72 | "jest/no-focused-tests": "error",
73 | "jest/prefer-to-have-length": "warn",
74 | "jest/valid-expect": "error"
75 | }
76 | }
--------------------------------------------------------------------------------
/frontend/src/features/UserGeneratedContent/UserContentList.js:
--------------------------------------------------------------------------------
1 | // src/features/UserGeneratedContent/UserContentList.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchUser Content } from './User ContentService';
5 | import UserContentForm from './User ContentForm';
6 | import './User ContentList.css';
7 |
8 | const UserContentList = () => {
9 | const [userContent, setUser Content] = useState([]);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 |
13 | useEffect(() => {
14 | const loadUser Content = async () => {
15 | try {
16 | const fetchedContent = await fetchUser Content();
17 | setUser Content(fetchedContent);
18 | } catch (err) {
19 | setError('Failed to fetch user-generated content');
20 | } finally {
21 | setLoading(false);
22 | }
23 | };
24 | loadUser Content();
25 | }, []);
26 |
27 | const handleContentAdded = (newContent) => {
28 | setUser Content((prevContent) => [...prevContent, newContent]);
29 | };
30 |
31 | if (loading) return Loading user-generated content...
;
32 | if (error) return {error}
;
33 |
34 | return (
35 |
36 |
User Generated Content
37 |
38 | {userContent.length === 0 ? (
39 |
No user-generated content available.
40 | ) : (
41 |
42 | {userContent.map((content) => (
43 | -
44 |
{content.title}
45 | {content.description}
46 |
47 | ))}
48 |
49 | )}
50 |
51 | );
52 | };
53 |
54 | export default UserContentList;
55 |
--------------------------------------------------------------------------------
/src/web/public/icons/icon-144x144.png:
--------------------------------------------------------------------------------
1 | Image Specifications:
2 | - Dimensions: 144x144 pixels
3 | - Format: PNG with transparency (alpha channel)
4 | - Color Space: sRGB
5 | - Purpose: any maskable
6 | - Maximum File Size: 10KB
7 |
8 | Design Elements:
9 | 1. Core Shape:
10 | - Circular base with 144px diameter
11 | - 14.4px (10%) padding safe zone for maskable support
12 | - Material Design icon grid alignment
13 |
14 | 2. Primary Elements:
15 | - Stylized "π" (Pi) symbol in the center
16 | - Egyptian pyramid silhouette integrated with Pi symbol
17 | - Traditional Egyptian patterns as background texture
18 |
19 | 3. Color Palette:
20 | - Primary: #1976D2 (Pi Network blue)
21 | - Secondary: #FFC107 (Egyptian gold)
22 | - Accent: #E91E63 (Marketplace accent)
23 | - Background gradient from #FFFFFF to #F5F5F5
24 | - Transparency for outer edges
25 |
26 | 4. Cultural Elements:
27 | - Hieroglyphic-inspired decorative elements
28 | - Arabesque patterns in border design
29 | - RTL-friendly composition
30 | - Traditional Egyptian color motifs
31 |
32 | 5. Technical Optimizations:
33 | - 1px stroke alignment to pixel grid
34 | - Sharp corner rendering at target size
35 | - Optimized PNG compression
36 | - Proper alpha channel implementation
37 | - Removed metadata for size optimization
38 |
39 | 6. Accessibility Features:
40 | - 4.5:1 minimum contrast ratio
41 | - Distinct silhouette recognition
42 | - Clear visibility on varied backgrounds
43 | - Consistent branding with other sizes
44 |
45 | Quality Assurance Checklist:
46 | ✓ Pixel-perfect rendering at 144x144
47 | ✓ Maskable icon safe zone compliance
48 | ✓ Material Design guidelines adherence
49 | ✓ Cultural sensitivity verification
50 | ✓ File size optimization (<10KB)
51 | ✓ Cross-device rendering testing
52 | ✓ PWA manifest compatibility
53 | ✓ Installation banner preview validation
54 |
55 | Note: This icon should be generated by a professional designer
56 | following these specifications using appropriate design tools
57 | like Adobe Illustrator or Figma, then exported with proper
58 | PNG optimization settings.
--------------------------------------------------------------------------------
/frontend/src/features/Recommendations/RecommendationList.js:
--------------------------------------------------------------------------------
1 | // src/features/Recommendations/RecommendationList.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchRecommendations } from './RecommendationService';
5 | import './RecommendationList.css';
6 |
7 | const RecommendationList = () => {
8 | const [recommendations, setRecommendations] = useState([]);
9 | const [loading, setLoading] = useState(true);
10 | const [error, setError] = useState(null);
11 |
12 | useEffect(() => {
13 | const loadRecommendations = async () => {
14 | try {
15 | const fetchedRecommendations = await fetchRecommendations();
16 | setRecommendations(fetchedRecommendations);
17 | } catch (err) {
18 | setError('Failed to fetch recommendations');
19 | } finally {
20 | setLoading(false);
21 | }
22 | };
23 | loadRecommendations();
24 | }, []);
25 |
26 | if (loading) return Loading recommendations...
;
27 | if (error) return {error}
;
28 |
29 | return (
30 |
31 |
Recommended for You
32 | {recommendations.length === 0 ? (
33 |
No recommendations available.
34 | ) : (
35 |
36 | {recommendations.map((product) => (
37 |
38 |

39 |
{product.name}
40 |
{product.description}
41 |
Price: ${product.price}
42 |
43 |
44 | ))}
45 |
46 | )}
47 |
48 | );
49 | };
50 |
51 | export default RecommendationList;
52 |
--------------------------------------------------------------------------------
/infrastructure/kubernetes/namespaces.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | # Application Namespace for core microservices
5 | - apiVersion: v1
6 | kind: Namespace
7 | metadata:
8 | name: app
9 | labels:
10 | name: app
11 | part-of: egyptian-map-pi
12 | environment: production
13 | region: me-south-1
14 | security-tier: restricted
15 | monitoring: enabled
16 | annotations:
17 | # Enable strict network policies for this namespace
18 | network-policy: strict
19 | # AWS IAM role binding for pod service accounts
20 | iam.amazonaws.com/permitted-roles: app-role
21 | # Enable Prometheus metrics scraping
22 | prometheus.io/scrape: "true"
23 |
24 | # Monitoring Namespace for observability stack
25 | - apiVersion: v1
26 | kind: Namespace
27 | metadata:
28 | name: monitoring
29 | labels:
30 | name: monitoring
31 | part-of: egyptian-map-pi
32 | environment: production
33 | region: me-south-1
34 | security-tier: restricted
35 | monitoring: enabled
36 | annotations:
37 | # Specific network policies for monitoring tools
38 | network-policy: monitoring
39 | # AWS IAM role for monitoring components
40 | iam.amazonaws.com/permitted-roles: monitoring-role
41 | # Enable self-monitoring
42 | prometheus.io/scrape: "true"
43 |
44 | # Storage Namespace for databases and persistent volumes
45 | - apiVersion: v1
46 | kind: Namespace
47 | metadata:
48 | name: storage
49 | labels:
50 | name: storage
51 | part-of: egyptian-map-pi
52 | environment: production
53 | region: me-south-1
54 | security-tier: critical
55 | monitoring: enabled
56 | annotations:
57 | # Storage-specific network policies
58 | network-policy: storage
59 | # AWS IAM role for storage operations
60 | iam.amazonaws.com/permitted-roles: storage-role
61 | # Enable metrics collection
62 | prometheus.io/scrape: "true"
63 | # Enable volume backups with Velero
64 | backup.velero.io/backup-volumes: "true"
--------------------------------------------------------------------------------
/infrastructure/terraform/modules/s3/outputs.tf:
--------------------------------------------------------------------------------
1 | # S3 bucket identifier output
2 | output "bucket_id" {
3 | description = "The name of the S3 bucket created for Egyptian Map of Pi media storage"
4 | value = aws_s3_bucket.main.id
5 | }
6 |
7 | # S3 bucket ARN output for IAM policies and access control
8 | output "bucket_arn" {
9 | description = "The ARN of the S3 bucket for IAM policy configuration and CloudFront OAI access"
10 | value = aws_s3_bucket.main.arn
11 | sensitive = true # ARN contains account ID, marking as sensitive
12 | }
13 |
14 | # S3 bucket domain name for CloudFront origin configuration
15 | output "bucket_domain_name" {
16 | description = "The domain name of the S3 bucket for CloudFront CDN origin configuration"
17 | value = aws_s3_bucket.main.bucket_domain_name
18 | }
19 |
20 | # S3 bucket regional domain name for optimized Middle East region access
21 | output "bucket_regional_domain_name" {
22 | description = "The regional domain name of the S3 bucket for optimized CloudFront access in the Middle East region"
23 | value = aws_s3_bucket.main.bucket_regional_domain_name
24 | }
25 |
26 | # Replica bucket outputs (if replication is enabled)
27 | output "replica_bucket_id" {
28 | description = "The name of the replica S3 bucket (if replication is enabled)"
29 | value = var.replication_enabled ? aws_s3_bucket.replica[0].id : null
30 | }
31 |
32 | output "replica_bucket_arn" {
33 | description = "The ARN of the replica S3 bucket for disaster recovery (if replication is enabled)"
34 | value = var.replication_enabled ? aws_s3_bucket.replica[0].arn : null
35 | sensitive = true
36 | }
37 |
38 | # Bucket website endpoint (if website hosting is enabled)
39 | output "bucket_website_endpoint" {
40 | description = "The website endpoint URL of the S3 bucket (if website hosting is enabled)"
41 | value = try(aws_s3_bucket.main.website_endpoint, null)
42 | }
43 |
44 | # Bucket region for reference
45 | output "bucket_region" {
46 | description = "The AWS region where the S3 bucket is created"
47 | value = aws_s3_bucket.main.region
48 | }
--------------------------------------------------------------------------------
/frontend/src/features/Chatbot/Chatbot.js:
--------------------------------------------------------------------------------
1 | // src/features/Chatbot/Chatbot.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { sendMessage } from './ChatbotService';
5 | import './Chatbot.css';
6 |
7 | const Chatbot = () => {
8 | const [messages, setMessages] = useState([]);
9 | const [input, setInput] = useState('');
10 | const [loading, setLoading] = useState(false);
11 |
12 | const handleSend = async (e) => {
13 | e.preventDefault();
14 | if (!input.trim()) return;
15 |
16 | const userMessage = { text: input, sender: 'user' };
17 | setMessages((prevMessages) => [...prevMessages, userMessage]);
18 | setInput('');
19 | setLoading(true);
20 |
21 | try {
22 | const botResponse = await sendMessage(input);
23 | setMessages((prevMessages) => [...prevMessages, botResponse]);
24 | } catch (error) {
25 | setMessages((prevMessages) => [
26 | ...prevMessages,
27 | { text: 'Error: Unable to get response from the chatbot.', sender: 'bot' },
28 | ]);
29 | } finally {
30 | setLoading(false);
31 | }
32 | };
33 |
34 | return (
35 |
36 |
Chatbot
37 |
38 | {messages.map((msg, index) => (
39 |
40 | {msg.text}
41 |
42 | ))}
43 | {loading &&
Typing...
}
44 |
45 |
54 |
55 | );
56 | };
57 |
58 | export default Chatbot;
59 |
--------------------------------------------------------------------------------
/src/backend/marketplace-service/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "composite": true,
5 | "incremental": true,
6 | "tsBuildInfoFile": "./dist/.tsbuildinfo",
7 | "rootDir": "src",
8 | "outDir": "dist",
9 | "baseUrl": ".",
10 | "target": "es2022",
11 | "module": "commonjs",
12 | "moduleResolution": "node",
13 | "esModuleInterop": true,
14 |
15 | // Strict Type Checking
16 | "strict": true,
17 | "strictNullChecks": true,
18 | "strictFunctionTypes": true,
19 | "strictBindCallApply": true,
20 | "strictPropertyInitialization": true,
21 | "noImplicitAny": true,
22 | "noImplicitThis": true,
23 | "alwaysStrict": true,
24 |
25 | // Additional Checks
26 | "noUnusedLocals": true,
27 | "noUnusedParameters": true,
28 | "noImplicitReturns": true,
29 | "noFallthroughCasesInSwitch": true,
30 |
31 | // Module Resolution
32 | "skipLibCheck": true,
33 | "resolveJsonModule": true,
34 |
35 | // Source Maps
36 | "sourceMap": true,
37 | "declaration": true,
38 | "declarationMap": true,
39 |
40 | // Path Aliases
41 | "paths": {
42 | "@shared/*": ["../shared/*"],
43 | "@models/*": ["src/models/*"],
44 | "@services/*": ["src/services/*"],
45 | "@controllers/*": ["src/controllers/*"],
46 | "@interfaces/*": ["src/interfaces/*"],
47 | "@config/*": ["src/config/*"],
48 | "@utils/*": ["src/utils/*"],
49 | "@middlewares/*": ["src/middlewares/*"],
50 | "@validators/*": ["src/validators/*"],
51 | "@types/*": ["src/types/*"]
52 | }
53 | },
54 | "include": [
55 | "src/**/*.ts",
56 | "src/**/*.json"
57 | ],
58 | "exclude": [
59 | "node_modules",
60 | "dist",
61 | "coverage",
62 | "**/*.test.ts",
63 | "**/*.spec.ts",
64 | "**/__tests__/**",
65 | "**/__mocks__/**"
66 | ],
67 | "references": [
68 | {
69 | "path": "../shared/tsconfig.json"
70 | }
71 | ],
72 | "ts-node": {
73 | "transpileOnly": true,
74 | "files": true,
75 | "compilerOptions": {
76 | "module": "commonjs"
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/frontend/src/features/Gamification/GamificationDashboard.js:
--------------------------------------------------------------------------------
1 | // src/features/Gamification/GamificationDashboard.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchUserProgress } from './GamificationService';
5 | import './GamificationDashboard.css';
6 |
7 | const GamificationDashboard = () => {
8 | const [progress, setProgress] = useState(null);
9 | const [loading, setLoading] = useState(true);
10 | const [error, setError] = useState(null);
11 |
12 | useEffect(() => {
13 | const loadProgress = async () => {
14 | try {
15 | const userProgress = await fetchUserProgress();
16 | setProgress(userProgress);
17 | } catch (err) {
18 | setError('Failed to fetch user progress');
19 | } finally {
20 | setLoading(false);
21 | }
22 | };
23 | loadProgress();
24 | }, []);
25 |
26 | if (loading) return Loading your progress...
;
27 | if (error) return {error}
;
28 |
29 | return (
30 |
31 |
Your Gamification Dashboard
32 |
33 |
Points: {progress.points}
34 |
35 |
36 |
Achievements
37 |
38 | {progress.achievements.map((achievement) => (
39 | -
40 | {achievement.name} - {achievement.completed ? '✅' : '❌'}
41 |
42 | ))}
43 |
44 |
45 |
46 |
Progress
47 |
{progress.progressPercentage}% completed
48 |
54 |
55 |
56 | );
57 | };
58 |
59 | export default GamificationDashboard;
60 |
--------------------------------------------------------------------------------
/infrastructure/kubernetes/services.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | # API Gateway Service
5 | - apiVersion: v1
6 | kind: Service
7 | metadata:
8 | name: api-gateway
9 | namespace: egyptian-map-pi
10 | labels:
11 | app: api-gateway
12 | part-of: egyptian-map-pi
13 | tier: frontend
14 | environment: production
15 | annotations:
16 | prometheus.io/scrape: "true"
17 | prometheus.io/port: "3000"
18 | spec:
19 | type: ClusterIP # Internal service type for security
20 | ports:
21 | - port: 80 # External port for service discovery
22 | targetPort: 3000 # Application port
23 | protocol: TCP
24 | name: http-api
25 | selector:
26 | app: api-gateway
27 | sessionAffinity: ClientIP # Enable session stickiness
28 | sessionAffinityConfig:
29 | clientIP:
30 | timeoutSeconds: 10800 # 3-hour session timeout
31 |
32 | # Authentication Service
33 | - apiVersion: v1
34 | kind: Service
35 | metadata:
36 | name: auth-service
37 | namespace: egyptian-map-pi
38 | labels:
39 | app: auth-service
40 | part-of: egyptian-map-pi
41 | tier: backend
42 | environment: production
43 | annotations:
44 | prometheus.io/scrape: "true"
45 | prometheus.io/port: "3001"
46 | spec:
47 | type: ClusterIP # Internal-only access
48 | ports:
49 | - port: 3001
50 | targetPort: 3001
51 | protocol: TCP
52 | name: http-auth
53 | selector:
54 | app: auth-service
55 | sessionAffinity: None # Stateless service
56 |
57 | # Marketplace Service
58 | - apiVersion: v1
59 | kind: Service
60 | metadata:
61 | name: marketplace-service
62 | namespace: egyptian-map-pi
63 | labels:
64 | app: marketplace-service
65 | part-of: egyptian-map-pi
66 | tier: backend
67 | environment: production
68 | annotations:
69 | prometheus.io/scrape: "true"
70 | prometheus.io/port: "3002"
71 | spec:
72 | type: ClusterIP # Internal-only access
73 | ports:
74 | - port: 3002
75 | targetPort: 3002
76 | protocol: TCP
77 | name: http-marketplace
78 | selector:
79 | app: marketplace-service
80 | sessionAffinity: None # Stateless service
--------------------------------------------------------------------------------
/src/web/public/locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "chat": {
3 | "title": "Messages",
4 | "newMessage": "New Message",
5 | "noMessages": "No messages",
6 | "loadMore": "Load More",
7 | "typeMessage": "Type your message...",
8 | "send": "Send",
9 | "attachImage": "Attach Image",
10 | "today": "Today",
11 | "yesterday": "Yesterday",
12 | "online": "Online",
13 | "offline": "Offline",
14 | "lastSeen": "Last seen {{time}}",
15 | "typing": "{{user}} is typing...",
16 | "imagePreview": "Image Preview",
17 | "voiceMessage": "Voice Message",
18 | "location": "Location"
19 | },
20 | "status": {
21 | "sent": "Sent",
22 | "delivered": "Delivered",
23 | "read": "Read",
24 | "failed": "Failed",
25 | "pending": "Pending",
26 | "uploading": "Uploading...",
27 | "downloading": "Downloading..."
28 | },
29 | "errors": {
30 | "sendFailed": "Failed to send message. Please try again",
31 | "loadFailed": "Failed to load messages",
32 | "networkError": "Network error",
33 | "invalidMessage": "Invalid message",
34 | "unauthorized": "Please login to chat",
35 | "attachmentFailed": "Failed to attach file",
36 | "fileTooLarge": "File size exceeds limit",
37 | "invalidFileType": "Unsupported file type"
38 | },
39 | "conversation": {
40 | "with": "Chat with {{name}}",
41 | "about": "About {{item}}",
42 | "price": "Price: {{amount}} Pi",
43 | "startChat": "Start Chat",
44 | "block": "Block User",
45 | "report": "Report Content",
46 | "delete": "Delete Conversation",
47 | "confirmDelete": "Are you sure you want to delete this conversation?",
48 | "blocked": "You have blocked this user",
49 | "unblock": "Unblock User",
50 | "reported": "Content reported",
51 | "archive": "Archive Conversation",
52 | "unarchive": "Unarchive Conversation"
53 | },
54 | "notifications": {
55 | "newMessage": "New message from {{sender}}",
56 | "messageRequest": "New chat request",
57 | "accepted": "Chat request accepted",
58 | "declined": "Chat request declined",
59 | "blocked": "You have been blocked by {{user}}",
60 | "unblocked": "You have been unblocked by {{user}}",
61 | "mentioned": "{{user}} mentioned you",
62 | "reacted": "{{user}} reacted to your message"
63 | }
64 | }
--------------------------------------------------------------------------------
/frontend/src/features/LoyaltyProgram/LoyaltyProgram.js:
--------------------------------------------------------------------------------
1 | // src/features/LoyaltyProgram/LoyaltyProgram.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { getLoyaltyPoints, getRewards, redeemReward } from './LoyaltyService';
5 | import './LoyaltyProgram.css';
6 |
7 | const LoyaltyProgram = () => {
8 | const [points, setPoints] = useState(0);
9 | const [rewards, setRewards] = useState([]);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 |
13 | useEffect(() => {
14 | const fetchLoyaltyData = async () => {
15 | try {
16 | const userPoints = await getLoyaltyPoints();
17 | const availableRewards = await getRewards();
18 | setPoints(userPoints);
19 | setRewards(availableRewards);
20 | } catch (err) {
21 | setError('Failed to fetch loyalty data');
22 | } finally {
23 | setLoading(false);
24 | }
25 | };
26 | fetchLoyaltyData();
27 | }, []);
28 |
29 | const handleRedeem = async (rewardId) => {
30 | try {
31 | await redeemReward(rewardId);
32 | alert('Reward redeemed successfully!');
33 | // Refresh points and rewards
34 | const userPoints = await getLoyaltyPoints();
35 | const availableRewards = await getRewards();
36 | setPoints(userPoints);
37 | setRewards(availableRewards);
38 | } catch (err) {
39 | alert('Failed to redeem reward');
40 | }
41 | };
42 |
43 | if (loading) return Loading...
;
44 | if (error) return {error}
;
45 |
46 | return (
47 |
48 |
Your Loyalty Points: {points}
49 |
Available Rewards:
50 |
51 | {rewards.map((reward) => (
52 | -
53 | {reward.name} - {reward.cost} points
54 |
55 |
56 | ))}
57 |
58 |
59 | );
60 | };
61 |
62 | export default LoyaltyProgram;
63 |
--------------------------------------------------------------------------------
/src/backend/api-gateway/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "rootDir": "./src",
5 | "outDir": "./dist",
6 | "baseUrl": "./src",
7 | "paths": {
8 | "@shared/*": ["../../shared/*"],
9 | "@config/*": ["config/*"],
10 | "@middleware/*": ["middleware/*"],
11 | "@routes/*": ["routes/*"],
12 | "@types/*": ["types/*"]
13 | },
14 | "composite": true,
15 | "declaration": true,
16 | "sourceMap": true,
17 | "target": "ES2022",
18 | "module": "CommonJS",
19 | "lib": ["ES2022"],
20 | "strict": true,
21 | "alwaysStrict": true,
22 | "noImplicitAny": true,
23 | "strictNullChecks": true,
24 | "strictFunctionTypes": true,
25 | "strictBindCallApply": true,
26 | "strictPropertyInitialization": true,
27 | "noImplicitThis": true,
28 | "useUnknownInCatchVariables": true,
29 | "noUnusedLocals": true,
30 | "noUnusedParameters": true,
31 | "exactOptionalPropertyTypes": true,
32 | "noImplicitReturns": true,
33 | "noFallthroughCasesInSwitch": true,
34 | "noUncheckedIndexedAccess": true,
35 | "noImplicitOverride": true,
36 | "allowUnusedLabels": false,
37 | "allowUnreachableCode": false,
38 | "esModuleInterop": true,
39 | "skipLibCheck": true,
40 | "forceConsistentCasingInFileNames": true,
41 | "moduleResolution": "node",
42 | "resolveJsonModule": true,
43 | "experimentalDecorators": true,
44 | "emitDecoratorMetadata": true,
45 | "incremental": true,
46 | "tsBuildInfoFile": "./dist/.tsbuildinfo"
47 | },
48 | "include": [
49 | "src/**/*.ts",
50 | "src/**/*.json"
51 | ],
52 | "exclude": [
53 | "node_modules",
54 | "dist",
55 | "coverage",
56 | "**/*.test.ts",
57 | "**/*.spec.ts"
58 | ],
59 | "references": [
60 | {
61 | "path": "../shared"
62 | }
63 | ],
64 | "ts-node": {
65 | "transpileOnly": true,
66 | "files": true,
67 | "compilerOptions": {
68 | "module": "CommonJS"
69 | }
70 | },
71 | "watchOptions": {
72 | "watchFile": "useFsEvents",
73 | "watchDirectory": "useFsEvents",
74 | "fallbackPolling": "dynamicPriority",
75 | "synchronousWatchDirectory": true,
76 | "excludeDirectories": [
77 | "**/node_modules",
78 | "dist"
79 | ]
80 | }
81 | }
--------------------------------------------------------------------------------
/src/backend/auth-service/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "target": "ES2022",
5 | "module": "CommonJS",
6 | "lib": ["ES2022"],
7 |
8 | // Output configuration
9 | "rootDir": "./src",
10 | "outDir": "./dist",
11 | "baseUrl": "./src",
12 |
13 | // Path aliases for auth service
14 | "paths": {
15 | "@interfaces/*": ["interfaces/*"],
16 | "@config/*": ["config/*"],
17 | "@models/*": ["models/*"],
18 | "@services/*": ["services/*"],
19 | "@controllers/*": ["controllers/*"],
20 | "@utils/*": ["utils/*"],
21 | "@shared/*": ["../../shared/*"]
22 | },
23 |
24 | // Strict type checking
25 | "strict": true,
26 | "noImplicitAny": true,
27 | "strictNullChecks": true,
28 | "strictFunctionTypes": true,
29 | "strictBindCallApply": true,
30 | "strictPropertyInitialization": true,
31 | "noImplicitThis": true,
32 | "alwaysStrict": true,
33 |
34 | // Additional checks
35 | "noUnusedLocals": true,
36 | "noUnusedParameters": true,
37 | "noImplicitReturns": true,
38 | "noFallthroughCasesInSwitch": true,
39 |
40 | // Module resolution
41 | "moduleResolution": "node",
42 | "allowSyntheticDefaultImports": true,
43 | "esModuleInterop": true,
44 |
45 | // Decorator support for Pi Network auth
46 | "experimentalDecorators": true,
47 | "emitDecoratorMetadata": true,
48 |
49 | // Build optimization
50 | "skipLibCheck": true,
51 | "forceConsistentCasingInFileNames": true,
52 | "resolveJsonModule": true,
53 | "sourceMap": false,
54 | "declaration": true,
55 | "composite": true,
56 | "incremental": true
57 | },
58 |
59 | // Project references
60 | "references": [
61 | {
62 | "path": "../shared"
63 | }
64 | ],
65 |
66 | // Source files
67 | "include": [
68 | "src/**/*.ts",
69 | "src/**/*.json"
70 | ],
71 | "exclude": [
72 | "node_modules",
73 | "dist",
74 | "coverage",
75 | "**/*.test.ts",
76 | "**/*.spec.ts",
77 | "**/__tests__/*",
78 | "**/__mocks__/*"
79 | ],
80 |
81 | // ts-node configuration for development
82 | "ts-node": {
83 | "transpileOnly": true,
84 | "files": true,
85 | "compilerOptions": {
86 | "module": "CommonJS"
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/infrastructure/kubernetes/autoscaling/vpa.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: autoscaling.k8s.io/v1
2 | kind: VerticalPodAutoscaler
3 | metadata:
4 | name: api-gateway-vpa
5 | namespace: app
6 | annotations:
7 | # Enable VPA monitoring integration
8 | vpa.monitoring/enabled: "true"
9 | # Indicate HPA coordination
10 | vpa.coordination/hpa-managed: "true"
11 | # Additional metadata for monitoring
12 | vpa.metrics/update-interval: "1m"
13 | vpa.policy/mode: "Auto"
14 | spec:
15 | targetRef:
16 | apiVersion: apps/v1
17 | kind: Deployment
18 | name: api-gateway
19 | updatePolicy:
20 | updateMode: "Auto"
21 | resourcePolicy:
22 | containerPolicies:
23 | - containerName: api-gateway
24 | # Set minimum resource bounds based on baseline usage
25 | minAllowed:
26 | cpu: "100m"
27 | memory: "256Mi"
28 | # Set maximum resource bounds based on peak load estimates
29 | maxAllowed:
30 | cpu: "1000m"
31 | memory: "1Gi"
32 | # Specify resources to be controlled
33 | controlledResources: ["cpu", "memory"]
34 | # Control scaling behavior
35 | controlledValues: "RequestsAndLimits"
36 | ---
37 | apiVersion: autoscaling.k8s.io/v1
38 | kind: VerticalPodAutoscaler
39 | metadata:
40 | name: marketplace-service-vpa
41 | namespace: app
42 | annotations:
43 | # Enable VPA monitoring integration
44 | vpa.monitoring/enabled: "true"
45 | # Indicate HPA coordination
46 | vpa.coordination/hpa-managed: "true"
47 | # Additional metadata for monitoring
48 | vpa.metrics/update-interval: "1m"
49 | vpa.policy/mode: "Auto"
50 | spec:
51 | targetRef:
52 | apiVersion: apps/v1
53 | kind: Deployment
54 | name: marketplace-service
55 | updatePolicy:
56 | updateMode: "Auto"
57 | resourcePolicy:
58 | containerPolicies:
59 | - containerName: marketplace-service
60 | # Set minimum resource bounds based on service requirements
61 | minAllowed:
62 | cpu: "500m"
63 | memory: "512Mi"
64 | # Set maximum resource bounds based on service scalability
65 | maxAllowed:
66 | cpu: "2000m"
67 | memory: "2Gi"
68 | # Specify resources to be controlled
69 | controlledResources: ["cpu", "memory"]
70 | # Control scaling behavior
71 | controlledValues: "RequestsAndLimits"
--------------------------------------------------------------------------------
/src/backend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "CommonJS",
5 | "lib": ["ES2022"],
6 |
7 | // Type checking and declaration generation
8 | "declaration": true,
9 | "declarationMap": true,
10 | "sourceMap": true,
11 | "composite": true,
12 | "incremental": true,
13 | "strict": true,
14 |
15 | // Module resolution
16 | "moduleResolution": "node",
17 | "esModuleInterop": true,
18 | "skipLibCheck": true,
19 | "forceConsistentCasingInFileNames": true,
20 | "resolveJsonModule": true,
21 |
22 | // Decorator support
23 | "experimentalDecorators": true,
24 | "emitDecoratorMetadata": true,
25 |
26 | // Path aliases for microservices
27 | "paths": {
28 | "@shared/*": ["./shared/*"],
29 | "@api-gateway/*": ["./api-gateway/src/*"],
30 | "@auth/*": ["./auth-service/src/*"],
31 | "@marketplace/*": ["./marketplace-service/src/*"],
32 | "@payment/*": ["./payment-service/src/*"],
33 | "@location/*": ["./location-service/src/*"],
34 | "@messaging/*": ["./messaging-service/src/*"]
35 | },
36 |
37 | // Output configuration
38 | "rootDir": ".",
39 | "outDir": "./dist",
40 | "baseUrl": "."
41 | },
42 |
43 | // Project references for microservices
44 | "references": [
45 | { "path": "./api-gateway" },
46 | { "path": "./auth-service" },
47 | { "path": "./marketplace-service" },
48 | { "path": "./payment-service" },
49 | { "path": "./location-service" },
50 | { "path": "./messaging-service" }
51 | ],
52 |
53 | // Source files to include/exclude
54 | "include": [
55 | "api-gateway/src/**/*.ts",
56 | "auth-service/src/**/*.ts",
57 | "marketplace-service/src/**/*.ts",
58 | "payment-service/src/**/*.ts",
59 | "location-service/src/**/*.ts",
60 | "messaging-service/src/**/*.ts",
61 | "shared/**/*.ts"
62 | ],
63 | "exclude": [
64 | "node_modules",
65 | "dist",
66 | "coverage",
67 | "**/*.test.ts",
68 | "**/*.spec.ts",
69 | "**/__tests__/**",
70 | "**/__mocks__/**"
71 | ],
72 |
73 | // ts-node configuration for development
74 | "ts-node": {
75 | "transpileOnly": true,
76 | "files": true,
77 | "compilerOptions": {
78 | "module": "CommonJS"
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/frontend/src/features/Escrow/EscrowPayment.js:
--------------------------------------------------------------------------------
1 | // src/features/Escrow/EscrowPayment.js
2 |
3 | import React, { useState } from 'react';
4 | import { createEscrowPayment } from './EscrowService';
5 | import './EscrowPayment.css';
6 |
7 | const EscrowPayment = () => {
8 | const [amount, setAmount] = useState('');
9 | const [recipient, setRecipient] = useState('');
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 |
13 | const handleSubmit = async (e) => {
14 | e.preventDefault();
15 | setError(null);
16 | setSuccess(false);
17 |
18 | try {
19 | await createEscrowPayment({ amount, recipient });
20 | setSuccess(true);
21 | setAmount('');
22 | setRecipient('');
23 | } catch (err) {
24 | setError('Failed to create escrow payment. Please try again.');
25 | }
26 | };
27 |
28 | return (
29 |
30 |
Escrow Payment
31 | {error &&
{error}
}
32 | {success &&
Payment created successfully!
}
33 |
58 |
59 | );
60 | };
61 |
62 | export default EscrowPayment;
63 |
--------------------------------------------------------------------------------
/src/backend/messaging-service/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1: Builder
2 | FROM node:18-alpine AS builder
3 |
4 | # Set working directory
5 | WORKDIR /app
6 |
7 | # Install build dependencies
8 | RUN apk add --no-cache python3 make g++
9 |
10 | # Copy package files
11 | COPY package*.json ./
12 | COPY tsconfig.json ./
13 |
14 | # Install dependencies including dev dependencies for build
15 | RUN npm ci
16 |
17 | # Copy source code
18 | COPY src/ ./src/
19 |
20 | # Build TypeScript code
21 | RUN npm run build
22 |
23 | # Prune dev dependencies
24 | RUN npm prune --production
25 |
26 | # Stage 2: Production
27 | FROM node:18-alpine
28 |
29 | # Set working directory
30 | WORKDIR /app
31 |
32 | # Install production dependencies
33 | RUN apk add --no-cache tini curl
34 |
35 | # Create non-root user
36 | RUN addgroup -g 1001 nodejs && \
37 | adduser -u 1001 -G nodejs -s /bin/sh -D nodejs
38 |
39 | # Set environment variables
40 | ENV NODE_ENV=production \
41 | PORT=3004 \
42 | SOCKET_PATH=/socket.io \
43 | NODE_OPTIONS="--max-old-space-size=2048" \
44 | LOG_LEVEL=info \
45 | npm_config_unsafe_perm=false
46 |
47 | # Copy production dependencies and built code
48 | COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
49 | COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
50 | COPY --chown=nodejs:nodejs package.json ./
51 |
52 | # Create healthcheck script
53 | RUN echo '#!/usr/bin/env node\n\
54 | const http = require("http");\n\
55 | const options = {\n\
56 | host: "localhost",\n\
57 | port: process.env.PORT || 3004,\n\
58 | path: "/health",\n\
59 | timeout: 2000\n\
60 | };\n\
61 | const request = http.request(options, (res) => {\n\
62 | process.exit(res.statusCode === 200 ? 0 : 1);\n\
63 | });\n\
64 | request.on("error", function(err) {\n\
65 | process.exit(1);\n\
66 | });\n\
67 | request.end();' > healthcheck.js && \
68 | chmod +x healthcheck.js
69 |
70 | # Set secure permissions
71 | RUN chown -R nodejs:nodejs /app && \
72 | chmod -R 755 /app
73 |
74 | # Switch to non-root user
75 | USER nodejs
76 |
77 | # Expose service port
78 | EXPOSE 3004
79 |
80 | # Health check configuration
81 | HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
82 | CMD node healthcheck.js
83 |
84 | # Use tini as init system
85 | ENTRYPOINT ["/sbin/tini", "--"]
86 |
87 | # Start the service
88 | CMD ["node", "dist/cluster.js"]
--------------------------------------------------------------------------------
/src/backend/shared/interfaces/base.interface.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Defines foundational interfaces that provide essential tracking and
3 | * identification properties for all entities in the Egyptian Map of Pi backend services.
4 | * These interfaces ensure consistent entity structure, audit trail capabilities, and
5 | * MongoDB compatibility across the entire system.
6 | */
7 |
8 | /**
9 | * Core interface that defines essential tracking and identification properties
10 | * required by all entities in the system.
11 | *
12 | * @interface BaseEntity
13 | * @property {string} id - Unique identifier for the entity
14 | * @property {Date} createdAt - Timestamp when the entity was created
15 | * @property {Date} updatedAt - Timestamp when the entity was last updated
16 | * @property {boolean} isActive - Flag indicating if the entity is active or soft-deleted
17 | */
18 | export interface BaseEntity {
19 | /**
20 | * Unique identifier for the entity
21 | */
22 | id: string;
23 |
24 | /**
25 | * Timestamp when the entity was created
26 | */
27 | createdAt: Date;
28 |
29 | /**
30 | * Timestamp when the entity was last updated
31 | */
32 | updatedAt: Date;
33 |
34 | /**
35 | * Flag indicating if the entity is active (true) or soft-deleted (false)
36 | * Used for implementing soft delete pattern across the system
37 | */
38 | isActive: boolean;
39 | }
40 |
41 | /**
42 | * MongoDB-specific document interface that extends BaseEntity to ensure
43 | * database compatibility while maintaining type safety.
44 | * This interface should be used when defining MongoDB document types.
45 | *
46 | * @interface BaseDocument
47 | * @extends {BaseEntity}
48 | */
49 | export interface BaseDocument extends BaseEntity {
50 | /**
51 | * MongoDB document identifier
52 | * Inherits id from BaseEntity but explicitly defined for clarity
53 | */
54 | id: string;
55 |
56 | /**
57 | * Creation timestamp
58 | * Inherits createdAt from BaseEntity but explicitly defined for clarity
59 | */
60 | createdAt: Date;
61 |
62 | /**
63 | * Last update timestamp
64 | * Inherits updatedAt from BaseEntity but explicitly defined for clarity
65 | */
66 | updatedAt: Date;
67 |
68 | /**
69 | * Active status flag
70 | * Inherits isActive from BaseEntity but explicitly defined for clarity
71 | */
72 | isActive: boolean;
73 | }
--------------------------------------------------------------------------------
/src/web/src/types/environment.d.ts:
--------------------------------------------------------------------------------
1 | // @types/node v18.0.0
2 | import 'node';
3 |
4 | /**
5 | * Union type defining allowed deployment environment values for strict type checking
6 | * Used to ensure environment configuration is properly typed across the application
7 | */
8 | export type Environment = 'development' | 'staging' | 'production';
9 |
10 | /**
11 | * Extended ProcessEnv interface to provide type safety for environment variables
12 | * Augments the NodeJS.ProcessEnv interface with application-specific environment variables
13 | */
14 | declare global {
15 | namespace NodeJS {
16 | interface ProcessEnv {
17 | /**
18 | * Current deployment environment
19 | * @default 'development'
20 | */
21 | NEXT_PUBLIC_APP_ENV: Environment;
22 |
23 | /**
24 | * Base URL for API endpoints
25 | * @example 'https://api.egyptianmapofpi.com'
26 | */
27 | NEXT_PUBLIC_API_URL: string;
28 |
29 | /**
30 | * Mapbox access token for map integration
31 | * Required for location-based features
32 | */
33 | NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN: string;
34 |
35 | /**
36 | * Custom map style URL for Egyptian-specific styling
37 | * @example 'mapbox://styles/egyptianmapofpi/custom-style'
38 | */
39 | NEXT_PUBLIC_MAP_STYLE_URL: string;
40 |
41 | /**
42 | * Pi Network API key for platform integration
43 | * Used for authentication and payment processing
44 | */
45 | NEXT_PUBLIC_PI_API_KEY: string;
46 |
47 | /**
48 | * Default application language
49 | * Supports Arabic (primary) and English (secondary)
50 | * @default 'ar'
51 | */
52 | NEXT_PUBLIC_DEFAULT_LANGUAGE: 'ar' | 'en';
53 |
54 | /**
55 | * Default application theme
56 | * Supports light and dark modes
57 | * @default 'light'
58 | */
59 | NEXT_PUBLIC_DEFAULT_THEME: 'light' | 'dark';
60 |
61 | /**
62 | * WebSocket server URL for real-time features
63 | * Used for chat and notifications
64 | */
65 | NEXT_PUBLIC_SOCKET_URL: string;
66 |
67 | /**
68 | * CDN URL for static assets and media content
69 | * Optimized for Egyptian region delivery
70 | */
71 | NEXT_PUBLIC_CDN_URL: string;
72 | }
73 | }
74 | }
75 |
76 | // Ensure this file is treated as a module
77 | export {};
--------------------------------------------------------------------------------
/src/backend/api-gateway/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1: Builder
2 | FROM node:18-alpine AS builder
3 |
4 | # Set working directory
5 | WORKDIR /app
6 |
7 | # Install build dependencies and tools
8 | RUN apk add --no-cache python3 make g++ git curl
9 |
10 | # Copy package files for dependency caching
11 | COPY package*.json ./
12 | COPY tsconfig.json ./
13 |
14 | # Install dependencies with strict version control and security audit
15 | RUN npm ci --ignore-scripts \
16 | && npm audit fix \
17 | && npm cache clean --force
18 |
19 | # Copy source code
20 | COPY src/ ./src/
21 |
22 | # Build TypeScript code with optimizations
23 | RUN npm run build \
24 | && npm prune --production
25 |
26 | # Stage 2: Production
27 | FROM node:18-alpine
28 |
29 | # Set labels
30 | LABEL maintainer="Egyptian Map of Pi Team" \
31 | service="api-gateway" \
32 | version="1.0.0" \
33 | environment="production" \
34 | region="me-south-1"
35 |
36 | # Set environment variables
37 | ENV NODE_ENV=production \
38 | PORT=3000 \
39 | TZ=Africa/Cairo \
40 | LANG=en_US.UTF-8 \
41 | NODE_OPTIONS="--max-old-space-size=2048"
42 |
43 | # Install production dependencies
44 | RUN apk add --no-cache tzdata curl \
45 | && cp /usr/share/zoneinfo/$TZ /etc/localtime \
46 | && echo $TZ > /etc/timezone
47 |
48 | # Create non-root user
49 | RUN addgroup -g 1001 -S nodejs \
50 | && adduser -S nodejs -u 1001 -G nodejs
51 |
52 | # Set working directory and permissions
53 | WORKDIR /app
54 | RUN chown -R nodejs:nodejs /app
55 |
56 | # Copy built artifacts from builder stage
57 | COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
58 | COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
59 | COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
60 |
61 | # Switch to non-root user
62 | USER nodejs
63 |
64 | # Security hardening
65 | RUN npm config set ignore-scripts true \
66 | && npm config set audit true \
67 | && npm config set fund false
68 |
69 | # Health check configuration
70 | HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
71 | CMD curl -f http://localhost:$PORT/health || exit 1
72 |
73 | # Set resource limits
74 | ENV NODE_OPTIONS="--max-old-space-size=2048 --max-http-header-size=16384"
75 |
76 | # Expose API port
77 | EXPOSE $PORT
78 |
79 | # Start application with proper signal handling
80 | CMD ["node", "--enable-source-maps", "dist/app.js"]
--------------------------------------------------------------------------------
/src/backend/marketplace-service/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1: Builder
2 | # node:18.17.1-alpine3.18 (v9.8.1 npm)
3 | FROM node:18.17.1-alpine3.18 AS builder
4 |
5 | # Add build dependencies and security updates
6 | RUN apk update && \
7 | apk add --no-cache \
8 | python3 \
9 | make \
10 | g++ \
11 | && rm -rf /var/cache/apk/*
12 |
13 | # Create app directory with appropriate permissions
14 | WORKDIR /app
15 | RUN chown -R node:node /app
16 |
17 | # Switch to non-root user for build process
18 | USER node
19 |
20 | # Copy package files with version locking
21 | COPY --chown=node:node package*.json ./
22 |
23 | # Install dependencies with strict version control
24 | RUN npm ci --only=production && \
25 | # Cache clean for optimization
26 | npm cache clean --force
27 |
28 | # Copy source code with appropriate ownership
29 | COPY --chown=node:node . .
30 |
31 | # Build TypeScript code with production optimizations
32 | RUN npm run build && \
33 | # Remove source maps in production
34 | rm -rf dist/**/*.js.map
35 |
36 | # Stage 2: Production
37 | FROM node:18.17.1-alpine3.18 AS production
38 |
39 | # Add production dependencies and security updates
40 | RUN apk update && \
41 | apk add --no-cache \
42 | tini \
43 | curl \
44 | && rm -rf /var/cache/apk/*
45 |
46 | # Create app directory with restricted permissions
47 | WORKDIR /app
48 | RUN chown -R node:node /app
49 |
50 | # Switch to non-root user
51 | USER node
52 |
53 | # Copy built artifacts and dependencies from builder
54 | COPY --chown=node:node --from=builder /app/dist ./dist
55 | COPY --chown=node:node --from=builder /app/node_modules ./node_modules
56 | COPY --chown=node:node --from=builder /app/package*.json ./
57 |
58 | # Set secure file permissions
59 | RUN chmod -R 755 /app
60 |
61 | # Set production environment variables
62 | ENV NODE_ENV=production \
63 | PORT=3003 \
64 | LOG_LEVEL=info \
65 | API_TIMEOUT=30000 \
66 | MAX_PAYLOAD_SIZE=10mb
67 |
68 | # Configure health check
69 | HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
70 | CMD curl -f http://localhost:${PORT}/health || exit 1
71 |
72 | # Use tini as init process
73 | ENTRYPOINT ["/sbin/tini", "--"]
74 |
75 | # Set resource limits
76 | LABEL com.egyptian-map-pi.resource.memory="512M" \
77 | com.egyptian-map-pi.resource.cpu="0.5"
78 |
79 | # Expose service port
80 | EXPOSE 3003
81 |
82 | # Start the service
83 | CMD ["node", "dist/server.js"]
--------------------------------------------------------------------------------
/infrastructure/kubernetes/storage/persistent-volumes.yaml:
--------------------------------------------------------------------------------
1 | # Kubernetes manifest for storage configuration
2 | # Version: Kubernetes 1.27+
3 | # AWS EBS CSI Driver: 1.5+
4 |
5 | # StorageClass for optimized EBS GP3 volumes with encryption and performance settings
6 | apiVersion: storage.k8s.io/v1
7 | kind: StorageClass
8 | metadata:
9 | name: ebs-gp3
10 | annotations:
11 | # Set as default storage class for the cluster
12 | storageclass.kubernetes.io/is-default-class: "true"
13 | labels:
14 | app.kubernetes.io/name: egyptian-map-of-pi
15 | app.kubernetes.io/component: storage
16 | app.kubernetes.io/part-of: infrastructure
17 | spec:
18 | # Use AWS EBS CSI driver for dynamic provisioning
19 | provisioner: ebs.csi.aws.com
20 | # GP3 volume configuration parameters
21 | parameters:
22 | type: gp3
23 | # Enable encryption by default for data security
24 | encrypted: "true"
25 | # Use ext4 filesystem for optimal performance
26 | fsType: ext4
27 | # Configure baseline performance
28 | iops: "3000"
29 | throughput: "125"
30 | # Use AWS KMS for encryption key management
31 | kmsKeyId: "auto"
32 | # Keep volumes after PVC deletion for data safety
33 | reclaimPolicy: Retain
34 | # Wait for pod scheduling before volume provisioning
35 | volumeBindingMode: WaitForFirstConsumer
36 | # Allow volume expansion for future scaling
37 | allowVolumeExpansion: true
38 | # Restrict volume provisioning to specific AZs
39 | allowedTopologies:
40 | - matchLabelExpressions:
41 | - key: topology.kubernetes.io/zone
42 | values:
43 | - me-south-1a
44 | - me-south-1b
45 | - me-south-1c
46 | # Volume mount options for performance and reliability
47 | mountOptions:
48 | - noatime
49 | - nodiratime
50 | - nobarrier
51 |
52 | ---
53 | # Default storage quota to prevent resource exhaustion
54 | apiVersion: v1
55 | kind: ResourceQuota
56 | metadata:
57 | name: storage-quota
58 | namespace: egyptian-map-of-pi
59 | spec:
60 | hard:
61 | # Limit total storage capacity
62 | requests.storage: 1000Gi
63 | # Limit number of PVCs
64 | persistentvolumeclaims: "20"
65 | # Limit GP3 storage specifically
66 | ebs-gp3.storageclass.storage.k8s.io/requests.storage: 800Gi
67 |
68 | ---
69 | # PriorityClass for storage operations
70 | apiVersion: scheduling.k8s.io/v1
71 | kind: PriorityClass
72 | metadata:
73 | name: storage-critical
74 | spec:
75 | value: 1000000
76 | globalDefault: false
77 | description: "Critical priority class for storage operations"
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Dependabot configuration v2 for Egyptian Map of Pi
2 | # Manages automated dependency updates for backend, frontend and GitHub Actions
3 | version: 2
4 | updates:
5 | # Backend Node.js dependencies
6 | - package-ecosystem: "npm"
7 | directory: "/src/backend"
8 | schedule:
9 | interval: "weekly"
10 | day: "monday"
11 | timezone: "Africa/Cairo"
12 | labels:
13 | - "dependencies"
14 | - "backend"
15 | assignees:
16 | - "egyptian-map-pi-team"
17 | reviewers:
18 | - "egyptian-map-pi-team"
19 | commit-message:
20 | prefix: "chore(deps)"
21 | include: "scope"
22 | groups:
23 | typescript-eslint:
24 | patterns:
25 | - "@typescript-eslint/*"
26 | jest:
27 | patterns:
28 | - "jest"
29 | - "@types/jest"
30 | - "ts-jest"
31 | node-core:
32 | patterns:
33 | - "express"
34 | - "mongoose"
35 | - "redis"
36 | ignore:
37 | - dependency-name: "node"
38 | versions: [">=19.0.0"]
39 | security-updates-only: false
40 | open-pull-requests-limit: 10
41 |
42 | # Frontend React dependencies
43 | - package-ecosystem: "npm"
44 | directory: "/src/web"
45 | schedule:
46 | interval: "weekly"
47 | day: "monday"
48 | timezone: "Africa/Cairo"
49 | labels:
50 | - "dependencies"
51 | - "frontend"
52 | assignees:
53 | - "egyptian-map-pi-team"
54 | reviewers:
55 | - "egyptian-map-pi-team"
56 | commit-message:
57 | prefix: "chore(deps)"
58 | include: "scope"
59 | groups:
60 | react:
61 | patterns:
62 | - "react"
63 | - "react-dom"
64 | - "@types/react*"
65 | mui:
66 | patterns:
67 | - "@mui/*"
68 | testing:
69 | patterns:
70 | - "@testing-library/*"
71 | - "jest"
72 | - "@types/jest"
73 | ignore:
74 | - dependency-name: "node"
75 | versions: [">=19.0.0"]
76 | security-updates-only: false
77 | open-pull-requests-limit: 10
78 |
79 | # GitHub Actions workflow dependencies
80 | - package-ecosystem: "github-actions"
81 | directory: "/"
82 | schedule:
83 | interval: "monthly"
84 | timezone: "Africa/Cairo"
85 | labels:
86 | - "dependencies"
87 | - "ci-cd"
88 | assignees:
89 | - "egyptian-map-pi-team"
90 | reviewers:
91 | - "egyptian-map-pi-team"
92 | commit-message:
93 | prefix: "chore(ci)"
94 | include: "scope"
95 | security-updates-only: false
96 | open-pull-requests-limit: 5
--------------------------------------------------------------------------------
/frontend/src/features/Subscription/SubscriptionForm.js:
--------------------------------------------------------------------------------
1 | // src/features/Subscription/SubscriptionForm.js
2 |
3 | import React, { useState } from 'react';
4 | import { createSubscription } from './SubscriptionService';
5 | import './SubscriptionForm.css';
6 |
7 | const SubscriptionForm = () => {
8 | const [plan, setPlan] = useState('');
9 | const [paymentInfo, setPaymentInfo] = useState('');
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 |
13 | const handleSubmit = async (e) => {
14 | e.preventDefault();
15 | setError(null);
16 | setSuccess(false);
17 |
18 | try {
19 | await createSubscription({ plan, paymentInfo });
20 | setSuccess(true);
21 | setPlan('');
22 | setPaymentInfo('');
23 | } catch (err) {
24 | setError('Failed to create subscription. Please try again.');
25 | }
26 | };
27 |
28 | return (
29 |
30 |
Subscribe to a Plan
31 | {error &&
{error}
}
32 | {success &&
Subscription created successfully!
}
33 |
61 |
62 | );
63 | };
64 |
65 | export default SubscriptionForm;
66 |
--------------------------------------------------------------------------------
/src/backend/location-service/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1: Builder
2 | FROM node:18-alpine AS builder
3 |
4 | # Install build dependencies
5 | RUN apk add --no-cache python3 make g++
6 |
7 | # Set working directory
8 | WORKDIR /app
9 |
10 | # Copy package files with strict version control
11 | COPY package*.json ./
12 |
13 | # Install dependencies with npm ci for reproducible builds
14 | RUN npm ci --no-audit
15 |
16 | # Copy source code and TypeScript config
17 | COPY . .
18 |
19 | # Build TypeScript code with optimizations
20 | RUN npm run build \
21 | && npm prune --production \
22 | && npm cache clean --force
23 |
24 | # Run security audit
25 | RUN npm audit
26 |
27 | # Stage 2: Production
28 | FROM node:18-alpine
29 |
30 | # Install dumb-init for proper process management
31 | RUN apk add --no-cache dumb-init=1.2.5-r2
32 |
33 | # Set working directory
34 | WORKDIR /app
35 |
36 | # Copy built artifacts and dependencies from builder
37 | COPY --from=builder /app/dist ./dist
38 | COPY --from=builder /app/node_modules ./node_modules
39 | COPY --from=builder /app/package*.json ./
40 | COPY --from=builder /app/healthcheck.js ./
41 |
42 | # Set secure permissions
43 | RUN chown -R node:node /app \
44 | && chmod -R 755 /app
45 |
46 | # Create non-root user
47 | USER node
48 |
49 | # Set environment variables
50 | ENV NODE_ENV=production \
51 | PORT=3002 \
52 | NODE_OPTIONS="--max-old-space-size=2048" \
53 | TZ="Africa/Cairo"
54 |
55 | # Set security limits
56 | RUN ulimit -n 65535
57 |
58 | # Configure health check
59 | HEALTHCHECK --interval=30s \
60 | --timeout=10s \
61 | --start-period=40s \
62 | --retries=3 \
63 | CMD ["node", "healthcheck.js"] || exit 1
64 |
65 | # Expose service port
66 | EXPOSE 3002
67 |
68 | # Set startup command with dumb-init
69 | ENTRYPOINT ["/usr/bin/dumb-init", "--"]
70 | CMD ["node", "dist/index.js"]
71 |
72 | # Build-time metadata
73 | LABEL maintainer="Egyptian Map of Pi Team" \
74 | version="1.0.0" \
75 | description="Location Service for Egyptian Map of Pi" \
76 | org.opencontainers.image.source="https://github.com/egyptian-map-of-pi/location-service" \
77 | org.opencontainers.image.vendor="Pi Network" \
78 | org.opencontainers.image.title="Location Service" \
79 | org.opencontainers.image.description="Handles geospatial operations, geocoding, and location-based features" \
80 | org.opencontainers.image.created="2023" \
81 | org.opencontainers.image.version="1.0.0" \
82 | org.opencontainers.image.licenses="Proprietary"
83 |
84 | # Security configurations
85 | RUN addgroup -S appgroup && adduser -S appuser -G appgroup
86 | USER appuser
--------------------------------------------------------------------------------
/src/backend/shared/constants/languages.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Language constants for Egyptian Map of Pi application
3 | * Defines core language settings with primary focus on Arabic support
4 | * @version 1.0.0
5 | */
6 |
7 | /**
8 | * Supported language codes following ISO 639-1 standard
9 | * AR: Arabic (Primary language for Egyptian market)
10 | * EN: English (Secondary language for international users)
11 | */
12 | export enum SUPPORTED_LANGUAGES {
13 | AR = 'ar',
14 | EN = 'en'
15 | }
16 |
17 | /**
18 | * Default application language set to Arabic for Egyptian market focus
19 | * This constant is used as the fallback language when user preference is not set
20 | */
21 | export const DEFAULT_LANGUAGE: SUPPORTED_LANGUAGES = SUPPORTED_LANGUAGES.AR;
22 |
23 | /**
24 | * Immutable mapping of languages to their text directions
25 | * Used for implementing RTL/LTR layout management across the application
26 | * Arabic: Right-to-Left (RTL)
27 | * English: Left-to-Right (LTR)
28 | */
29 | export const LANGUAGE_DIRECTIONS: Readonly> = {
30 | [SUPPORTED_LANGUAGES.AR]: 'rtl',
31 | [SUPPORTED_LANGUAGES.EN]: 'ltr'
32 | } as const;
33 |
34 | /**
35 | * Native language names for UI display
36 | * Maps language codes to their native script representation
37 | * Arabic is displayed in Arabic script: العربية
38 | * English is displayed in Latin script: English
39 | */
40 | export const LANGUAGE_NAMES: Readonly> = {
41 | [SUPPORTED_LANGUAGES.AR]: 'العربية',
42 | [SUPPORTED_LANGUAGES.EN]: 'English'
43 | } as const;
44 |
45 | /**
46 | * Type guard to check if a string is a supported language code
47 | * @param code - The language code to check
48 | * @returns boolean indicating if the code is a supported language
49 | */
50 | export const isSupportedLanguage = (code: string): code is SUPPORTED_LANGUAGES => {
51 | return Object.values(SUPPORTED_LANGUAGES).includes(code as SUPPORTED_LANGUAGES);
52 | };
53 |
54 | /**
55 | * Gets the text direction for a given language code
56 | * @param language - The language code to get direction for
57 | * @returns The text direction ('rtl' | 'ltr') for the language
58 | */
59 | export const getLanguageDirection = (language: SUPPORTED_LANGUAGES): 'rtl' | 'ltr' => {
60 | return LANGUAGE_DIRECTIONS[language];
61 | };
62 |
63 | /**
64 | * Gets the native name for a given language code
65 | * @param language - The language code to get native name for
66 | * @returns The native name string for the language
67 | */
68 | export const getLanguageName = (language: SUPPORTED_LANGUAGES): string => {
69 | return LANGUAGE_NAMES[language];
70 | };
--------------------------------------------------------------------------------
/infrastructure/kubernetes/secrets.yaml:
--------------------------------------------------------------------------------
1 | # API Gateway Secrets
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: api-gateway-secrets
6 | namespace: egyptian-map-pi
7 | labels:
8 | app: api-gateway
9 | part-of: egyptian-map-pi
10 | environment: production
11 | managed-by: terraform
12 | annotations:
13 | kubernetes.io/created-by: terraform
14 | vault.hashicorp.com/agent-inject: "true"
15 | vault.hashicorp.com/role: "api-gateway"
16 | vault.hashicorp.com/secret-rotation: "true"
17 | vault.hashicorp.com/secret-rotation-period: "24h"
18 | type: Opaque
19 | data:
20 | jwt-private-key: ${JWT_PRIVATE_KEY} # Base64 encoded JWT private key
21 | jwt-public-key: ${JWT_PUBLIC_KEY} # Base64 encoded JWT public key
22 | audit-key: ${AUDIT_KEY} # Base64 encoded audit encryption key
23 | ---
24 | # Auth Service Secrets
25 | apiVersion: v1
26 | kind: Secret
27 | metadata:
28 | name: auth-service-secrets
29 | namespace: egyptian-map-pi
30 | labels:
31 | app: auth-service
32 | part-of: egyptian-map-pi
33 | environment: production
34 | managed-by: terraform
35 | annotations:
36 | kubernetes.io/created-by: terraform
37 | vault.hashicorp.com/agent-inject: "true"
38 | vault.hashicorp.com/role: "auth-service"
39 | vault.hashicorp.com/secret-rotation: "true"
40 | vault.hashicorp.com/secret-rotation-period: "168h" # 7 days
41 | type: Opaque
42 | data:
43 | pi-network-api-key: ${PI_NETWORK_API_KEY} # Base64 encoded Pi Network API key
44 | pi-network-api-secret: ${PI_NETWORK_API_SECRET} # Base64 encoded Pi Network API secret
45 | kyc-encryption-key: ${KYC_ENCRYPTION_KEY} # Base64 encoded KYC data encryption key
46 | ---
47 | # Payment Service Secrets
48 | apiVersion: v1
49 | kind: Secret
50 | metadata:
51 | name: payment-service-secrets
52 | namespace: egyptian-map-pi
53 | labels:
54 | app: payment-service
55 | part-of: egyptian-map-pi
56 | environment: production
57 | managed-by: terraform
58 | annotations:
59 | kubernetes.io/created-by: terraform
60 | vault.hashicorp.com/agent-inject: "true"
61 | vault.hashicorp.com/role: "payment-service"
62 | vault.hashicorp.com/secret-rotation: "true"
63 | vault.hashicorp.com/secret-rotation-period: "168h" # 7 days
64 | encryption.egyptian-map-pi.io/version: "v1"
65 | type: Opaque
66 | data:
67 | pi-network-payment-key: ${PI_NETWORK_PAYMENT_KEY} # Base64 encoded Pi Network payment API key
68 | escrow-service-key: ${ESCROW_SERVICE_KEY} # Base64 encoded escrow service key
69 | transaction-encryption-key: ${TRANSACTION_ENCRYPT_KEY} # Base64 encoded transaction data encryption key
--------------------------------------------------------------------------------
/src/web/public/locales/ar/payment.json:
--------------------------------------------------------------------------------
1 | {
2 | "form": {
3 | "title": "إتمام الشراء",
4 | "amount": "المبلغ",
5 | "amount_placeholder": "أدخل المبلغ بعملة باي",
6 | "payment_method": "طريقة الدفع",
7 | "pi_wallet": "محفظة باي",
8 | "escrow_service": "خدمة الضمان",
9 | "escrow_checkbox": "أوافق على استخدام خدمة الضمان من شبكة باي",
10 | "escrow_info": "خدمة الضمان تحمي البائع والمشتري",
11 | "delivery_method": "طريقة التوصيل",
12 | "delivery_placeholder": "اختر طريقة التوصيل",
13 | "location": "موقعك",
14 | "current_location": "استخدم الموقع الحالي",
15 | "select_on_map": "اختر على الخريطة",
16 | "buttons": {
17 | "cancel": "إلغاء",
18 | "pay_now": "ادفع الآن",
19 | "processing": "جاري المعالجة..."
20 | },
21 | "errors": {
22 | "minimum_amount": "الحد الأدنى للمبلغ هو ٠.١ باي",
23 | "maximum_amount": "الحد الأقصى للمبلغ هو ١٠,٠٠٠ باي",
24 | "invalid_amount": "يرجى إدخال مبلغ صحيح",
25 | "required_field": "هذا الحقل مطلوب"
26 | }
27 | },
28 | "confirmation": {
29 | "title": "تأكيد الدفع",
30 | "payment_id": "رقم الدفع",
31 | "amount": "المبلغ",
32 | "seller": "البائع",
33 | "status": "الحالة",
34 | "date": "التاريخ",
35 | "escrow_status": "حالة الضمان",
36 | "buttons": {
37 | "close": "إغلاق",
38 | "cancel_payment": "إلغاء الدفع",
39 | "view_details": "عرض التفاصيل",
40 | "contact_seller": "تواصل مع البائع"
41 | },
42 | "messages": {
43 | "processing": "جاري معالجة الدفع...",
44 | "success": "تم الدفع بنجاح!",
45 | "failed": "فشل الدفع",
46 | "cancelled": "تم إلغاء الدفع",
47 | "pending": "الدفع قيد الانتظار"
48 | }
49 | },
50 | "history": {
51 | "title": "سجل المعاملات",
52 | "no_transactions": "لا توجد معاملات",
53 | "loading": "جاري تحميل المعاملات...",
54 | "table": {
55 | "date": "التاريخ",
56 | "payment_id": "رقم الدفع",
57 | "amount": "المبلغ",
58 | "type": "النوع",
59 | "status": "الحالة",
60 | "actions": "الإجراءات"
61 | },
62 | "filters": {
63 | "all": "الكل",
64 | "sent": "مرسل",
65 | "received": "مستلم",
66 | "pending": "قيد الانتظار",
67 | "completed": "مكتمل"
68 | },
69 | "pagination": {
70 | "rows_per_page": "عدد الصفوف في الصفحة:",
71 | "of": "من"
72 | }
73 | },
74 | "status": {
75 | "pending": "قيد الانتظار",
76 | "processing": "قيد المعالجة",
77 | "completed": "مكتمل",
78 | "failed": "فشل",
79 | "cancelled": "ملغي",
80 | "refunded": "مسترد",
81 | "escrow_held": "في الضمان",
82 | "escrow_released": "تم تحرير الضمان",
83 | "escrow_disputed": "قيد النزاع"
84 | }
85 | }
--------------------------------------------------------------------------------
/src/web/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": [
4 | "next/core-web-vitals",
5 | "plugin:@typescript-eslint/recommended",
6 | "plugin:react/recommended"
7 | ],
8 | "parser": "@typescript-eslint/parser",
9 | "parserOptions": {
10 | "ecmaVersion": 2022,
11 | "sourceType": "module",
12 | "ecmaFeatures": {
13 | "jsx": true
14 | },
15 | "project": "./tsconfig.json"
16 | },
17 | "plugins": [
18 | "@typescript-eslint",
19 | "react"
20 | ],
21 | "settings": {
22 | "react": {
23 | "version": "18.2"
24 | }
25 | },
26 | "rules": {
27 | // React specific rules
28 | "react/react-in-jsx-scope": "off",
29 | "react/prop-types": "off",
30 | "react/jsx-curly-brace-presence": ["error", { "props": "never", "children": "never" }],
31 | "react/jsx-no-duplicate-props": "error",
32 | "react/jsx-pascal-case": "error",
33 |
34 | // TypeScript specific rules
35 | "@typescript-eslint/explicit-function-return-type": "off",
36 | "@typescript-eslint/explicit-module-boundary-types": "off",
37 | "@typescript-eslint/no-explicit-any": "error",
38 | "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
39 | "@typescript-eslint/no-non-null-assertion": "error",
40 | "@typescript-eslint/consistent-type-imports": "error",
41 | "@typescript-eslint/no-floating-promises": "error",
42 |
43 | // General code quality rules
44 | "no-console": ["warn", { "allow": ["warn", "error"] }],
45 | "prefer-const": "error",
46 | "eqeqeq": ["error", "always"],
47 | "curly": ["error", "all"],
48 | "no-var": "error",
49 | "object-shorthand": ["error", "always"],
50 | "quotes": ["error", "single", { "avoidEscape": true }],
51 | "semi": ["error", "always"],
52 | "no-duplicate-imports": "error",
53 | "no-unused-expressions": "error",
54 | "no-shadow": "error",
55 | "no-return-await": "error",
56 | "no-throw-literal": "error",
57 |
58 | // Mobile-first and PWA specific rules
59 | "no-restricted-globals": ["error", "event"],
60 | "max-lines": ["warn", { "max": 300, "skipBlankLines": true, "skipComments": true }],
61 | "max-depth": ["error", 4],
62 | "complexity": ["warn", 15]
63 | },
64 | "env": {
65 | "browser": true,
66 | "es2022": true,
67 | "node": true,
68 | "jest": true
69 | },
70 | "globals": {
71 | "process": "readonly",
72 | "window": "readonly",
73 | "document": "readonly",
74 | "navigator": "readonly"
75 | },
76 | "ignorePatterns": [
77 | "node_modules/",
78 | ".next/",
79 | "out/",
80 | "public/",
81 | "**/*.test.ts",
82 | "**/*.test.tsx",
83 | "jest.config.ts",
84 | "next.config.js"
85 | ]
86 | }
--------------------------------------------------------------------------------
/infrastructure/kubernetes/autoscaling/hpa.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: autoscaling/v2
2 | kind: HorizontalPodAutoscaler
3 | metadata:
4 | name: api-gateway-hpa
5 | namespace: app
6 | labels:
7 | app: egyptian-map-pi
8 | component: api-gateway
9 | region: me-south-1
10 | spec:
11 | scaleTargetRef:
12 | apiVersion: apps/v1
13 | kind: Deployment
14 | name: api-gateway
15 | minReplicas: 2 # Minimum HA requirement
16 | maxReplicas: 10 # Maximum scaling for traffic spikes
17 | metrics:
18 | - type: Resource
19 | resource:
20 | name: cpu
21 | target:
22 | type: Utilization
23 | averageUtilization: 70 # Scale at 70% CPU utilization
24 | behavior:
25 | scaleUp:
26 | stabilizationWindowSeconds: 60 # 1-minute stabilization window
27 | policies:
28 | - type: Pods
29 | value: 2 # Add up to 2 pods at a time
30 | periodSeconds: 30
31 | ---
32 | apiVersion: autoscaling/v2
33 | kind: HorizontalPodAutoscaler
34 | metadata:
35 | name: marketplace-service-hpa
36 | namespace: app
37 | labels:
38 | app: egyptian-map-pi
39 | component: marketplace
40 | region: me-south-1
41 | spec:
42 | scaleTargetRef:
43 | apiVersion: apps/v1
44 | kind: Deployment
45 | name: marketplace-service
46 | minReplicas: 2 # Minimum HA requirement
47 | maxReplicas: 10 # Maximum scaling for search operations
48 | metrics:
49 | - type: Resource
50 | resource:
51 | name: cpu
52 | target:
53 | type: Utilization
54 | averageUtilization: 70 # Scale at 70% CPU utilization
55 | behavior:
56 | scaleUp:
57 | stabilizationWindowSeconds: 90 # 1.5-minute stabilization window
58 | policies:
59 | - type: Pods
60 | value: 2 # Add up to 2 pods at a time
61 | periodSeconds: 45
62 | ---
63 | apiVersion: autoscaling/v2
64 | kind: HorizontalPodAutoscaler
65 | metadata:
66 | name: messaging-service-hpa
67 | namespace: app
68 | labels:
69 | app: egyptian-map-pi
70 | component: messaging
71 | region: me-south-1
72 | spec:
73 | scaleTargetRef:
74 | apiVersion: apps/v1
75 | kind: Deployment
76 | name: messaging-service
77 | minReplicas: 2 # Minimum HA requirement
78 | maxReplicas: 8 # Maximum scaling for WebSocket connections
79 | metrics:
80 | - type: Resource
81 | resource:
82 | name: cpu
83 | target:
84 | type: Utilization
85 | averageUtilization: 70 # Scale at 70% CPU utilization
86 | behavior:
87 | scaleUp:
88 | stabilizationWindowSeconds: 120 # 2-minute stabilization window
89 | policies:
90 | - type: Pods
91 | value: 1 # Add 1 pod at a time for more controlled scaling
92 | periodSeconds: 60
--------------------------------------------------------------------------------
/src/web/src/constants/categories.ts:
--------------------------------------------------------------------------------
1 | // @mui/material/icons version: 5.14.0
2 | import LocalMallIcon from '@mui/material/icons/LocalMall';
3 | import DevicesIcon from '@mui/material/icons/Devices';
4 | import RestaurantIcon from '@mui/material/icons/Restaurant';
5 | import BuildIcon from '@mui/material/icons/Build';
6 | import MoreHorizIcon from '@mui/material/icons/MoreHoriz';
7 |
8 | /**
9 | * Interface defining a marketplace category with bilingual support
10 | * @property id - Unique identifier for the category
11 | * @property nameAr - Category name in Arabic
12 | * @property nameEn - Category name in English
13 | * @property icon - Material UI icon component for the category
14 | */
15 | export interface Category {
16 | id: string;
17 | nameAr: string;
18 | nameEn: string;
19 | icon: React.ComponentType;
20 | }
21 |
22 | /**
23 | * Predefined marketplace categories for the Egyptian Map of Pi
24 | * Includes bilingual names (Arabic/English) and Material UI icons
25 | * Categories are marked as readonly to prevent runtime modifications
26 | */
27 | export const CATEGORIES: readonly Category[] = [
28 | {
29 | id: 'FASHION',
30 | nameAr: 'الموضة والملابس',
31 | nameEn: 'Fashion & Clothing',
32 | icon: LocalMallIcon
33 | },
34 | {
35 | id: 'ELECTRONICS',
36 | nameAr: 'الإلكترونيات',
37 | nameEn: 'Electronics',
38 | icon: DevicesIcon
39 | },
40 | {
41 | id: 'FOOD',
42 | nameAr: 'الطعام والمشروبات',
43 | nameEn: 'Food & Beverages',
44 | icon: RestaurantIcon
45 | },
46 | {
47 | id: 'SERVICES',
48 | nameAr: 'الخدمات',
49 | nameEn: 'Services',
50 | icon: BuildIcon
51 | },
52 | {
53 | id: 'OTHER',
54 | nameAr: 'أخرى',
55 | nameEn: 'Other',
56 | icon: MoreHorizIcon
57 | }
58 | ] as const;
59 |
60 | /**
61 | * Type representing valid category IDs
62 | * Derived from the CATEGORIES array for type safety
63 | */
64 | export type CategoryId = typeof CATEGORIES[number]['id'];
65 |
66 | /**
67 | * Helper function to get a category by its ID
68 | * @param id - The category ID to look up
69 | * @returns The matching category or undefined if not found
70 | */
71 | export const getCategoryById = (id: CategoryId): Category | undefined => {
72 | return CATEGORIES.find(category => category.id === id);
73 | };
74 |
75 | /**
76 | * Helper function to get a category name in the specified language
77 | * @param id - The category ID
78 | * @param language - The desired language ('ar' or 'en')
79 | * @returns The category name in the specified language or undefined if category not found
80 | */
81 | export const getCategoryName = (id: CategoryId, language: 'ar' | 'en'): string | undefined => {
82 | const category = getCategoryById(id);
83 | if (!category) return undefined;
84 | return language === 'ar' ? category.nameAr : category.nameEn;
85 | };
86 |
87 | export default CATEGORIES;
--------------------------------------------------------------------------------
/src/web/public/locales/ar/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "chat": {
3 | "title": "الرسائل",
4 | "newMessage": "رسالة جديدة",
5 | "noMessages": "لا توجد رسائل",
6 | "loadMore": "تحميل المزيد",
7 | "typeMessage": "اكتب رسالتك...",
8 | "send": "إرسال",
9 | "attachImage": "إرفاق صورة",
10 | "today": "اليوم",
11 | "yesterday": "أمس",
12 | "online": "متصل",
13 | "offline": "غير متصل",
14 | "lastSeen": "آخر ظهور {{time}}",
15 | "searchPlaceholder": "البحث في الرسائل...",
16 | "archiveChat": "أرشفة المحادثة",
17 | "unarchiveChat": "إلغاء أرشفة المحادثة",
18 | "typing": "يكتب...",
19 | "recording": "يسجل رسالة صوتية..."
20 | },
21 | "status": {
22 | "sent": "تم الإرسال",
23 | "delivered": "تم التوصيل",
24 | "read": "تم القراءة",
25 | "failed": "فشل الإرسال",
26 | "pending": "جاري الإرسال",
27 | "uploading": "جاري الرفع...",
28 | "downloading": "جاري التحميل..."
29 | },
30 | "errors": {
31 | "sendFailed": "فشل إرسال الرسالة. يرجى المحاولة مرة أخرى",
32 | "loadFailed": "فشل تحميل الرسائل",
33 | "networkError": "خطأ في الشبكة",
34 | "invalidMessage": "رسالة غير صالحة",
35 | "unauthorized": "يرجى تسجيل الدخول للمحادثة",
36 | "blockedUser": "لا يمكنك إرسال رسائل لهذا المستخدم",
37 | "fileTooBig": "حجم الملف كبير جداً",
38 | "unsupportedFile": "نوع الملف غير مدعوم",
39 | "rateLimited": "يرجى الانتظار قبل إرسال المزيد من الرسائل"
40 | },
41 | "conversation": {
42 | "with": "محادثة مع {{name}}",
43 | "about": "حول {{item}}",
44 | "price": "السعر: {{amount}} Pi",
45 | "startChat": "بدء المحادثة",
46 | "block": "حظر المستخدم",
47 | "report": "الإبلاغ عن المحتوى",
48 | "delete": "حذف المحادثة",
49 | "confirmDelete": "هل أنت متأكد من رغبتك في حذف هذه المحادثة؟",
50 | "mute": "كتم الإشعارات",
51 | "unmute": "تفعيل الإشعارات",
52 | "pin": "تثبيت المحادثة",
53 | "unpin": "إلغاء تثبيت المحادثة",
54 | "markAsRead": "تحديد كمقروء",
55 | "markAsUnread": "تحديد كغير مقروء"
56 | },
57 | "notifications": {
58 | "newMessage": "رسالة جديدة من {{sender}}",
59 | "messageRequest": "طلب محادثة جديد",
60 | "accepted": "تم قبول طلب المحادثة",
61 | "declined": "تم رفض طلب المحادثة",
62 | "newOffer": "عرض جديد على {{item}}",
63 | "offerAccepted": "تم قبول عرضك",
64 | "offerDeclined": "تم رفض عرضك",
65 | "paymentReceived": "تم استلام الدفعة",
66 | "paymentSent": "تم إرسال الدفعة"
67 | },
68 | "media": {
69 | "photo": "صورة",
70 | "video": "فيديو",
71 | "audio": "تسجيل صوتي",
72 | "document": "مستند",
73 | "location": "الموقع",
74 | "contact": "جهة اتصال"
75 | },
76 | "actions": {
77 | "copy": "نسخ",
78 | "forward": "إعادة توجيه",
79 | "reply": "رد",
80 | "edit": "تعديل",
81 | "share": "مشاركة",
82 | "download": "تحميل",
83 | "cancel": "إلغاء",
84 | "confirm": "تأكيد"
85 | }
86 | }
--------------------------------------------------------------------------------
/src/web/src/interfaces/location.interface.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Location-related interfaces and types for the Egyptian Map of Pi
3 | * Defines core data structures for handling geographic locations within Egypt's boundaries
4 | * @version 1.0.0
5 | */
6 |
7 | /**
8 | * Geographic coordinates interface with validation for Egyptian boundaries
9 | * Latitude range: 22°N to 31.5°N
10 | * Longitude range: 25°E to 35°E
11 | */
12 | export interface Coordinates {
13 | /** Latitude in decimal degrees (22°N to 31.5°N) */
14 | latitude: number;
15 |
16 | /** Longitude in decimal degrees (25°E to 35°E) */
17 | longitude: number;
18 | }
19 |
20 | /**
21 | * Comprehensive Egyptian address structure with bilingual support
22 | * Includes both English and Arabic representations of address components
23 | */
24 | export interface Address {
25 | /** Street name in English */
26 | street: string;
27 |
28 | /** District/neighborhood name in English */
29 | district: string;
30 |
31 | /** City name in English */
32 | city: string;
33 |
34 | /** Governorate name in English */
35 | governorate: string;
36 |
37 | /** Egyptian postal code (5 digits) */
38 | postalCode: string;
39 |
40 | /** Street name in Arabic */
41 | streetNameAr: string;
42 |
43 | /** District/neighborhood name in Arabic */
44 | districtAr: string;
45 |
46 | /** City name in Arabic */
47 | cityAr: string;
48 |
49 | /** Governorate name in Arabic */
50 | governorateAr: string;
51 | }
52 |
53 | /**
54 | * Enumeration of location types in the Egyptian marketplace system
55 | * Defines different categories of locations for business logic
56 | */
57 | export enum LocationType {
58 | /** Physical retail store location */
59 | STORE = 'STORE',
60 |
61 | /** Designated pickup point for orders */
62 | PICKUP_POINT = 'PICKUP_POINT',
63 |
64 | /** Customer delivery address */
65 | DELIVERY_ADDRESS = 'DELIVERY_ADDRESS',
66 |
67 | /** Marketplace hub location */
68 | MARKETPLACE = 'MARKETPLACE',
69 |
70 | /** Service provider location */
71 | SERVICE_LOCATION = 'SERVICE_LOCATION'
72 | }
73 |
74 | /**
75 | * Complete location interface combining coordinates, address, and metadata
76 | * Core data structure for location-based features in the application
77 | */
78 | export interface Location {
79 | /** Unique identifier for the location */
80 | id: string;
81 |
82 | /** Geographic coordinates with Egyptian boundary validation */
83 | coordinates: Coordinates;
84 |
85 | /** Structured address information in both English and Arabic */
86 | address: Address;
87 |
88 | /** Category/type of the location */
89 | type: LocationType;
90 |
91 | /** Verification status of the location */
92 | isVerified: boolean;
93 |
94 | /** Timestamp of location creation */
95 | createdAt: Date;
96 |
97 | /** Timestamp of last location update */
98 | updatedAt: Date;
99 | }
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Requires core team review for any changes not covered by specific rules
2 | * @core-team
3 |
4 | # Backend service implementations
5 | src/backend/ @backend-team
6 |
7 | # Frontend web application code
8 | src/web/ @frontend-team
9 |
10 | # Authentication service - requires security team review
11 | src/backend/auth-service/ @security-team @backend-team
12 |
13 | # Payment service - requires security team review
14 | src/backend/payment-service/ @security-team @backend-team
15 |
16 | # Infrastructure and deployment configurations
17 | infrastructure/ @devops-team
18 |
19 | # Kubernetes security configurations - requires both security and devops review
20 | infrastructure/kubernetes/security/ @security-team @devops-team
21 |
22 | # CI/CD workflow configurations - requires security validation
23 | .github/workflows/ @devops-team @security-team
24 |
25 | # Shared validation utilities - requires security review
26 | src/backend/shared/validators/ @security-team @backend-team
27 |
28 | # Frontend validation implementations - requires security oversight
29 | src/web/src/validators/ @security-team @frontend-team
30 |
31 | # Test implementations including security testing
32 | src/**/tests/ @qa-team @security-team
33 |
34 | # Monitoring and security telemetry configurations
35 | infrastructure/kubernetes/monitoring/ @devops-team @sre-team @security-team
36 |
37 | # Security documentation and compliance requirements
38 | docs/security/ @security-team @core-team
39 |
40 | # Service configuration files requiring security review
41 | src/**/config/ @security-team @devops-team
42 |
43 | # Specific workflow files with enhanced security requirements
44 | .github/workflows/ci.yml @devops-team @security-team
45 | .github/workflows/cd.yml @devops-team @security-team
46 | .github/workflows/security-scan.yml @security-team @devops-team
47 |
48 | # Package dependencies and lock files
49 | package.json @security-team @devops-team
50 | package-lock.json @security-team @devops-team
51 | yarn.lock @security-team @devops-team
52 |
53 | # Database schema and migration files
54 | src/**/migrations/ @backend-team @security-team
55 | src/**/schemas/ @backend-team @security-team
56 |
57 | # API specifications and documentation
58 | api/ @backend-team @security-team
59 | docs/api/ @backend-team @security-team
60 |
61 | # Environment configurations
62 | .env.example @security-team @devops-team
63 | src/**/.env.example @security-team @devops-team
64 |
65 | # Security policy and compliance documentation
66 | SECURITY.md @security-team @core-team
67 | security-policy.md @security-team @core-team
68 |
69 | # Dependency security configurations
70 | .snyk @security-team
71 | .npmrc @security-team @devops-team
72 |
73 | # Container security configurations
74 | **/Dockerfile @security-team @devops-team
75 | docker-compose*.yml @security-team @devops-team
76 |
77 | # Load testing and performance configurations
78 | load-tests/ @qa-team @sre-team @security-team
79 | performance-tests/ @qa-team @sre-team @security-team
--------------------------------------------------------------------------------
/src/backend/payment-service/Dockerfile:
--------------------------------------------------------------------------------
1 | # Stage 1: Builder
2 | FROM node:18-alpine AS builder
3 |
4 | # Set environment variables
5 | ENV NODE_ENV=production
6 |
7 | # Install build essentials and security updates
8 | RUN apk update && \
9 | apk add --no-cache \
10 | python3 \
11 | make \
12 | g++ \
13 | git \
14 | && rm -rf /var/cache/apk/*
15 |
16 | # Set working directory
17 | WORKDIR /app
18 |
19 | # Copy package files with strict permissions
20 | COPY --chown=node:node package*.json ./
21 | COPY --chown=node:node tsconfig.json ./
22 |
23 | # Install dependencies with security audit
24 | RUN npm ci --only=production && \
25 | npm audit fix && \
26 | npm cache clean --force
27 |
28 | # Copy source code and config files
29 | COPY --chown=node:node . .
30 |
31 | # Verify source integrity and build TypeScript code
32 | RUN npm run build && \
33 | npm prune --production
34 |
35 | # Stage 2: Production
36 | FROM node:18-alpine
37 |
38 | # Set environment variables
39 | ENV NODE_ENV=production \
40 | PORT=3005 \
41 | LOG_LEVEL=info
42 |
43 | # Install security updates and essential packages
44 | RUN apk update && \
45 | apk add --no-cache \
46 | dumb-init \
47 | tini \
48 | && rm -rf /var/cache/apk/*
49 |
50 | # Create and set working directory with proper permissions
51 | WORKDIR /app
52 | RUN chown -R node:node /app
53 |
54 | # Copy built artifacts and dependencies from builder
55 | COPY --chown=node:node --from=builder /app/dist ./dist
56 | COPY --chown=node:node --from=builder /app/node_modules ./node_modules
57 | COPY --chown=node:node --from=builder /app/package*.json ./
58 |
59 | # Set strict file permissions
60 | RUN chmod -R 755 /app && \
61 | chmod -R 644 /app/dist/* && \
62 | chmod -R 644 /app/package*.json
63 |
64 | # Configure non-root user
65 | USER node
66 |
67 | # Set security policies
68 | RUN npm config set ignore-scripts true && \
69 | npm config set unsafe-perm false
70 |
71 | # Expose service port
72 | EXPOSE 3005
73 |
74 | # Configure health check
75 | HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
76 | CMD node dist/healthcheck.js || exit 1
77 |
78 | # Set startup command with init system
79 | ENTRYPOINT ["/sbin/tini", "--"]
80 | CMD ["node", "dist/index.js"]
81 |
82 | # Add metadata labels
83 | LABEL maintainer="Egyptian Map of Pi Team" \
84 | version="1.0.0" \
85 | description="Payment Service for Egyptian Map of Pi" \
86 | org.opencontainers.image.source="https://github.com/egyptian-map-of-pi/payment-service" \
87 | org.opencontainers.image.vendor="Egyptian Map of Pi" \
88 | org.opencontainers.image.title="Payment Service" \
89 | org.opencontainers.image.description="Secure Pi cryptocurrency payment processing service" \
90 | org.opencontainers.image.version="1.0.0" \
91 | org.opencontainers.image.created="2023-10-19" \
92 | security.capabilities="no-new-privileges=true"
93 |
94 | # Apply security options
95 | STOPSIGNAL SIGTERM
--------------------------------------------------------------------------------
/infrastructure/terraform/modules/cdn/variables.tf:
--------------------------------------------------------------------------------
1 | # Terraform variables definition file for CloudFront CDN module
2 | # Version: 1.0
3 | # Provider version compatibility: hashicorp/terraform ~> 1.0
4 |
5 | # Environment identifier variable with validation
6 | variable "environment" {
7 | type = string
8 | description = "Deployment environment identifier (prod, staging, dev) for resource naming and configuration"
9 |
10 | validation {
11 | condition = can(regex("^(prod|staging|dev)$", var.environment))
12 | error_message = "Environment must be one of: prod, staging, dev"
13 | }
14 | }
15 |
16 | # Project name variable
17 | variable "project_name" {
18 | type = string
19 | description = "Project identifier for resource naming and tagging conventions"
20 | default = "egyptian-map-of-pi"
21 | }
22 |
23 | # AWS region variable
24 | variable "region_name" {
25 | type = string
26 | description = "AWS region name for CDN configuration, defaulting to Middle East (Bahrain)"
27 | default = "me-south-1"
28 | }
29 |
30 | # S3 bucket domain name variable
31 | variable "bucket_domain_name" {
32 | type = string
33 | description = "Origin S3 bucket domain name for CDN content source configuration"
34 | }
35 |
36 | # S3 origin identifier variable
37 | variable "s3_origin_id" {
38 | type = string
39 | description = "Unique identifier for the S3 origin in CloudFront distribution"
40 | default = "S3-egyptian-map-of-pi"
41 | }
42 |
43 | # Cache TTL configurations
44 | variable "default_ttl" {
45 | type = number
46 | description = "Default Time-To-Live in seconds for cached objects"
47 | default = 3600 # 1 hour
48 | }
49 |
50 | variable "static_ttl" {
51 | type = number
52 | description = "Time-To-Live in seconds for static assets (CSS, JS, images)"
53 | default = 86400 # 24 hours
54 | }
55 |
56 | variable "media_ttl" {
57 | type = number
58 | description = "Time-To-Live in seconds for media files (user uploads)"
59 | default = 604800 # 7 days
60 | }
61 |
62 | variable "price_list_ttl" {
63 | type = number
64 | description = "Time-To-Live in seconds for price list and product data"
65 | default = 300 # 5 minutes
66 | }
67 |
68 | # Performance optimization configurations
69 | variable "enable_compression" {
70 | type = bool
71 | description = "Enable CloudFront compression for improved performance"
72 | default = true
73 | }
74 |
75 | # HTTP method configurations
76 | variable "allowed_methods" {
77 | type = list(string)
78 | description = "List of allowed HTTP methods"
79 | default = ["GET", "HEAD", "OPTIONS"]
80 | }
81 |
82 | # Resource tagging configurations
83 | variable "tags" {
84 | type = map(string)
85 | description = "Resource tags for cost allocation and management"
86 | default = {
87 | Project = "egyptian-map-of-pi"
88 | ManagedBy = "terraform"
89 | Environment = "var.environment"
90 | Region = "middle-east"
91 | Service = "cdn"
92 | }
93 | }
--------------------------------------------------------------------------------
/infrastructure/terraform/providers.tf:
--------------------------------------------------------------------------------
1 | # Version constraints for Terraform and required providers
2 | # version: ~> 4.0
3 | terraform {
4 | required_version = ">= 1.0.0"
5 |
6 | required_providers {
7 | aws = {
8 | source = "hashicorp/aws"
9 | version = "~> 4.0"
10 | }
11 | kubernetes = {
12 | source = "hashicorp/kubernetes"
13 | version = "~> 2.0"
14 | }
15 | helm = {
16 | source = "hashicorp/helm"
17 | version = "~> 2.0"
18 | }
19 | }
20 | }
21 |
22 | # Primary AWS provider configuration for main region (Bahrain)
23 | provider "aws" {
24 | region = var.aws_region
25 |
26 | # Common resource tags for all AWS resources
27 | default_tags {
28 | tags = {
29 | Environment = var.environment
30 | Project = "egyptian-map-of-pi"
31 | ManagedBy = "terraform"
32 | Region = var.aws_region
33 | }
34 | }
35 |
36 | # Assume role if specified for different AWS accounts
37 | dynamic "assume_role" {
38 | for_each = var.aws_assume_role_arn != null ? [1] : []
39 | content {
40 | role_arn = var.aws_assume_role_arn
41 | }
42 | }
43 | }
44 |
45 | # Secondary AWS provider for Disaster Recovery region (Milan)
46 | provider "aws" {
47 | alias = "dr"
48 | region = "eu-south-1"
49 |
50 | default_tags {
51 | tags = {
52 | Environment = "dr"
53 | Project = "egyptian-map-of-pi"
54 | ManagedBy = "terraform"
55 | Region = "eu-south-1"
56 | }
57 | }
58 | }
59 |
60 | # Kubernetes provider configuration for EKS cluster management
61 | provider "kubernetes" {
62 | host = module.eks.cluster_endpoint
63 | cluster_ca_certificate = base64decode(module.eks.cluster_ca_certificate)
64 | token = module.eks.cluster_token
65 |
66 | # AWS EKS authentication configuration
67 | exec {
68 | api_version = "client.authentication.k8s.io/v1beta1"
69 | command = "aws"
70 | args = [
71 | "eks",
72 | "get-token",
73 | "--cluster-name",
74 | "${var.project_name}-${var.environment}",
75 | "--region",
76 | var.aws_region
77 | ]
78 | }
79 | }
80 |
81 | # Helm provider configuration for Kubernetes package management
82 | provider "helm" {
83 | kubernetes {
84 | host = module.eks.cluster_endpoint
85 | cluster_ca_certificate = base64decode(module.eks.cluster_ca_certificate)
86 | token = module.eks.cluster_token
87 |
88 | exec {
89 | api_version = "client.authentication.k8s.io/v1beta1"
90 | command = "aws"
91 | args = [
92 | "eks",
93 | "get-token",
94 | "--cluster-name",
95 | "${var.project_name}-${var.environment}",
96 | "--region",
97 | var.aws_region
98 | ]
99 | }
100 | }
101 |
102 | # Helm chart repository configuration
103 | repository_config_path = "${path.module}/.helm/repositories.yaml"
104 | repository_cache = "${path.module}/.helm/cache"
105 | }
--------------------------------------------------------------------------------
/src/backend/messaging-service/src/interfaces/message.interface.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Defines comprehensive interfaces and types for the real-time messaging system
3 | * between buyers and sellers in the Egyptian Map of Pi marketplace. Includes message type
4 | * definitions, delivery status tracking, and MongoDB document structure with Arabic language support.
5 | */
6 |
7 | import { BaseDocument } from '../../shared/interfaces/base.interface';
8 |
9 | /**
10 | * Enum defining all possible message types supported in the messaging system.
11 | * Includes special types for location sharing and transaction updates.
12 | */
13 | export enum MessageType {
14 | /**
15 | * Standard text message
16 | */
17 | TEXT = 'TEXT',
18 |
19 | /**
20 | * Image/media message
21 | */
22 | IMAGE = 'IMAGE',
23 |
24 | /**
25 | * System-generated notification or alert
26 | */
27 | SYSTEM = 'SYSTEM',
28 |
29 | /**
30 | * Location sharing message with coordinates
31 | */
32 | LOCATION = 'LOCATION',
33 |
34 | /**
35 | * Transaction-related update or status change
36 | */
37 | TRANSACTION = 'TRANSACTION'
38 | }
39 |
40 | /**
41 | * Enum tracking the delivery and read status of messages.
42 | * Includes comprehensive state management including failure handling.
43 | */
44 | export enum MessageStatus {
45 | /**
46 | * Message has been sent but not yet delivered
47 | */
48 | SENT = 'SENT',
49 |
50 | /**
51 | * Message has been delivered to recipient
52 | */
53 | DELIVERED = 'DELIVERED',
54 |
55 | /**
56 | * Message has been read by recipient
57 | */
58 | READ = 'READ',
59 |
60 | /**
61 | * Message delivery failed
62 | */
63 | FAILED = 'FAILED'
64 | }
65 |
66 | /**
67 | * Interface defining the complete structure of message documents in MongoDB.
68 | * Extends BaseDocument to inherit standard document properties.
69 | * Includes support for Arabic content and rich metadata.
70 | */
71 | export interface MessageDocument extends BaseDocument {
72 | /**
73 | * Reference to the transaction this message belongs to
74 | */
75 | transactionId: string;
76 |
77 | /**
78 | * ID of the user who sent the message
79 | */
80 | senderId: string;
81 |
82 | /**
83 | * ID of the message recipient
84 | */
85 | receiverId: string;
86 |
87 | /**
88 | * Primary message content in English
89 | */
90 | content: string;
91 |
92 | /**
93 | * Arabic translation of the message content
94 | * Required for proper Arabic language support
95 | */
96 | contentAr: string;
97 |
98 | /**
99 | * Type of message for proper rendering and handling
100 | */
101 | type: MessageType;
102 |
103 | /**
104 | * Current delivery status of the message
105 | */
106 | status: MessageStatus;
107 |
108 | /**
109 | * Additional metadata based on message type:
110 | * - LOCATION: coordinates, address
111 | * - IMAGE: dimensions, size, URL
112 | * - TRANSACTION: status, amount, etc.
113 | */
114 | metadata: Record;
115 | }
--------------------------------------------------------------------------------
/src/web/src/pages/categories/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview Categories index page component for Egyptian Map of Pi marketplace
3 | * @version 1.0.0
4 | *
5 | * Implements a responsive, bilingual category browsing interface with RTL support,
6 | * accessibility features, and mobile-first design.
7 | */
8 |
9 | import React, { useCallback, useState } from 'react';
10 | import { useRouter } from 'next/router';
11 | import { Container, useMediaQuery } from '@mui/material';
12 | import { useTheme } from '@mui/material/styles';
13 |
14 | import MainLayout from '../../components/layout/MainLayout';
15 | import CategoryGrid from '../../components/listing/CategoryGrid';
16 | import ErrorBoundary from '../../components/common/ErrorBoundary';
17 | import { useListings } from '../../hooks/useListings';
18 |
19 | /**
20 | * Categories page component with enhanced Egyptian market features
21 | * Implements mobile-first design and bilingual support
22 | */
23 | const CategoriesPage: React.FC = () => {
24 | // Hooks initialization
25 | const router = useRouter();
26 | const theme = useTheme();
27 | const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
28 | const { setFilter, isLoading } = useListings();
29 |
30 | // Local state for navigation
31 | const [isNavigating, setIsNavigating] = useState(false);
32 |
33 | /**
34 | * Handles category selection and navigation with loading state
35 | * @param categoryId - Selected category identifier
36 | */
37 | const handleCategoryClick = useCallback(async (categoryId: string) => {
38 | try {
39 | setIsNavigating(true);
40 |
41 | // Update listings filter with selected category
42 | setFilter({ category: categoryId });
43 |
44 | // Preserve existing query parameters
45 | const query = {
46 | ...router.query,
47 | category: categoryId
48 | };
49 |
50 | // Navigate to listings page with category filter
51 | await router.push({
52 | pathname: '/listings',
53 | query
54 | }, undefined, {
55 | shallow: true,
56 | locale: router.locale
57 | });
58 |
59 | } catch (error) {
60 | console.error('Navigation error:', error);
61 | } finally {
62 | setIsNavigating(false);
63 | }
64 | }, [router, setFilter]);
65 |
66 | return (
67 |
68 |
69 |
80 |
85 |
86 |
87 |
88 | );
89 | };
90 |
91 | // Display name for debugging
92 | CategoriesPage.displayName = 'CategoriesPage';
93 |
94 | export default CategoriesPage;
--------------------------------------------------------------------------------
/src/backend/auth-service/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@egyptian-map-pi/auth-service",
3 | "version": "1.0.0",
4 | "description": "Authentication service for Egyptian Map of Pi platform",
5 | "main": "dist/index.js",
6 | "private": true,
7 | "engines": {
8 | "node": ">=18.0.0",
9 | "npm": ">=9.8.0"
10 | },
11 | "scripts": {
12 | "build": "rimraf dist && tsc -p tsconfig.json",
13 | "start": "node dist/index.js",
14 | "dev": "nodemon --exec ts-node src/index.ts",
15 | "test": "jest --coverage",
16 | "lint": "eslint . --ext .ts",
17 | "clean": "rimraf dist coverage",
18 | "security-check": "npm audit",
19 | "validate": "tsc --noEmit"
20 | },
21 | "dependencies": {
22 | "@egyptian-map-pi/shared": "^1.0.0",
23 | "@nestjs/cache-manager": "^2.0.0",
24 | "@nestjs/common": "^10.0.0",
25 | "@nestjs/core": "^10.0.0",
26 | "@nestjs/swagger": "^7.0.0",
27 | "@pinetwork-js/sdk": "^2.0.0",
28 | "@socket.io/redis-adapter": "8.2.1",
29 | "axios": "^1.5.0",
30 | "bcryptjs": "^2.4.3",
31 | "class-transformer": "^0.5.1",
32 | "class-validator": "^0.14.0",
33 | "compression": "^1.7.4",
34 | "cors": "^2.8.5",
35 | "dayjs": "^1.11.9",
36 | "dotenv": "^16.3.1",
37 | "express": "4.18.2",
38 | "express-rate-limit": "^6.7.0",
39 | "express-validator": "^7.0.0",
40 | "firebase-admin": "11.0.0",
41 | "geoip-lite": "1.4.7",
42 | "helmet": "^7.0.0",
43 | "http-proxy-middleware": "2.0.6",
44 | "i18next": "^23.5.0",
45 | "inversify": "^6.0.0",
46 | "inversify-express-utils": "^6.4.3",
47 | "ioredis": "5.3.2",
48 | "joi": "^17.9.2",
49 | "jsonwebtoken": "^9.0.1",
50 | "moment-timezone": "^0.5.43",
51 | "mongodb-encryption": "^2.0.0",
52 | "mongoose": "^7.4.1",
53 | "mongoose-field-encryption": "^4.0.0",
54 | "morgan": "^1.10.0",
55 | "node-cache": "5.1.2",
56 | "pi-backend": "^1.0.0",
57 | "pino": "8.14.1",
58 | "rate-limiter-flexible": "^2.4.1",
59 | "redis": "^4.6.7",
60 | "reflect-metadata": "0.1.13",
61 | "sanitize-html": "^2.11.0",
62 | "socket.io": "^4.7.0",
63 | "uuid": "9.0.0",
64 | "validator": "13.9.0",
65 | "winston": "^3.10.0",
66 | "winston-daily-rotate-file": "4.7.1"
67 | },
68 | "devDependencies": {
69 | "@jest/globals": "^29.6.2",
70 | "@types/express": "^4.17.17",
71 | "@types/jest": "29.5.3",
72 | "@types/mongodb": "^4.0.7",
73 | "@types/mongoose": "5.11.97",
74 | "@types/node": "^18.0.0",
75 | "@typescript-eslint/eslint-plugin": "6.2.1",
76 | "@typescript-eslint/parser": "6.2.1",
77 | "axios-mock-adapter": "^1.21.0",
78 | "eslint": "8.46.0",
79 | "eslint-config-prettier": "8.10.0",
80 | "eslint-plugin-import": "2.28.1",
81 | "eslint-plugin-jest": "27.2.3",
82 | "jest": "^29.0.0",
83 | "jest-mock": "^29.0.0",
84 | "mongodb-memory-server": "^8.0.0",
85 | "nock": "^13.0.0",
86 | "nodemon": "3.0.1",
87 | "prettier": "^3.0.0",
88 | "rimraf": "5.0.1",
89 | "supertest": "^6.3.3",
90 | "ts-jest": "29.1.1",
91 | "ts-node": "10.9.1",
92 | "typescript": "5.1.6"
93 | }
94 | }
--------------------------------------------------------------------------------
/src/backend/messaging-service/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@egyptian-map-pi/messaging-service",
3 | "version": "1.0.0",
4 | "private": true,
5 | "engines": {
6 | "node": ">=18.0.0"
7 | },
8 | "scripts": {
9 | "build": "tsc -p tsconfig.json",
10 | "start": "node dist/cluster.js",
11 | "dev": "nodemon --exec ts-node src/app.ts",
12 | "test": "jest --watch",
13 | "test:coverage": "jest --coverage --coverageThreshold=80",
14 | "lint": "eslint 'src/**/*.ts'",
15 | "lint:fix": "eslint 'src/**/*.ts' --fix",
16 | "clean": "rimraf dist logs",
17 | "docker:build": "docker build -t messaging-service .",
18 | "docker:push": "docker push messaging-service"
19 | },
20 | "dependencies": {
21 | "@egyptian-map-pi/shared": "^1.0.0",
22 | "@nestjs/cache-manager": "^2.0.0",
23 | "@nestjs/common": "^10.0.0",
24 | "@nestjs/core": "^10.0.0",
25 | "@nestjs/swagger": "^7.0.0",
26 | "@pinetwork-js/sdk": "^2.0.0",
27 | "@socket.io/redis-adapter": "8.2.1",
28 | "axios": "^1.5.0",
29 | "bcryptjs": "^2.4.3",
30 | "class-transformer": "^0.5.1",
31 | "class-validator": "^0.14.0",
32 | "compression": "^1.7.4",
33 | "cors": "^2.8.5",
34 | "dayjs": "^1.11.9",
35 | "dotenv": "^16.3.1",
36 | "express": "4.18.2",
37 | "express-rate-limit": "^6.7.0",
38 | "express-validator": "^7.0.0",
39 | "firebase-admin": "11.0.0",
40 | "geoip-lite": "1.4.7",
41 | "helmet": "^7.0.0",
42 | "http-proxy-middleware": "2.0.6",
43 | "i18next": "^23.5.0",
44 | "inversify": "^6.0.0",
45 | "inversify-express-utils": "^6.4.3",
46 | "ioredis": "5.3.2",
47 | "joi": "^17.9.2",
48 | "jsonwebtoken": "^9.0.1",
49 | "mongoose": "^7.4.1",
50 | "mongoose-field-encryption": "^4.0.0",
51 | "morgan": "^1.10.0",
52 | "node-cache": "5.1.2",
53 | "rate-limiter-flexible": "^2.4.1",
54 | "redis": "^4.6.7",
55 | "reflect-metadata": "0.1.13",
56 | "sanitize-html": "^2.11.0",
57 | "socket.io": "^4.7.0",
58 | "socket.io-client": "^4.7.0",
59 | "uuid": "9.0.0",
60 | "validator": "13.9.0",
61 | "winston": "^3.10.0",
62 | "winston-daily-rotate-file": "4.7.1"
63 | },
64 | "devDependencies": {
65 | "@jest/globals": "^29.6.2",
66 | "@types/express": "^4.17.17",
67 | "@types/jest": "29.5.3",
68 | "@types/mongodb": "^4.0.7",
69 | "@types/mongoose": "5.11.97",
70 | "@types/node": "^18.0.0",
71 | "@typescript-eslint/eslint-plugin": "6.2.1",
72 | "@typescript-eslint/parser": "6.2.1",
73 | "axios-mock-adapter": "^1.21.0",
74 | "eslint": "8.46.0",
75 | "eslint-config-prettier": "8.10.0",
76 | "eslint-plugin-import": "2.28.1",
77 | "eslint-plugin-jest": "27.2.3",
78 | "jest": "^29.0.0",
79 | "jest-mock": "^29.0.0",
80 | "lerna": "7.1.4",
81 | "mongodb-memory-server": "^8.0.0",
82 | "nock": "^13.0.0",
83 | "nodemon": "3.0.1",
84 | "prettier": "^3.0.0",
85 | "rimraf": "5.0.1",
86 | "supertest": "^6.3.3",
87 | "ts-jest": "29.1.1",
88 | "ts-node": "10.9.1",
89 | "typescript": "5.1.6"
90 | },
91 | "author": "Egyptian Map of Pi Team",
92 | "license": "MIT"
93 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Create a standardized bug report for the Egyptian Map of Pi application
4 | title: "[Bug] : "
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | ## Bug Description
13 |
14 | ### Current Behavior
15 | **English:**
16 | [Describe what is currently happening]
17 |
18 | **Arabic:**
19 | [وصف ما يحدث حاليا]
20 |
21 | ### Expected Behavior
22 | **English:**
23 | [Describe what should happen]
24 |
25 | **Arabic:**
26 | [وصف ما يجب أن يحدث]
27 |
28 | ### Steps to Reproduce
29 | **English:**
30 | 1. [First Step]
31 | 2. [Second Step]
32 | 3. [Third Step]
33 |
34 | **Arabic:**
35 | 1. [الخطوة الأولى]
36 | 2. [الخطوة الثانية]
37 | 3. [الخطوة الثالثة]
38 |
39 | ## Pi Network Details
40 | - Pi SDK Version: [e.g., 2.0.0]
41 | - Wallet Integration Status: [Connected/Disconnected]
42 | - Transaction Type: [e.g., Payment/Escrow]
43 | - Network Mode: [Testnet/Mainnet]
44 | - Pioneer Authentication Status: [Authenticated/Not Authenticated]
45 |
46 | ## Egyptian Market Context
47 | - Governorate Location: [e.g., Cairo, Alexandria]
48 | - Language Preference: [Arabic/English/Both]
49 | - Local Payment Method: [Pi Wallet]
50 | - Merchant Category: [e.g., Retail, Services]
51 | - Regulatory Compliance Impact: [Yes/No - Explain if Yes]
52 |
53 | ## Technical Environment
54 | - Browser/Device: [e.g., Pi Browser v2.0, iPhone 13]
55 | - Operating System: [e.g., iOS 15.0, Android 12]
56 | - App Version: [e.g., 1.2.0]
57 | - Network Conditions: [e.g., 4G, Wifi]
58 | - Location Services Status: [Enabled/Disabled]
59 |
60 | ## Impact Assessment
61 |
62 | ### User Impact
63 | **English:**
64 | [Describe how this affects users]
65 |
66 | **Arabic:**
67 | [وصف كيف يؤثر هذا على المستخدمين]
68 |
69 | ### Security Impact Level
70 | - Level: [Select: critical/high/medium/low]
71 | - Details: [Explain security implications]
72 |
73 | ### Performance Metrics Impact
74 | - Page Load Time: [Affected/Not Affected - Include metrics]
75 | - API Response Time: [Affected/Not Affected - Include metrics]
76 | - Transaction Speed: [Affected/Not Affected - Include metrics]
77 |
78 | ### Data Integrity Status
79 | - User Data: [Affected/Not Affected]
80 | - Transaction Records: [Affected/Not Affected]
81 | - Location Data: [Affected/Not Affected]
82 |
83 | ### Transaction Security Status
84 | - Pi Wallet Operations: [Affected/Not Affected]
85 | - Payment Processing: [Affected/Not Affected]
86 | - Escrow System: [Affected/Not Affected]
87 |
88 | ## Additional Information
89 |
90 |
91 | ---
92 |
93 |
94 | - [ ] Bug description provided in both English and Arabic
95 | - [ ] Pi Network integration details are complete
96 | - [ ] Egyptian market context is properly documented
97 | - [ ] Security impact has been assessed
98 | - [ ] Performance metrics have been documented
99 | - [ ] Steps to reproduce are clear and detailed in both languages
100 |
--------------------------------------------------------------------------------
/src/backend/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | **/node_modules
3 | npm-debug.log
4 | yarn-debug.log
5 | yarn-error.log
6 |
7 | # Build outputs
8 | dist
9 | **/dist
10 | build
11 | **/build
12 | *.tsbuildinfo
13 |
14 | # Development and test files
15 | **/*.test.js
16 | **/*.spec.js
17 | **/__tests__
18 | **/coverage
19 | .nyc_output
20 |
21 | # Version control
22 | .git
23 | .gitignore
24 | .gitattributes
25 |
26 | # IDE and editor files
27 | .idea
28 | .vscode
29 | *.swp
30 | *.swo
31 | .DS_Store
32 | Thumbs.db
33 |
34 | # Environment and configuration files
35 | .env*
36 | .env.local
37 | .env.development
38 | .env.test
39 | .env.production
40 | **/.env*
41 | **/config/secrets*
42 |
43 | # Documentation and markdown files
44 | *.md
45 | docs
46 | **/docs
47 | CHANGELOG
48 | LICENSE
49 |
50 | # Service-specific exclusions
51 | # API Gateway
52 | src/backend/api-gateway/dist
53 | src/backend/api-gateway/node_modules
54 | src/backend/api-gateway/logs
55 | src/backend/api-gateway/coverage
56 | src/backend/api-gateway/tmp
57 |
58 | # Auth Service
59 | src/backend/auth-service/dist
60 | src/backend/auth-service/node_modules
61 | src/backend/auth-service/keys
62 | src/backend/auth-service/certificates
63 | src/backend/auth-service/secrets
64 | src/backend/auth-service/logs
65 |
66 | # Marketplace Service
67 | src/backend/marketplace-service/dist
68 | src/backend/marketplace-service/node_modules
69 | src/backend/marketplace-service/uploads
70 | src/backend/marketplace-service/temp
71 | src/backend/marketplace-service/logs
72 |
73 | # Location Service
74 | src/backend/location-service/dist
75 | src/backend/location-service/node_modules
76 | src/backend/location-service/cache
77 | src/backend/location-service/logs
78 |
79 | # Payment Service
80 | src/backend/payment-service/dist
81 | src/backend/payment-service/node_modules
82 | src/backend/payment-service/keys
83 | src/backend/payment-service/logs
84 |
85 | # Messaging Service
86 | src/backend/messaging-service/dist
87 | src/backend/messaging-service/node_modules
88 | src/backend/messaging-service/uploads
89 | src/backend/messaging-service/logs
90 |
91 | # Log files
92 | **/*.log
93 | logs
94 | **/logs
95 | log
96 | **/log
97 |
98 | # Temporary files
99 | tmp
100 | **/tmp
101 | temp
102 | **/temp
103 | *.tmp
104 | *.temp
105 |
106 | # Docker related
107 | Dockerfile*
108 | docker-compose*.yml
109 | .docker
110 |
111 | # Debug files
112 | **/*.debug
113 | **/*.dump
114 |
115 | # Backup files
116 | **/*.bak
117 | **/*.backup
118 | **/backup
119 | **/*~
120 |
121 | # System files
122 | **/.DS_Store
123 | **/Thumbs.db
124 |
125 | # Package files (let npm/yarn install handle dependencies)
126 | package-lock.json
127 | **/package-lock.json
128 | yarn.lock
129 | **/yarn.lock
130 |
131 | # Test files and fixtures
132 | **/__mocks__
133 | **/test
134 | **/tests
135 | **/*.test.*
136 | **/*.spec.*
137 | **/fixtures
138 | **/mock*
139 |
140 | # Miscellaneous
141 | .npmrc
142 | .yarnrc
143 | .editorconfig
144 | .prettierrc
145 | .eslintrc
146 | .eslintignore
147 | .babelrc
148 | tsconfig.json
149 | **/tsconfig.json
150 | jest.config.js
151 | **/jest.config.js
--------------------------------------------------------------------------------
/infrastructure/terraform/modules/eks/outputs.tf:
--------------------------------------------------------------------------------
1 | # Core cluster information
2 | output "cluster_id" {
3 | description = "The name/id of the EKS cluster for the Egyptian Map of Pi platform"
4 | value = aws_eks_cluster.main.id
5 | }
6 |
7 | output "cluster_endpoint" {
8 | description = "The endpoint URL for the Kubernetes API server"
9 | value = aws_eks_cluster.main.endpoint
10 | }
11 |
12 | output "cluster_certificate_authority_data" {
13 | description = "Base64 encoded certificate data required to communicate with the cluster"
14 | value = aws_eks_cluster.main.certificate_authority[0].data
15 | sensitive = true
16 | }
17 |
18 | output "cluster_version" {
19 | description = "The Kubernetes version running on the EKS cluster"
20 | value = aws_eks_cluster.main.version
21 | }
22 |
23 | # Node group information
24 | output "node_group_id" {
25 | description = "EKS node group identifier"
26 | value = aws_eks_node_group.main.id
27 | }
28 |
29 | output "node_group_status" {
30 | description = "Status of the EKS node group"
31 | value = aws_eks_node_group.main.status
32 | }
33 |
34 | output "node_group_resources" {
35 | description = "List of objects containing information about underlying resources of the node group"
36 | value = aws_eks_node_group.main.resources
37 | }
38 |
39 | # Security and networking
40 | output "cluster_security_group_id" {
41 | description = "Security group ID attached to the EKS cluster control plane"
42 | value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
43 | }
44 |
45 | output "cluster_oidc_issuer_url" {
46 | description = "The URL on the EKS cluster for the OpenID Connect identity provider"
47 | value = aws_eks_cluster.main.identity[0].oidc[0].issuer
48 | }
49 |
50 | output "cluster_vpc_config" {
51 | description = "VPC configuration for the EKS cluster"
52 | value = {
53 | vpc_id = aws_eks_cluster.main.vpc_config[0].vpc_id
54 | subnet_ids = aws_eks_cluster.main.vpc_config[0].subnet_ids
55 | security_group_ids = aws_eks_cluster.main.vpc_config[0].security_group_ids
56 | }
57 | }
58 |
59 | # Monitoring and logging
60 | output "cluster_logging_enabled_types" {
61 | description = "List of enabled control plane logging types"
62 | value = aws_eks_cluster.main.enabled_cluster_log_types
63 | }
64 |
65 | output "node_group_scaling_config" {
66 | description = "Current scaling configuration of the node group"
67 | value = {
68 | desired_size = aws_eks_node_group.main.scaling_config[0].desired_size
69 | max_size = aws_eks_node_group.main.scaling_config[0].max_size
70 | min_size = aws_eks_node_group.main.scaling_config[0].min_size
71 | }
72 | }
73 |
74 | # Tags
75 | output "cluster_tags" {
76 | description = "Tags applied to the EKS cluster"
77 | value = aws_eks_cluster.main.tags
78 | }
79 |
80 | # Platform-specific outputs
81 | output "platform_info" {
82 | description = "Egyptian Map of Pi platform-specific cluster information"
83 | value = {
84 | platform_name = "egyptian-map-of-pi"
85 | region = "me-south-1" # AWS Bahrain region
86 | environment = "production"
87 | kubernetes_version = aws_eks_cluster.main.version
88 | }
89 | }
--------------------------------------------------------------------------------
/src/backend/Dockerfile:
--------------------------------------------------------------------------------
1 | # -----------------------------
2 | # Stage 1: Builder
3 | # -----------------------------
4 | FROM node:18-alpine AS builder
5 |
6 | # Install build essentials
7 | RUN apk add --no-cache \
8 | python3 \
9 | make \
10 | g++ \
11 | dumb-init@~1.2.5
12 |
13 | # Set working directory
14 | WORKDIR /app
15 |
16 | # Copy package files for dependency installation
17 | COPY package*.json yarn.lock lerna.json ./
18 | COPY api-gateway/package.json ./api-gateway/
19 | COPY auth-service/package.json ./auth-service/
20 | COPY marketplace-service/package.json ./marketplace-service/
21 | COPY payment-service/package.json ./payment-service/
22 | COPY location-service/package.json ./location-service/
23 | COPY messaging-service/package.json ./messaging-service/
24 | COPY shared/package.json ./shared/
25 |
26 | # Install dependencies with yarn workspaces
27 | RUN yarn install --frozen-lockfile --network-timeout 600000
28 |
29 | # Copy source code and configs
30 | COPY . .
31 |
32 | # Build TypeScript code
33 | RUN yarn build
34 |
35 | # Prune dev dependencies and clean up
36 | RUN yarn install --production --ignore-scripts --prefer-offline \
37 | && yarn cache clean \
38 | && find . -name "*.map" -type f -delete \
39 | && find . -name "*.test.*" -type f -delete \
40 | && find . -name "__tests__" -type d -exec rm -rf {} + 2>/dev/null || true
41 |
42 | # -----------------------------
43 | # Stage 2: Production
44 | # -----------------------------
45 | FROM node:18-alpine
46 |
47 | # Install production essentials
48 | RUN apk add --no-cache \
49 | dumb-init@~1.2.5 \
50 | curl \
51 | && addgroup -g 1001 -S nodejs \
52 | && adduser -S nodejs -u 1001 -G nodejs
53 |
54 | # Set working directory
55 | WORKDIR /app
56 |
57 | # Copy built artifacts and production dependencies
58 | COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
59 | COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
60 | COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
61 | COPY --from=builder --chown=nodejs:nodejs /app/yarn.lock ./
62 |
63 | # Set secure permissions
64 | RUN chmod 755 /app \
65 | && chown -R nodejs:nodejs /app
66 |
67 | # Configure environment
68 | ENV NODE_ENV=production \
69 | PORT=3000 \
70 | NODE_OPTIONS="--max-old-space-size=2048" \
71 | TZ=Africa/Cairo
72 |
73 | # Expose service ports
74 | EXPOSE 3000 4001 4002 4003 4004 4005
75 |
76 | # Health check configuration
77 | HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
78 | CMD curl -f http://localhost:3000/health || exit 1
79 |
80 | # Set security configurations
81 | USER nodejs
82 | RUN mkdir -p /app/logs && chown -R nodejs:nodejs /app/logs
83 |
84 | # Set container metadata
85 | LABEL maintainer="Egyptian Map of Pi Team" \
86 | version="1.0.0" \
87 | description="Egyptian Map of Pi Backend Services" \
88 | security.capabilities="drop-all" \
89 | org.opencontainers.image.source="https://github.com/egyptian-map-pi/backend"
90 |
91 | # Use dumb-init as entrypoint for proper signal handling
92 | ENTRYPOINT ["/usr/bin/dumb-init", "--"]
93 |
94 | # Start the application with production optimizations
95 | CMD ["node", "--enable-source-maps", "dist/api-gateway/src/main.js"]
--------------------------------------------------------------------------------
/src/backend/.env.example:
--------------------------------------------------------------------------------
1 | # ==================================
2 | # Server Configuration
3 | # ==================================
4 | # Application environment (development/staging/production)
5 | NODE_ENV=development
6 | # Server port number for the microservice
7 | PORT=3000
8 | # Base URL for API endpoints in the current environment
9 | API_BASE_URL=http://localhost:3000
10 | # Name of the microservice for logging and monitoring
11 | SERVICE_NAME=auth-service
12 |
13 | # ==================================
14 | # Database Configuration
15 | # ==================================
16 | # MongoDB connection string with authentication
17 | MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/egyptian-map-of-pi?retryWrites=true&w=majority
18 | # MongoDB replica set name for high availability
19 | MONGODB_REPLICA_SET=rs0
20 | # Redis connection string for caching and session management
21 | REDIS_URL=redis://user:pass@localhost:6379/0
22 | # Enable Redis cluster mode for high availability
23 | REDIS_CLUSTER_MODE=true
24 |
25 | # ==================================
26 | # Authentication
27 | # ==================================
28 | # Secret key for JWT token generation and validation (min 32 characters)
29 | JWT_SECRET=your-secure-jwt-secret-key-min-32-chars
30 | # JWT access token expiration in seconds (1 hour)
31 | JWT_ACCESS_EXPIRATION=3600
32 | # JWT refresh token expiration in seconds (24 hours)
33 | JWT_REFRESH_EXPIRATION=86400
34 | # Algorithm used for JWT signing
35 | JWT_ALGORITHM=HS256
36 |
37 | # ==================================
38 | # Pi Network Integration
39 | # ==================================
40 | # Pi Network API key for authentication
41 | PI_API_KEY=your-pi-network-api-key
42 | # Pi Network API endpoint for the current environment
43 | PI_NETWORK_API_URL=https://api.minepi.com/v2
44 | # Enable Pi Network sandbox mode for testing
45 | PI_SANDBOX_MODE=true
46 | # Secret for validating Pi Network webhooks
47 | PI_WEBHOOK_SECRET=your-pi-webhook-secret
48 |
49 | # ==================================
50 | # Storage Configuration
51 | # ==================================
52 | # S3 bucket name for file storage
53 | AWS_S3_BUCKET=egyptian-map-of-pi-uploads
54 | # AWS region for S3 bucket (Bahrain for Egyptian compliance)
55 | AWS_REGION=me-south-1
56 | # AWS access key ID for S3 access
57 | AWS_ACCESS_KEY_ID=your-aws-access-key
58 | # AWS secret access key for S3 access
59 | AWS_SECRET_ACCESS_KEY=your-aws-secret-key
60 | # CloudFront CDN domain for serving static assets
61 | CDN_DOMAIN=cdn.egyptian-map-of-pi.com
62 |
63 | # ==================================
64 | # CORS Configuration
65 | # ==================================
66 | # Comma-separated list of allowed CORS origins
67 | ALLOWED_ORIGINS=https://egyptian-map-of-pi.com,https://staging.egyptian-map-of-pi.com
68 | # CORS preflight cache duration in seconds (2 hours)
69 | CORS_MAX_AGE=7200
70 |
71 | # ==================================
72 | # Logging and Monitoring
73 | # ==================================
74 | # Application logging level (debug/info/warn/error)
75 | LOG_LEVEL=info
76 | # Sentry error tracking DSN (optional)
77 | SENTRY_DSN=https://your-sentry-dsn
78 | # Enable detailed request logging
79 | ENABLE_REQUEST_LOGGING=true
80 | # Enable performance metric collection
81 | ENABLE_PERFORMANCE_MONITORING=true
--------------------------------------------------------------------------------
/src/backend/api-gateway/src/config/cors.config.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview CORS configuration for the Egyptian Map of Pi API Gateway
3 | * Implements strict security policies and domain restrictions while ensuring
4 | * compliance with Egyptian regulatory requirements.
5 | *
6 | * @version 1.0.0
7 | * @license MIT
8 | */
9 |
10 | import { CorsConfig } from '../../shared/interfaces/config.interface';
11 |
12 | /**
13 | * Production domain whitelist
14 | * Strictly controlled list of allowed origins for enhanced security
15 | */
16 | const PRODUCTION_DOMAINS = [
17 | 'https://egyptian-map-of-pi.com',
18 | 'https://*.egyptian-map-of-pi.com', // Subdomains for merchant portals
19 | 'https://staging.egyptian-map-of-pi.com'
20 | ] as const;
21 |
22 | /**
23 | * Development domains for local testing
24 | * Only enabled in non-production environments
25 | */
26 | const DEVELOPMENT_DOMAINS = [
27 | 'http://localhost:3000'
28 | ] as const;
29 |
30 | /**
31 | * Required security headers for Egyptian regulatory compliance
32 | * Implements security framework requirements for cross-origin requests
33 | */
34 | const SECURITY_HEADERS = [
35 | 'Content-Type',
36 | 'Authorization',
37 | 'X-Requested-With',
38 | 'Accept',
39 | 'Origin',
40 | 'Access-Control-Allow-Headers',
41 | 'Access-Control-Request-Method',
42 | 'Access-Control-Request-Headers',
43 | 'X-Pi-Network-Auth' // Custom header for Pi Network authentication
44 | ] as const;
45 |
46 | /**
47 | * Allowed HTTP methods
48 | * Restricted to essential operations for security
49 | */
50 | const ALLOWED_METHODS = [
51 | 'GET',
52 | 'POST',
53 | 'PUT',
54 | 'DELETE',
55 | 'OPTIONS'
56 | ] as const;
57 |
58 | /**
59 | * CORS configuration implementing strict security policies
60 | * @const corsConfig
61 | * @implements {CorsConfig}
62 | */
63 | export const corsConfig: CorsConfig = {
64 | // Combine production and development domains based on environment
65 | allowedOrigins: [
66 | ...PRODUCTION_DOMAINS,
67 | ...(process.env.NODE_ENV === 'development' ? DEVELOPMENT_DOMAINS : [])
68 | ],
69 |
70 | // Restrict HTTP methods to essential operations
71 | allowedMethods: [...ALLOWED_METHODS],
72 |
73 | // Implement required security headers
74 | allowedHeaders: [...SECURITY_HEADERS],
75 |
76 | // Enable credentials for authenticated requests
77 | credentials: true,
78 |
79 | // Additional security headers for Egyptian compliance
80 | securityHeaders: {
81 | 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
82 | 'X-Content-Type-Options': 'nosniff',
83 | 'X-Frame-Options': 'SAMEORIGIN',
84 | 'X-XSS-Protection': '1; mode=block',
85 | 'Referrer-Policy': 'strict-origin-when-cross-origin',
86 | 'Content-Security-Policy': "default-src 'self'"
87 | },
88 |
89 | // Validate origin before processing requests
90 | validateOriginBeforeRequest: true,
91 |
92 | // Preflight request timeout in seconds
93 | preflightContinue: 10,
94 |
95 | // Required by BaseEntity interface
96 | id: 'cors-config',
97 | createdAt: new Date(),
98 | updatedAt: new Date(),
99 | isActive: true
100 | };
101 |
102 | export default corsConfig;
--------------------------------------------------------------------------------
/infrastructure/kubernetes/configmaps.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | # API Gateway ConfigMap
5 | - apiVersion: v1
6 | kind: ConfigMap
7 | metadata:
8 | name: api-gateway-config
9 | namespace: app
10 | labels:
11 | app: api-gateway
12 | part-of: egyptian-map-pi
13 | environment: production
14 | data:
15 | # CORS Configuration
16 | cors-config:
17 | allowedOrigins:
18 | - https://*.pi.network
19 | - https://*.egyptian-map-pi.com
20 | - https://egyptian-map-pi.com
21 | allowedMethods:
22 | - GET
23 | - POST
24 | - PUT
25 | - DELETE
26 | - OPTIONS
27 | allowedHeaders:
28 | - Content-Type
29 | - Authorization
30 | - X-Pi-Network-Token
31 | - Accept-Language
32 | maxAge: "86400"
33 | credentials: true
34 |
35 | # Rate Limiting Configuration
36 | rate-limit-config:
37 | windowMs: "900000" # 15 minutes
38 | max: "100" # 100 requests per windowMs
39 | message: "Too many requests from this IP"
40 | skipSuccessfulRequests: false
41 | headers: true
42 |
43 | # Logging Configuration
44 | logging-config:
45 | level: info
46 | format: json
47 | timestamp: true
48 | colorize: false
49 | requestId: true
50 |
51 | # Metrics Configuration
52 | metrics-config:
53 | enabled: true
54 | path: /metrics
55 | collectDefaultMetrics: true
56 | prefix: egyptian_map_pi_
57 |
58 | # Auth Service ConfigMap
59 | - apiVersion: v1
60 | kind: ConfigMap
61 | metadata:
62 | name: auth-service-config
63 | namespace: app
64 | labels:
65 | app: auth-service
66 | part-of: egyptian-map-pi
67 | environment: production
68 | data:
69 | # Pi Network Integration Configuration
70 | pi-network-config:
71 | apiEndpoint: https://api.minepi.com
72 | sandboxMode: "false"
73 | platformType: web
74 | appVersion: "1.0.0"
75 | scope:
76 | - payments
77 | - username
78 | - wallet_address
79 |
80 | # JWT Configuration
81 | jwt-config:
82 | algorithm: RS256
83 | expiresIn: "24h"
84 | issuer: egyptian-map-pi
85 | audience: egyptian-map-pi-users
86 | refreshTokenExpiry: "7d"
87 |
88 | # KYC Configuration for Egyptian Market
89 | kyc-config:
90 | requiredLevel: full
91 | region: EG
92 | allowedDocumentTypes:
93 | - national_id
94 | - passport
95 | - drivers_license
96 | minAge: 18
97 | verificationTimeout: "48h"
98 | merchantRequirements:
99 | businessRegistration: true
100 | taxId: true
101 | addressVerification: true
102 |
103 | # Localization Configuration
104 | localization-config:
105 | defaultLanguage: ar
106 | supportedLanguages:
107 | - ar
108 | - en
109 | rtlLanguages:
110 | - ar
111 | timezone: Africa/Cairo
--------------------------------------------------------------------------------