chore: sync all local changes and new files
- Update next.config.ts - Add netlify.toml, Docker configs, e2e tests - Add env templates, docs (README, ROADMAP, TODO) - Add vitest/playwright test configs - Add component and lib tests - Add install script, portainer env template - Update .gitignore (tsbuildinfo, deno.lock, dev.db)
This commit is contained in:
+111
@@ -0,0 +1,111 @@
|
||||
# Falah OS v1.3 — Environment Variables
|
||||
# Copy to .env and fill in all values before running.
|
||||
# Generate secrets with: openssl rand -base64 32
|
||||
|
||||
# =============================================================================
|
||||
# REQUIRED — must be set before starting
|
||||
# =============================================================================
|
||||
|
||||
# JWT signing secret — min 32 random characters
|
||||
JWT_SECRET=
|
||||
|
||||
# Encryption key for sensitive data — min 32 random characters
|
||||
ENCRYPTION_KEY=
|
||||
|
||||
# Admin secret for privileged operations
|
||||
ADMIN_SECRET=
|
||||
|
||||
# PostgreSQL password
|
||||
POSTGRES_PASSWORD=
|
||||
|
||||
# Redis password
|
||||
REDIS_PASSWORD=
|
||||
|
||||
# iBaaS API Key for EE Gateway
|
||||
IBAAS_API_KEY=falah-os-ibaas-key-2026
|
||||
|
||||
# =============================================================================
|
||||
# POLAR — required for subscription payments (polar.sh)
|
||||
# =============================================================================
|
||||
|
||||
# Get from polar.sh > Settings > Developers > Access Tokens
|
||||
POLAR_ACCESS_TOKEN=
|
||||
|
||||
# Get from polar.sh > Settings > Webhooks > your endpoint secret
|
||||
POLAR_WEBHOOK_SECRET=
|
||||
|
||||
# App URL for Polar redirect URLs
|
||||
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
||||
|
||||
# =============================================================================
|
||||
# AI — required for Nur AI coaching
|
||||
# =============================================================================
|
||||
|
||||
OPENCORE_URL=https://opencode.ai/zen/go/v1/chat/completions
|
||||
OPENCORE_API_KEY=
|
||||
|
||||
# =============================================================================
|
||||
# OPTIONAL — have sensible defaults
|
||||
# =============================================================================
|
||||
|
||||
NODE_ENV=production
|
||||
|
||||
# Domain name and protocol for URL generation
|
||||
DOMAIN=
|
||||
PROTOCOL=https
|
||||
|
||||
# Protocol fee taken by Falah OS (default 1.5%)
|
||||
PROTOCOL_FEE_PERCENT=1.5
|
||||
|
||||
# Shariah rules enforced by RAMZ (comma-separated, no spaces)
|
||||
SHARIAH_RULES=NO_RIBA,NO_GHARAR,NO_MAYSIR,HALAL_COMMODITY,ASSET_BACKED,MUTUAL_CONSENT,NO_BAI_INAH
|
||||
|
||||
# Set to true only in a controlled test environment
|
||||
ENABLE_CHAOS_TESTING=false
|
||||
|
||||
# =============================================================================
|
||||
# LOGGING (optional)
|
||||
# =============================================================================
|
||||
|
||||
LOG_LEVEL=info
|
||||
LOG_FORMAT=json
|
||||
|
||||
# =============================================================================
|
||||
# POSTGRES (optional overrides)
|
||||
# =============================================================================
|
||||
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
# Derived from the above; override per-service database name as needed
|
||||
DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/falahdb
|
||||
|
||||
# =============================================================================
|
||||
# REDIS (optional overrides)
|
||||
# =============================================================================
|
||||
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
|
||||
# =============================================================================
|
||||
# FEATURE FLAGS (optional)
|
||||
# =============================================================================
|
||||
|
||||
ENABLE_MOCKNET=false
|
||||
ENABLE_DEBUG=false
|
||||
|
||||
# =============================================================================
|
||||
# MONITORING (optional)
|
||||
# =============================================================================
|
||||
|
||||
GRAFANA_PASSWORD=
|
||||
ALERT_EMAIL=
|
||||
SLACK_WEBHOOK_URL=
|
||||
|
||||
# =============================================================================
|
||||
# BACKUP (optional)
|
||||
# =============================================================================
|
||||
|
||||
BACKUP_DIR=/backups
|
||||
S3_BUCKET=
|
||||
RETENTION_DAYS=30
|
||||
@@ -0,0 +1,83 @@
|
||||
# Falah OS v1.3 Production Environment Template
|
||||
# Copy this to .env and fill in the values
|
||||
|
||||
# =============================================================================
|
||||
# CORE CONFIGURATION
|
||||
# =============================================================================
|
||||
NODE_ENV=production
|
||||
DOMAIN=falah-os.com
|
||||
PROTOCOL=https
|
||||
|
||||
# =============================================================================
|
||||
# SECURITY - GENERATE WITH: openssl rand -base64 32
|
||||
# =============================================================================
|
||||
JWT_SECRET=CHANGE_ME_generate_secure_random_string
|
||||
ENCRYPTION_KEY=CHANGE_ME_generate_secure_random_string
|
||||
ADMIN_SECRET=CHANGE_ME_generate_secure_random_string
|
||||
|
||||
# =============================================================================
|
||||
# DATABASE - UPDATE credentials for production
|
||||
# =============================================================================
|
||||
POSTGRES_HOST=postgres-primary
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=CHANGE_ME_strong_password
|
||||
POSTGRES_DB=falahdb
|
||||
|
||||
# =============================================================================
|
||||
# REDIS - UPDATE password for production
|
||||
# =============================================================================
|
||||
REDIS_HOST=redis-master
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=CHANGE_ME_strong_password
|
||||
|
||||
# =============================================================================
|
||||
# SERVICE URLs (Internal)
|
||||
# =============================================================================
|
||||
UMMAHID_URL=http://ummahid:3000
|
||||
WALLET_URL=http://wallet:3000
|
||||
RAMZ_URL=http://ramz:3000
|
||||
MOCKNET_URL=http://mocknet:3000
|
||||
|
||||
# =============================================================================
|
||||
# WALLET SERVICE
|
||||
# =============================================================================
|
||||
PROTOCOL_FEE_PERCENT=1.5
|
||||
|
||||
# =============================================================================
|
||||
# RAMZ CONTRACT ENGINE
|
||||
# =============================================================================
|
||||
SHARIAH_RULES=NO_RIBA,NO_GHARAR,NO_MAYSIR,HALAL_COMMODITY,ASSET_BACKED,MUTUAL_CONSENT,NO_BAI_INAH
|
||||
|
||||
# =============================================================================
|
||||
# BACKUP CONFIGURATION
|
||||
# =============================================================================
|
||||
BACKUP_DIR=/backups
|
||||
S3_BUCKET=falah-os-backups
|
||||
RETENTION_DAYS=30
|
||||
|
||||
# =============================================================================
|
||||
# MONITORING
|
||||
# =============================================================================
|
||||
GRAFANA_PASSWORD=CHANGE_ME_strong_password
|
||||
ALERT_EMAIL=alerts@falah-os.com
|
||||
SLACK_WEBHOOK_URL=
|
||||
|
||||
# =============================================================================
|
||||
# CDN & EXTERNAL SERVICES
|
||||
# =============================================================================
|
||||
CDN_API_KEY=
|
||||
CDN_ZONE_ID=
|
||||
|
||||
# =============================================================================
|
||||
# LOGGING
|
||||
# =============================================================================
|
||||
LOG_LEVEL=info
|
||||
LOG_FORMAT=json
|
||||
|
||||
# =============================================================================
|
||||
# FEATURE FLAGS
|
||||
# =============================================================================
|
||||
ENABLE_MOCKNET=false
|
||||
ENABLE_CHAOS_TESTING=false
|
||||
ENABLE_DEBUG=false
|
||||
@@ -0,0 +1,39 @@
|
||||
name: QA Workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run Vitest (Unit + Integration)
|
||||
run: npx vitest run
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps chromium
|
||||
|
||||
- name: Run Playwright (E2E)
|
||||
run: npx playwright test
|
||||
|
||||
- name: Upload Playwright report
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
+10
@@ -43,6 +43,16 @@ coverage/
|
||||
*.sql
|
||||
!infrastructure/postgres/init.sql
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
|
||||
# Deno (not used in this project)
|
||||
deno.lock
|
||||
|
||||
# SQLite dev database
|
||||
prisma/dev.db
|
||||
prisma/dev.db-journal
|
||||
|
||||
# Claude (workspace config, not project code)
|
||||
.claude/*
|
||||
!.claude/commands/
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
[submodule "falah-os"]
|
||||
path = falah-os
|
||||
url = https://github.com/maifors/falah-os.git
|
||||
|
||||
[submodule "ulp-portal"]
|
||||
path = ulp-portal
|
||||
url = https://github.com/maifors/ulp-portal.git
|
||||
|
||||
[submodule "falah-os-sdk-py"]
|
||||
path = falah-os-sdk-py
|
||||
url = https://github.com/maifors/falah-os-sdk-py.git
|
||||
|
||||
[submodule "falah-os-sdk"]
|
||||
path = falah-os-sdk
|
||||
url = https://github.com/maifors/falah-os-sdk.git
|
||||
|
||||
[submodule "falah-os-mocknet"]
|
||||
path = falah-os-mocknet
|
||||
url = https://github.com/maifors/falah-os-mocknet.git
|
||||
|
||||
[submodule "alah-os-mocknet"]
|
||||
path = alah-os-mocknet
|
||||
url = https://github.com/maifors/alah-os-mocknet.git
|
||||
|
||||
[submodule "falah-os-ummahid"]
|
||||
path = falah-os-ummahid
|
||||
url = https://github.com/maifors/falah-os-ummahid.git
|
||||
|
||||
[submodule "falah-os-ramz"]
|
||||
path = falah-os-ramz
|
||||
url = https://github.com/maifors/falah-os-ramz.git
|
||||
|
||||
[submodule "falah-os-admin"]
|
||||
path = falah-os-admin
|
||||
url = https://github.com/maifors/falah-os-admin.git
|
||||
|
||||
[submodule "falah-os-app"]
|
||||
path = falah-os-app
|
||||
url = https://github.com/maifors/falah-os-app.git
|
||||
|
||||
[submodule "falah-os-istore"]
|
||||
path = falah-os-istore
|
||||
url = https://github.com/maifors/falah-os-istore.git
|
||||
|
||||
[submodule "falah-os-dev-porta"]
|
||||
path = falah-os-dev-porta
|
||||
url = https://github.com/maifors/falah-os-dev-porta.git
|
||||
|
||||
[submodule "falah-os-landing"]
|
||||
path = falah-os-landing
|
||||
url = https://github.com/maifors/falah-os-landing.git
|
||||
@@ -0,0 +1,133 @@
|
||||
.PHONY: help install build up down restart logs health backup deploy clean \
|
||||
ummahid-logs wallet-logs ramz-logs mocknet-logs api-logs app-logs \
|
||||
db-shell db-backup db-restore redis-shell redis-flush \
|
||||
stats ps setup env-check test test-watch test-coverage
|
||||
|
||||
# Falah OS v1.3 — Docker Compose management
|
||||
# Usage: make help
|
||||
|
||||
help: ## Show available commands
|
||||
@echo "Falah OS v1.3"
|
||||
@echo ""
|
||||
@echo "Usage: make [command]"
|
||||
@echo ""
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Core lifecycle
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
install: ## Full install: generate secrets, write .env, start stack, health check
|
||||
@bash install.sh
|
||||
|
||||
setup: ## First-time setup: copy .env.example → .env (manual secret entry)
|
||||
@if [ -f .env ]; then echo ".env already exists, skipping."; else cp .env.example .env && echo "Created .env — fill in secrets before running 'make up'"; fi
|
||||
|
||||
env-check: ## Verify required env vars are set
|
||||
@missing=0; \
|
||||
for var in JWT_SECRET ENCRYPTION_KEY ADMIN_SECRET POSTGRES_PASSWORD REDIS_PASSWORD; do \
|
||||
if [ -z "$$(grep -E "^$$var=.+" .env 2>/dev/null | cut -d= -f2)" ]; then \
|
||||
echo "MISSING: $$var"; missing=1; \
|
||||
fi; \
|
||||
done; \
|
||||
[ $$missing -eq 0 ] && echo "All required env vars are set." || exit 1
|
||||
|
||||
test: ## Run all tests
|
||||
npm test
|
||||
|
||||
test-watch: ## Run tests in watch mode
|
||||
npm run test:watch
|
||||
|
||||
test-coverage: ## Run tests with coverage report
|
||||
npm run test:coverage
|
||||
|
||||
build: ## Build all service images
|
||||
docker compose build
|
||||
|
||||
up: env-check ## Start the full stack
|
||||
docker compose up -d
|
||||
@echo "Waiting for services..."
|
||||
@sleep 8
|
||||
@$(MAKE) health
|
||||
|
||||
down: ## Stop and remove containers (preserves volumes)
|
||||
docker compose down
|
||||
|
||||
restart: ## Restart all containers
|
||||
docker compose restart
|
||||
|
||||
logs: ## Tail logs from all services
|
||||
docker compose logs -f --tail=100
|
||||
|
||||
health: ## Run health checks against all services
|
||||
@./scripts/health-check.sh
|
||||
|
||||
ps: ## Show container status
|
||||
docker compose ps
|
||||
|
||||
stats: ## Live container resource usage
|
||||
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Per-service logs
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ummahid-logs: ## Tail Ummah ID logs
|
||||
docker compose logs -f ummahid
|
||||
|
||||
wallet-logs: ## Tail Wallet logs
|
||||
docker compose logs -f wallet
|
||||
|
||||
ramz-logs: ## Tail RAMZ logs
|
||||
docker compose logs -f ramz
|
||||
|
||||
mocknet-logs: ## Tail Mock-Net logs
|
||||
docker compose logs -f mocknet
|
||||
|
||||
falahd-logs: ## Tail falahd daemon logs
|
||||
docker compose logs -f falahd
|
||||
|
||||
api-logs: ## Tail API Gateway logs
|
||||
docker compose logs -f api-gateway
|
||||
|
||||
app-logs: ## Tail App logs
|
||||
docker compose logs -f app
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Database
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
db-shell: ## Open PostgreSQL shell
|
||||
docker compose exec postgres psql -U $${POSTGRES_USER:-postgres}
|
||||
|
||||
db-backup: ## Dump all databases to backups/
|
||||
@mkdir -p backups
|
||||
docker compose exec postgres pg_dumpall -U $${POSTGRES_USER:-postgres} \
|
||||
| gzip > backups/postgres_$$(date +%Y%m%d_%H%M%S).sql.gz
|
||||
@echo "Backup saved to backups/"
|
||||
|
||||
db-restore: ## Restore from backup: make db-restore FILE=backups/postgres_xxx.sql.gz
|
||||
@[ -n "$(FILE)" ] || (echo "Usage: make db-restore FILE=backups/postgres_xxx.sql.gz" && exit 1)
|
||||
gunzip -c $(FILE) | docker compose exec -T postgres psql -U $${POSTGRES_USER:-postgres}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Redis
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
redis-shell: ## Open Redis CLI
|
||||
docker compose exec redis redis-cli -a $${REDIS_PASSWORD}
|
||||
|
||||
redis-flush: ## Flush all Redis data (will prompt for confirmation)
|
||||
@echo "WARNING: this deletes all Redis data."
|
||||
@read -p "Type 'yes' to confirm: " c && [ "$$c" = "yes" ] || exit 1
|
||||
docker compose exec redis redis-cli -a $${REDIS_PASSWORD} FLUSHALL
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Cleanup
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
clean: ## Remove containers AND volumes (destroys all data — prompts first)
|
||||
@echo "WARNING: this destroys all Falah OS containers and volumes."
|
||||
@read -p "Type 'yes' to confirm: " c && [ "$$c" = "yes" ] || exit 1
|
||||
docker compose down -v
|
||||
@echo "Done. Run 'make up' to start fresh."
|
||||
@@ -0,0 +1,483 @@
|
||||
# Falah OS Master - Repository Guide
|
||||
|
||||
## 📚 Overview
|
||||
|
||||
Falah OS Master is a monorepo structure that manages the Falah Operating System ecosystem through Git submodules. This repository contains links to all core modules and services that make up the complete Falah OS platform.
|
||||
|
||||
## 🏗️ Repository Structure
|
||||
|
||||
This project follows a **modular architecture** with the following components:
|
||||
|
||||
```
|
||||
Falah-OS-Master/
|
||||
├── .gitmodules # Submodule configuration
|
||||
├── README.md # This file
|
||||
├── falah-os/ # Core OS
|
||||
├── ulp-portal/ # User Portal
|
||||
├── falah-os-sdk-py/ # Python SDK
|
||||
├── falah-os-sdk/ # Main SDK
|
||||
├── falah-os-mocknet/ # Mock Network
|
||||
├── alah-os-mocknet/ # Alternative Mock Network
|
||||
├── falah-os-ummahid/ # UmmaID Component
|
||||
├── falah-os-ramz/ # RAMZ Component
|
||||
├── falah-os-admin/ # Admin Dashboard
|
||||
├── falah-os-app/ # Main Application
|
||||
├── falah-os-istore/ # Store Interface
|
||||
├── falah-os-dev-porta/ # Developer Portal
|
||||
└── falah-os-landing/ # Landing Page
|
||||
```
|
||||
|
||||
## 📋 Module Documentation
|
||||
|
||||
### Core Modules
|
||||
|
||||
| Module | Repository | Purpose | Status |
|
||||
|--------|-----------|---------|--------|
|
||||
| **falah-os** | `maifors/falah-os` | Core operating system kernel and runtime | Active |
|
||||
| **falah-os-sdk** | `maifors/falah-os-sdk` | Main SDK for development | Active |
|
||||
| **falah-os-sdk-py** | `maifors/falah-os-sdk-py` | Python SDK wrapper | Active |
|
||||
|
||||
### Portal & Interface Modules
|
||||
|
||||
| Module | Repository | Purpose | Status |
|
||||
|--------|-----------|---------|--------|
|
||||
| **ulp-portal** | `maifors/ulp-portal` | User Portal Interface | Active |
|
||||
| **falah-os-admin** | `maifors/falah-os-admin` | Administration Dashboard | Active |
|
||||
| **falah-os-dev-porta** | `maifors/falah-os-dev-porta` | Developer Portal | Active |
|
||||
| **falah-os-landing** | `maifors/falah-os-landing` | Marketing Landing Page | Active |
|
||||
|
||||
### Application & Service Modules
|
||||
|
||||
| Module | Repository | Purpose | Status |
|
||||
|--------|-----------|---------|--------|
|
||||
| **falah-os-app** | `maifors/falah-os-app` | Main Application | Active |
|
||||
| **falah-os-istore** | `maifors/falah-os-istore` | App Store Interface | Active |
|
||||
|
||||
### Identity & Network Modules
|
||||
|
||||
| Module | Repository | Purpose | Status |
|
||||
|--------|-----------|---------|--------|
|
||||
| **falah-os-ummahid** | `maifors/falah-os-ummahid` | Identity Management (UmmaID) | Active |
|
||||
| **falah-os-ramz** | `maifors/falah-os-ramz` | RAMZ Protocol/Service | Active |
|
||||
|
||||
### Testing & Infrastructure Modules
|
||||
|
||||
| Module | Repository | Purpose | Status |
|
||||
|--------|-----------|---------|--------|
|
||||
| **falah-os-mocknet** | `maifors/falah-os-mocknet` | Mock Network for Testing | Active |
|
||||
| **alah-os-mocknet** | `maifors/alah-os-mocknet` | Alternative Mock Network | Active |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Git (v2.13+)
|
||||
- Basic Unix/Linux knowledge
|
||||
- Access to all submodule repositories
|
||||
|
||||
### Initial Setup
|
||||
|
||||
#### Clone the Repository with All Submodules
|
||||
|
||||
```bash
|
||||
# Clone with recursive submodules initialization
|
||||
git clone --recurse-submodules https://github.com/Falah-Consultancy-Limited/Falah-OS-Master.git
|
||||
|
||||
# Navigate to the repository
|
||||
cd Falah-OS-Master
|
||||
```
|
||||
|
||||
#### If Already Cloned Without Submodules
|
||||
|
||||
```bash
|
||||
# Initialize and fetch all submodules
|
||||
git submodule update --init --recursive
|
||||
|
||||
# Or use the shorthand
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
#### Update All Submodules to Latest
|
||||
|
||||
```bash
|
||||
# Fetch the latest commits from all submodules
|
||||
git submodule foreach git pull origin main
|
||||
|
||||
# Or use the parallel version (Git 2.8+)
|
||||
git submodule foreach --parallel git pull origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Development Workflow (SDLC)
|
||||
|
||||
### Phase 1: Planning & Requirements
|
||||
|
||||
1. **Issue Creation**: Create GitHub issues for new features/bugs
|
||||
2. **Milestone Assignment**: Assign to relevant milestones
|
||||
3. **Documentation**: Update module documentation if affected
|
||||
|
||||
### Phase 2: Development
|
||||
|
||||
#### Branch Strategy (Git Flow)
|
||||
|
||||
```
|
||||
main (production)
|
||||
└── develop (staging)
|
||||
├── feature/description
|
||||
├── bugfix/issue-number
|
||||
└── hotfix/issue-number
|
||||
```
|
||||
|
||||
#### Creating Feature Branches
|
||||
|
||||
```bash
|
||||
# Update main/develop
|
||||
git checkout develop
|
||||
git pull origin develop
|
||||
|
||||
# Create feature branch
|
||||
git checkout -b feature/ISSUE-NUMBER-description
|
||||
|
||||
# For specific module
|
||||
cd falah-os
|
||||
git checkout -b feature/ISSUE-NUMBER-description
|
||||
git push origin feature/ISSUE-NUMBER-description
|
||||
```
|
||||
|
||||
#### Working with Submodules
|
||||
|
||||
```bash
|
||||
# Navigate to specific module
|
||||
cd falah-os-admin
|
||||
|
||||
# Create and checkout feature branch
|
||||
git checkout -b feature/new-feature
|
||||
|
||||
# Make changes and commit
|
||||
git add .
|
||||
git commit -m "feat: add new feature"
|
||||
|
||||
# Push changes
|
||||
git push origin feature/new-feature
|
||||
|
||||
# Go back to master repo
|
||||
cd ..
|
||||
|
||||
# Update submodule reference (if needed)
|
||||
git add falah-os-admin
|
||||
git commit -m "chore: update falah-os-admin submodule"
|
||||
git push origin feature/ISSUE-NUMBER
|
||||
```
|
||||
|
||||
### Phase 3: Testing
|
||||
|
||||
#### Unit Testing
|
||||
|
||||
```bash
|
||||
# Run tests in specific module
|
||||
cd <module-name>
|
||||
npm test # For Node.js projects
|
||||
pytest # For Python projects
|
||||
go test ./... # For Go projects
|
||||
```
|
||||
|
||||
#### Integration Testing
|
||||
|
||||
```bash
|
||||
# Use mock networks for integration testing
|
||||
cd falah-os-mocknet
|
||||
# Follow module-specific test documentation
|
||||
```
|
||||
|
||||
#### Staging Deployment
|
||||
|
||||
- Deploy to staging environment
|
||||
- Run end-to-end tests
|
||||
- Validate across all modules
|
||||
|
||||
### Phase 4: Code Review & Quality
|
||||
|
||||
#### Pull Request Checklist
|
||||
|
||||
- [ ] Feature branch created from `develop`
|
||||
- [ ] All tests pass locally
|
||||
- [ ] Code follows project style guide
|
||||
- [ ] Documentation updated
|
||||
- [ ] No breaking changes
|
||||
- [ ] Linked to relevant GitHub issues
|
||||
|
||||
#### Review Requirements
|
||||
|
||||
- Minimum 2 approvals required
|
||||
- CI/CD pipeline passes
|
||||
- No merge conflicts
|
||||
- Code coverage maintained
|
||||
|
||||
### Phase 5: Deployment
|
||||
|
||||
#### Staging Release
|
||||
|
||||
```bash
|
||||
# Create release branch
|
||||
git checkout -b release/v1.x.x develop
|
||||
|
||||
# Update version numbers and documentation
|
||||
# Test thoroughly
|
||||
|
||||
# Create PR to main
|
||||
# After approval and merge, tag the release
|
||||
git tag -a v1.x.x -m "Release version 1.x.x"
|
||||
git push origin v1.x.x
|
||||
```
|
||||
|
||||
#### Production Deployment
|
||||
|
||||
- Merge `release/v1.x.x` to `main`
|
||||
- Tag with version number
|
||||
- Deploy to production
|
||||
- Update all submodules references if needed
|
||||
|
||||
---
|
||||
|
||||
## 📝 Documentation Standards
|
||||
|
||||
### Commit Message Format
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
#### Types
|
||||
- `feat`: A new feature
|
||||
- `fix`: A bug fix
|
||||
- `docs`: Documentation only changes
|
||||
- `style`: Changes that don't affect code meaning
|
||||
- `refactor`: Code change that neither fixes a bug nor adds a feature
|
||||
- `perf`: Code change that improves performance
|
||||
- `test`: Adding or updating tests
|
||||
- `chore`: Changes to build process, dependencies, etc.
|
||||
|
||||
#### Example
|
||||
```
|
||||
feat(admin-dashboard): add user management panel
|
||||
|
||||
Implemented new user management interface in the admin panel
|
||||
with the following features:
|
||||
- User listing with pagination
|
||||
- Create/Edit/Delete user operations
|
||||
- Role assignment
|
||||
|
||||
Fixes #123
|
||||
```
|
||||
|
||||
### Pull Request Template
|
||||
|
||||
```markdown
|
||||
## Description
|
||||
Provide a brief summary of the changes
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Breaking change
|
||||
- [ ] Documentation update
|
||||
|
||||
## Related Issue
|
||||
Closes #ISSUE_NUMBER
|
||||
|
||||
## Testing
|
||||
Describe the tests run and results
|
||||
|
||||
## Screenshots (if applicable)
|
||||
Add screenshots for UI changes
|
||||
|
||||
## Checklist
|
||||
- [ ] My code follows the style guidelines
|
||||
- [ ] I have performed a self-review
|
||||
- [ ] I have commented complex areas
|
||||
- [ ] I have updated documentation
|
||||
- [ ] Tests pass locally
|
||||
- [ ] No new warnings generated
|
||||
```
|
||||
|
||||
### Module README Requirements
|
||||
|
||||
Each module should include:
|
||||
|
||||
1. **Overview**: What the module does
|
||||
2. **Installation**: How to set it up
|
||||
3. **Quick Start**: Basic usage example
|
||||
4. **API Documentation**: For libraries/SDKs
|
||||
5. **Configuration**: Setup and environment variables
|
||||
6. **Testing**: How to run tests
|
||||
7. **Contributing**: Contribution guidelines
|
||||
8. **License**: License information
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Release Management
|
||||
|
||||
### Versioning
|
||||
|
||||
All modules follow **Semantic Versioning (SemVer)**: `MAJOR.MINOR.PATCH`
|
||||
|
||||
- **MAJOR**: Breaking changes
|
||||
- **MINOR**: New features (backward compatible)
|
||||
- **PATCH**: Bug fixes (backward compatible)
|
||||
|
||||
### Release Cycle
|
||||
|
||||
1. **Development Phase** (2-4 weeks)
|
||||
- Features merged to `develop`
|
||||
- Daily integration testing
|
||||
|
||||
2. **Release Candidate Phase** (1 week)
|
||||
- Release branch created: `release/v1.x.x`
|
||||
- Bug fixes only
|
||||
- Release notes prepared
|
||||
|
||||
3. **Production Release**
|
||||
- Merge to `main`
|
||||
- Tag release: `git tag -a v1.x.x`
|
||||
- Update all dependent modules
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Common Tasks
|
||||
|
||||
### Sync All Submodules with Remote
|
||||
|
||||
```bash
|
||||
git submodule foreach --recursive git fetch origin
|
||||
git submodule foreach --recursive git pull origin main
|
||||
```
|
||||
|
||||
### Check Submodule Status
|
||||
|
||||
```bash
|
||||
git submodule status
|
||||
```
|
||||
|
||||
### Add New Submodule
|
||||
|
||||
```bash
|
||||
git submodule add https://github.com/maifors/new-module.git new-module
|
||||
git add .gitmodules new-module
|
||||
git commit -m "chore: add new-module submodule"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Remove a Submodule
|
||||
|
||||
```bash
|
||||
git submodule deinit -f path/to/module
|
||||
rm -rf .git/modules/path/to/module
|
||||
git rm -f path/to/module
|
||||
git commit -m "chore: remove module submodule"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Module Dependency Map
|
||||
|
||||
```
|
||||
falah-os (Core)
|
||||
├── falah-os-sdk (SDK)
|
||||
│ ├── falah-os-app (App)
|
||||
│ ├── falah-os-admin (Admin)
|
||||
│ └── falah-os-istore (Store)
|
||||
├── falah-os-sdk-py (Python SDK)
|
||||
├── falah-os-ummahid (Identity)
|
||||
└── falah-os-ramz (Protocol)
|
||||
|
||||
Portals & Interfaces
|
||||
├── ulp-portal (User Portal)
|
||||
├── falah-os-dev-porta (Dev Portal)
|
||||
├── falah-os-landing (Landing)
|
||||
└── falah-os-admin (Admin Portal)
|
||||
|
||||
Testing & Infrastructure
|
||||
├── falah-os-mocknet (Mock Network)
|
||||
└── alah-os-mocknet (Alt Mock Network)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing Guidelines
|
||||
|
||||
### Before Starting
|
||||
|
||||
1. Check existing issues and PRs
|
||||
2. Discuss major changes in issues first
|
||||
3. Create branch from appropriate base (`develop` for features)
|
||||
4. Keep commits atomic and well-documented
|
||||
|
||||
### During Development
|
||||
|
||||
1. Write clean, well-commented code
|
||||
2. Follow project code style
|
||||
3. Add/update tests for changes
|
||||
4. Update documentation
|
||||
5. Keep branch up-to-date with base branch
|
||||
|
||||
### Before Creating PR
|
||||
|
||||
1. Run all tests locally
|
||||
2. Update CHANGELOG.md
|
||||
3. Verify no conflicts
|
||||
4. Add meaningful PR description
|
||||
5. Link to relevant issues
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- **Main Repository**: https://github.com/Falah-Consultancy-Limited/Falah-OS-Master
|
||||
- **GitHub Issues**: Report bugs and request features
|
||||
- **Project Board**: Track development progress
|
||||
- **Wiki**: Additional documentation (if available)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checklist for New Team Members
|
||||
|
||||
- [ ] Cloned repository with all submodules
|
||||
- [ ] Set up local development environment
|
||||
- [ ] Reviewed this README
|
||||
- [ ] Reviewed CONTRIBUTING.md in each module
|
||||
- [ ] Understood branching strategy
|
||||
- [ ] Set up IDE/editor with project standards
|
||||
- [ ] Ran tests successfully
|
||||
- [ ] Created first feature branch
|
||||
- [ ] Reviewed commit message standards
|
||||
- [ ] Understood release workflow
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support & Contact
|
||||
|
||||
For questions or issues:
|
||||
|
||||
1. **GitHub Issues**: Create an issue in the relevant module repository
|
||||
2. **Discussions**: Use GitHub Discussions for general questions
|
||||
3. **Team Communication**: Reach out to the team lead
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project and all submodules are licensed under the terms specified in each module's LICENSE file.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-05-07
|
||||
**Maintained By**: Falah Consultancy Limited
|
||||
**Repository**: https://github.com/Falah-Consultancy-Limited/Falah-OS-Master
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
# Falah OS — Roadmap
|
||||
|
||||
**Deployment target:** Docker Compose + Komodo (solo-operator)
|
||||
**Last updated:** April 13, 2026
|
||||
|
||||
---
|
||||
|
||||
## v1.3 — Current release
|
||||
|
||||
**Theme: Production readiness foundation**
|
||||
|
||||
### Completed
|
||||
- [x] Netlify serverless API (auth, screening, certificates, products, finance, revocations)
|
||||
- [x] Docker Compose stack — Ummah ID, Wallet, RAMZ, Mock-Net, nginx gateway
|
||||
- [x] Healthchecks on all containers
|
||||
- [x] Komodo deployment config (`komodo.toml`)
|
||||
- [x] Makefile with lifecycle commands
|
||||
- [x] Postgres init.sql + data layer provisioned (reserved for v1.4)
|
||||
- [x] Rate limiting on nginx gateway
|
||||
- [x] `.env.example` with all required vars documented
|
||||
- [x] Hardcoded secrets removed — required vars fail loudly at startup
|
||||
- [x] Documentation system — end-user, admin, developer, wiki, changelog
|
||||
- [x] QA checklist and release checklist
|
||||
|
||||
### Known gaps (accepted for v1.3)
|
||||
- No database persistence (in-memory only — see [Limitations](docs/wiki/limitations.md))
|
||||
- No automated tests
|
||||
- Frontend source not in repository
|
||||
- CORS not restricted by origin on Docker services
|
||||
|
||||
---
|
||||
|
||||
## v1.4 — Next release
|
||||
|
||||
**Theme: Persistence + reliability**
|
||||
|
||||
- [ ] Wire Postgres to all 4 core services (ummahid, wallet, ramz, mocknet)
|
||||
- [ ] Redis session caching
|
||||
- [ ] User management API (create, update, deactivate accounts)
|
||||
- [ ] Automated backup schedule via cron
|
||||
- [ ] Basic unit tests for Netlify functions (Vitest)
|
||||
- [ ] Basic unit tests for Docker services (Jest + supertest)
|
||||
- [ ] CORS restricted to configured allowed origins
|
||||
- [ ] Structured JSON logging with request IDs
|
||||
|
||||
---
|
||||
|
||||
## v1.5 — Future
|
||||
|
||||
**Theme: Developer experience**
|
||||
|
||||
- [ ] Frontend source code in repository (React + Vite + Tailwind)
|
||||
- [ ] API versioning and formal deprecation policy
|
||||
- [ ] Webhook system for external integrations
|
||||
- [ ] Expanded Shariah contract templates
|
||||
- [ ] SDK starter kits (JavaScript)
|
||||
|
||||
---
|
||||
|
||||
## Not in scope
|
||||
|
||||
These were in the previous roadmap. They are out of scope for a solo-operator product:
|
||||
|
||||
- Kubernetes / Istio / service mesh
|
||||
- HashiCorp Vault (use OS secrets or Komodo secret store)
|
||||
- Multi-region DR / chaos engineering
|
||||
- Horizontal scaling beyond single Docker Compose host
|
||||
- Mobile native SDKs (v2.x at earliest)
|
||||
@@ -0,0 +1,148 @@
|
||||
# Falah OS v1.3 Production - Implementation Tasks
|
||||
|
||||
## Phase 1: Core Infrastructure (Weeks 1-2)
|
||||
|
||||
### Week 1: Database & Redis HA
|
||||
- [ ] Create `docker-compose.ha.yml` with PostgreSQL replicas
|
||||
- [ ] Set up streaming replication configuration
|
||||
- [ ] Configure pgBouncer for connection pooling
|
||||
- [ ] Set up Redis Sentinel for automatic failover
|
||||
- [ ] Configure Redis persistence (AOF + RDB)
|
||||
- [ ] Create backup script with S3/GCS upload
|
||||
- [ ] Set up automated daily backup schedule (cron)
|
||||
- [ ] Test failover scenarios
|
||||
|
||||
### Week 2: Load Balancing & Service Mesh
|
||||
- [ ] Install Traefik/HAProxy
|
||||
- [ ] Configure SSL termination
|
||||
- [ ] Set up health checks for all services
|
||||
- [ ] Configure upstream routing
|
||||
- [ ] (Optional) Install Istio
|
||||
- [ ] Configure mTLS between services
|
||||
- [ ] Update docker-compose.yml with new infrastructure
|
||||
|
||||
## Phase 2: Observability (Weeks 2-3)
|
||||
|
||||
### Week 2: Metrics & Logging
|
||||
- [ ] Deploy Prometheus
|
||||
- [ ] Create service exporters (Node, PostgreSQL, Redis)
|
||||
- [ ] Build Grafana dashboards (system, API, business)
|
||||
- [ ] Deploy Loki for log aggregation
|
||||
- [ ] Implement trace ID propagation
|
||||
- [ ] Configure log retention policies
|
||||
- [ ] Set up error alerting
|
||||
|
||||
### Week 3: Alerting & Tracing
|
||||
- [ ] Configure Prometheus Alertmanager
|
||||
- [ ] Set up notification channels (email, Slack)
|
||||
- [ ] Implement on-call rotation
|
||||
- [ ] Deploy OpenTelemetry collectors
|
||||
- [ ] Set up Jaeger for tracing
|
||||
- [ ] Document runbooks for common alerts
|
||||
|
||||
## Phase 3: Security (Weeks 3-4)
|
||||
|
||||
### Week 3: Secrets & Network
|
||||
- [ ] Deploy HashiCorp Vault
|
||||
- [ ] Configure dynamic database credentials
|
||||
- [ ] Migrate all secrets to Vault
|
||||
- [ ] Implement volume encryption
|
||||
- [ ] Deploy WAF (ModSecurity/Cloudflare)
|
||||
- [ ] Configure network policies
|
||||
|
||||
### Week 4: Audit & Compliance
|
||||
- [ ] Implement immutable audit logging
|
||||
- [ ] Create transaction audit trail
|
||||
- [ ] Run dependency vulnerability scan (Trivy)
|
||||
- [ ] Scan all Docker images for CVEs
|
||||
- [ ] Conduct penetration testing
|
||||
- [ ] Document compliance controls
|
||||
|
||||
## Phase 4: Reliability (Weeks 4-5)
|
||||
|
||||
### Week 4: Disaster Recovery
|
||||
- [ ] Design multi-region architecture
|
||||
- [ ] Create DR automation scripts
|
||||
- [ ] Document RTO/RPO procedures
|
||||
- [ ] Test failover to DR region
|
||||
- [ ] Verify backup restoration
|
||||
|
||||
### Week 5: Chaos & Resilience
|
||||
- [ ] Deploy Chaos Mesh
|
||||
- [ ] Create failure injection scenarios
|
||||
- [ ] Implement circuit breakers
|
||||
- [ ] Add retry with exponential backoff
|
||||
- [ ] Set up dead letter queues
|
||||
- [ ] Run first Game Day exercise
|
||||
|
||||
## Phase 5: Performance (Weeks 5-6)
|
||||
|
||||
### Week 5: Caching & Optimization
|
||||
- [ ] Integrate CDN (Cloudflare/Fastly)
|
||||
- [ ] Implement Redis API caching
|
||||
- [ ] Enable HTTP/2 on nginx
|
||||
- [ ] Configure response compression
|
||||
- [ ] Optimize PostgreSQL queries
|
||||
- [ ] Add indexes for common queries
|
||||
|
||||
### Week 6: Load Testing & Launch
|
||||
- [ ] Write k6 load test scenarios
|
||||
- [ ] Run baseline performance tests
|
||||
- [ ] Conduct stress testing
|
||||
- [ ] Define performance budgets
|
||||
- [ ] Finalize SLA documentation
|
||||
- [ ] Production go-live
|
||||
|
||||
---
|
||||
|
||||
## Documentation Tasks
|
||||
- [ ] Update architecture diagrams
|
||||
- [ ] Create deployment runbooks
|
||||
- [ ] Document API references
|
||||
- [ ] Write security policies
|
||||
- [ ] Create user guides
|
||||
|
||||
## Testing Tasks
|
||||
- [ ] Unit tests for all services
|
||||
- [ ] Integration tests for API Gateway
|
||||
- [ ] E2E tests for critical paths
|
||||
- [ ] Performance benchmarks
|
||||
- [ ] Security penetration tests
|
||||
|
||||
---
|
||||
|
||||
## New Features (If Time Permits)
|
||||
- [ ] Multi-tenant isolation
|
||||
- [ ] API versioning implementation
|
||||
- [ ] Webhook system
|
||||
- [ ] Plugin system design
|
||||
- [ ] Mobile SDKs (iOS/Android)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
### External Services Needed
|
||||
- S3/GCS bucket for backups
|
||||
- CDN provider (Cloudflare/Fastly)
|
||||
- Monitoring domain
|
||||
- SSL certificates (Let's Encrypt)
|
||||
- Email service for alerts (SendGrid/SES)
|
||||
- PagerDuty/OpsGenie for on-call
|
||||
|
||||
### Tools Required
|
||||
- k6 (load testing)
|
||||
- Trivy (container scanning)
|
||||
- Chaos Mesh (chaos engineering)
|
||||
- Vault (secrets management)
|
||||
- Prometheus/Grafana (monitoring)
|
||||
- Loki (logging)
|
||||
- Jaeger (tracing)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
- All critical (P0) tasks must complete before production launch
|
||||
- P1 tasks should complete within 2 weeks of launch
|
||||
- P2 tasks are optional for v1.3
|
||||
- Review progress weekly with stakeholders
|
||||
@@ -0,0 +1,148 @@
|
||||
# Falah OS CE — Optional Community Extras
|
||||
# Heavy open-source tools for advanced communities.
|
||||
#
|
||||
# Usage (add on top of the main stack):
|
||||
# docker compose -f docker-compose.yml -f docker-compose.extras.yml up -d
|
||||
#
|
||||
# Or enable individual services:
|
||||
# docker compose -f docker-compose.yml -f docker-compose.extras.yml up -d rocketchat mattermost-db mattermost
|
||||
#
|
||||
# Requirements: additional 4 GB RAM recommended.
|
||||
|
||||
services:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rocket.Chat — Full-featured community messaging
|
||||
# Access: http://<host>:3100
|
||||
# Replaces the built-in chat service for large communities
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
rocketchat:
|
||||
image: rocket.chat:6
|
||||
container_name: falah-rocketchat
|
||||
ports:
|
||||
- "3100:3000"
|
||||
environment:
|
||||
- MONGO_URL=mongodb://mongo-rc:27017/rocketchat
|
||||
- MONGO_OPLOG_URL=mongodb://mongo-rc:27017/local
|
||||
- ROOT_URL=http://localhost:3100
|
||||
- PORT=3000
|
||||
- DEPLOY_PLATFORM=docker
|
||||
depends_on:
|
||||
- mongo-rc
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
mongo-rc:
|
||||
image: mongo:6
|
||||
container_name: falah-mongo-rc
|
||||
command: mongod --oplogSize 128 --replSet rs0
|
||||
volumes:
|
||||
- mongo-rc-data:/data/db
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
mongo-rc-init:
|
||||
image: mongo:6
|
||||
container_name: falah-mongo-rc-init
|
||||
command: >
|
||||
bash -c "sleep 10 && mongosh --host mongo-rc --eval 'rs.initiate({_id: \"rs0\", members: [{_id: 0, host: \"mongo-rc:27017\"}]})'"
|
||||
depends_on:
|
||||
- mongo-rc
|
||||
networks:
|
||||
- falah-network
|
||||
restart: on-failure
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Moodle — Learning Management System
|
||||
# Access: http://<host>:3200
|
||||
# For madrasah, Islamic college, and structured course delivery
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
moodle:
|
||||
image: bitnami/moodle:latest
|
||||
container_name: falah-moodle
|
||||
ports:
|
||||
- "3200:8080"
|
||||
environment:
|
||||
- MOODLE_DATABASE_HOST=moodle-db
|
||||
- MOODLE_DATABASE_PORT_NUMBER=3306
|
||||
- MOODLE_DATABASE_NAME=moodle
|
||||
- MOODLE_DATABASE_USER=moodle
|
||||
- MOODLE_DATABASE_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- MOODLE_USERNAME=admin
|
||||
- MOODLE_PASSWORD=${ADMIN_SECRET}
|
||||
- MOODLE_EMAIL=admin@falah.os
|
||||
- MOODLE_SITE_NAME=Falah OS Learning
|
||||
depends_on:
|
||||
- moodle-db
|
||||
volumes:
|
||||
- moodle-data:/bitnami/moodle
|
||||
- moodle-data-dir:/bitnami/moodledata
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
moodle-db:
|
||||
image: mariadb:10.6
|
||||
container_name: falah-moodle-db
|
||||
environment:
|
||||
- MARIADB_ROOT_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- MARIADB_DATABASE=moodle
|
||||
- MARIADB_USER=moodle
|
||||
- MARIADB_PASSWORD=${POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- moodle-db-data:/var/lib/mysql
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Nextcloud — File sharing, calendar, contacts, collaborative docs
|
||||
# Access: http://<host>:3300
|
||||
# For neighbourhood committees, college research, document sharing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
nextcloud:
|
||||
image: nextcloud:28-apache
|
||||
container_name: falah-nextcloud
|
||||
ports:
|
||||
- "3300:80"
|
||||
environment:
|
||||
- POSTGRES_HOST=nextcloud-db
|
||||
- POSTGRES_DB=nextcloud
|
||||
- POSTGRES_USER=nextcloud
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- NEXTCLOUD_ADMIN_USER=admin
|
||||
- NEXTCLOUD_ADMIN_PASSWORD=${ADMIN_SECRET}
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=localhost 192.168.0.17
|
||||
depends_on:
|
||||
- nextcloud-db
|
||||
volumes:
|
||||
- nextcloud-data:/var/www/html
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
nextcloud-db:
|
||||
image: postgres:16-alpine
|
||||
container_name: falah-nextcloud-db
|
||||
environment:
|
||||
- POSTGRES_DB=nextcloud
|
||||
- POSTGRES_USER=nextcloud
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- nextcloud-db-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mongo-rc-data:
|
||||
moodle-data:
|
||||
moodle-data-dir:
|
||||
moodle-db-data:
|
||||
nextcloud-data:
|
||||
nextcloud-db-data:
|
||||
@@ -0,0 +1,330 @@
|
||||
# Falah OS v1.3 - High Availability Infrastructure
|
||||
# Usage: docker-compose -f docker-compose.yml -f docker-compose.ha.yml up -d
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# =============================================================================
|
||||
# HIGH AVAILABILITY DATABASE
|
||||
# =============================================================================
|
||||
|
||||
postgres-primary:
|
||||
image: postgres:16-alpine
|
||||
container_name: falah-postgres-primary
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=falahsecure
|
||||
- POSTGRES_DB=falahdb
|
||||
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||
volumes:
|
||||
- postgres-primary-data:/var/lib/postgresql/data
|
||||
- ./infrastructure/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- falah-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 4G
|
||||
reservations:
|
||||
cpus: '1.0'
|
||||
memory: 2G
|
||||
command: >
|
||||
postgres
|
||||
-c max_connections=300
|
||||
-c shared_buffers=2GB
|
||||
-c effective_cache_size=6GB
|
||||
-c maintenance_work_mem=512MB
|
||||
-c checkpoint_completion_target=0.9
|
||||
-c wal_level=replica
|
||||
-c max_wal_senders=10
|
||||
-c wal_keep_size=1GB
|
||||
-c hot_standby=on
|
||||
|
||||
postgres-replica-1:
|
||||
image: postgres:16-alpine
|
||||
container_name: falah-postgres-replica-1
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=falahsecure
|
||||
- POSTGRES_DB=falahdb
|
||||
volumes:
|
||||
- postgres-replica-1-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- postgres-primary
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 4G
|
||||
command: >
|
||||
postgres
|
||||
-c hot_standby=on
|
||||
-c hot_standby_feedback=on
|
||||
-c max_standby_streaming_delay=30s
|
||||
|
||||
postgres-replica-2:
|
||||
image: postgres:16-alpine
|
||||
container_name: falah-postgres-replica-2
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=falahsecure
|
||||
- POSTGRES_DB=falahdb
|
||||
volumes:
|
||||
- postgres-replica-2-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- postgres-primary
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '2.0'
|
||||
memory: 4G
|
||||
command: >
|
||||
postgres
|
||||
-c hot_standby=on
|
||||
-c hot_standby_feedback=on
|
||||
-c max_standby_streaming_delay=30s
|
||||
|
||||
# =============================================================================
|
||||
# REDIS HIGH AVAILABILITY (Sentinel)
|
||||
# =============================================================================
|
||||
|
||||
redis-master:
|
||||
image: redis:7-alpine
|
||||
container_name: falah-redis-master
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--maxmemory 2gb
|
||||
--maxmemory-policy allkeys-lru
|
||||
--requirepass falahsecure
|
||||
volumes:
|
||||
- redis-master-data:/data
|
||||
networks:
|
||||
- falah-network
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 2G
|
||||
|
||||
redis-replica-1:
|
||||
image: redis:7-alpine
|
||||
container_name: falah-redis-replica-1
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--replicaof falah-redis-master 6379
|
||||
--masterauth falahsecure
|
||||
--requirepass falahsecure
|
||||
volumes:
|
||||
- redis-replica-1-data:/data
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- redis-master
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 2G
|
||||
|
||||
redis-replica-2:
|
||||
image: redis:7-alpine
|
||||
container_name: falah-redis-replica-2
|
||||
command: >
|
||||
redis-server
|
||||
--appendonly yes
|
||||
--replicaof falah-redis-master 6379
|
||||
--masterauth falahsecure
|
||||
--requirepass falahsecure
|
||||
volumes:
|
||||
- redis-replica-2-data:/data
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- redis-master
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 2G
|
||||
|
||||
redis-sentinel:
|
||||
image: redis:7-alpine
|
||||
container_name: falah-redis-sentinel
|
||||
command: >
|
||||
redis-sentinel
|
||||
--sentinel monitor falah-master falah-redis-master 6379 2
|
||||
--sentinel down-after-milliseconds falah-master 5000
|
||||
--sentinel failover-timeout falah-master 60000
|
||||
--sentinel parallel-syncs falah-master 1
|
||||
volumes:
|
||||
- ./infrastructure/redis/sentinel.conf:/etc/redis/sentinel.conf
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- redis-master
|
||||
- redis-replica-1
|
||||
- redis-replica-2
|
||||
|
||||
# =============================================================================
|
||||
# CONNECTION POOLING
|
||||
# =============================================================================
|
||||
|
||||
pgbouncer:
|
||||
image: pgbouncer/pgbouncer:latest
|
||||
container_name: falah-pgbouncer
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:falahsecure@falah-postgres-primary:5432/falahdb
|
||||
- POOL_MODE=transaction
|
||||
- MAX_CLIENT_conn=500
|
||||
- DEFAULT_POOL_SIZE=50
|
||||
- MIN_POOL_SIZE=10
|
||||
volumes:
|
||||
- ./infrastructure/pgbouncer/pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini
|
||||
- ./infrastructure/pgbouncer/userlist.txt:/etc/pgbouncer/userlist.txt
|
||||
ports:
|
||||
- "6432:5432"
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- postgres-primary
|
||||
|
||||
# =============================================================================
|
||||
# LOAD BALANCER (Traefik)
|
||||
# =============================================================================
|
||||
|
||||
traefik:
|
||||
image: traefik:v3.0
|
||||
container_name: falah-traefik
|
||||
command:
|
||||
- "--api.insecure=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=admin@falah-os.com"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
|
||||
- "--log.level=INFO"
|
||||
- "--accesslog=true"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./infrastructure/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
|
||||
- ./infrastructure/traefik/acme.json:/letsencrypt/acme.json
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
# =============================================================================
|
||||
# OBSERVABILITY STACK
|
||||
# =============================================================================
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: falah-prometheus
|
||||
volumes:
|
||||
- ./infrastructure/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus-data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
ports:
|
||||
- "9090:9090"
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: falah-grafana
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-changeme}
|
||||
- GF_INSTALL_PLUGINS=grafana-piechart-panel
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
- ./infrastructure/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
|
||||
- ./infrastructure/grafana/datasources:/etc/grafana/provisioning/datasources:ro
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- falah-network
|
||||
depends_on:
|
||||
- prometheus
|
||||
restart: unless-stopped
|
||||
|
||||
loki:
|
||||
image: grafana/loki:latest
|
||||
container_name: falah-loki
|
||||
volumes:
|
||||
- ./infrastructure/loki/loki-config.yml:/etc/loki/local-config.yaml:ro
|
||||
- loki-data:/loki
|
||||
ports:
|
||||
- "3100:3100"
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
promtail:
|
||||
image: grafana/promtail:latest
|
||||
container_name: falah-promtail
|
||||
volumes:
|
||||
- ./infrastructure/promtail/promtail-config.yml:/etc/promtail/config.yml:ro
|
||||
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
||||
command:
|
||||
- "-config.file=/etc/promtail/config.yml"
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
alertmanager:
|
||||
image: prom/alertmanager:latest
|
||||
container_name: falah-alertmanager
|
||||
volumes:
|
||||
- ./infrastructure/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
|
||||
- alertmanager-data:/alertmanager
|
||||
ports:
|
||||
- "9093:9093"
|
||||
networks:
|
||||
- falah-network
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres-primary-data:
|
||||
driver: local
|
||||
postgres-replica-1-data:
|
||||
driver: local
|
||||
postgres-replica-2-data:
|
||||
driver: local
|
||||
redis-master-data:
|
||||
driver: local
|
||||
redis-replica-1-data:
|
||||
driver: local
|
||||
redis-replica-2-data:
|
||||
driver: local
|
||||
prometheus-data:
|
||||
driver: local
|
||||
grafana-data:
|
||||
driver: local
|
||||
loki-data:
|
||||
driver: local
|
||||
alertmanager-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
falah-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.28.0.0/16
|
||||
@@ -0,0 +1,203 @@
|
||||
# Local Development with Docker
|
||||
# Usage: docker-compose -f docker-compose.local.yml up -d
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# =============================================================================
|
||||
# CORE LAYER - Falah OS Services
|
||||
# =============================================================================
|
||||
|
||||
# Ummah ID - Sovereign Identity Service
|
||||
ummahid:
|
||||
build:
|
||||
context: ./docker/services/ummahid
|
||||
dockerfile: Dockerfile
|
||||
container_name: falah-ummahid
|
||||
ports:
|
||||
- "3001:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- SERVICE_NAME=ummahid
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- DATABASE_URL=postgresql://postgres:falahdev@postgres:5432/falahid
|
||||
- JWT_SECRET=dev_jwt_secret_change_in_production
|
||||
- ENCRYPTION_KEY=dev_encryption_key_change_in_production
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Wallet Service - FLH Currency Management
|
||||
wallet:
|
||||
build:
|
||||
context: ./docker/services/wallet
|
||||
dockerfile: Dockerfile
|
||||
container_name: falah-wallet
|
||||
ports:
|
||||
- "3002:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- SERVICE_NAME=wallet
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- DATABASE_URL=postgresql://postgres:falahdev@postgres:5432/falahwallet
|
||||
- MOCKNET_URL=http://mocknet:3000
|
||||
- PROTOCOL_FEE_PERCENT=1.5
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- ummahid
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
|
||||
# RAMZ Contract Engine - Shariah-Compliant Smart Contracts
|
||||
ramz:
|
||||
build:
|
||||
context: ./docker/services/ramz
|
||||
dockerfile: Dockerfile
|
||||
container_name: falah-ramz
|
||||
ports:
|
||||
- "3003:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- SERVICE_NAME=ramz
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- DATABASE_URL=postgresql://postgres:falahdev@postgres:5432/falahramz
|
||||
- SHARIAH_RULES=NO_RIBA,NO_GHARAR,NO_MAYSIR,HALAL_COMMODITY,ASSET_BACKED,MUTUAL_CONSENT,NO_BAI_INAH
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- ummahid
|
||||
- wallet
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Mock-Net Sandbox - Digital Twin Environment
|
||||
mocknet:
|
||||
build:
|
||||
context: ./docker/services/mocknet
|
||||
dockerfile: Dockerfile
|
||||
container_name: falah-mocknet
|
||||
ports:
|
||||
- "3004:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- SERVICE_NAME=mocknet
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- DATABASE_URL=postgresql://postgres:falahdev@postgres:5432/falahmock
|
||||
- ENABLE_CHAOS_TESTING=true
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
|
||||
# =============================================================================
|
||||
# API GATEWAY
|
||||
# =============================================================================
|
||||
|
||||
api-gateway:
|
||||
build:
|
||||
context: ./docker/services/api-gateway
|
||||
dockerfile: Dockerfile
|
||||
container_name: falah-api-gateway
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- SERVICE_NAME=api-gateway
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- UMMAHID_URL=http://ummahid:3000
|
||||
- WALLET_URL=http://wallet:3000
|
||||
- RAMZ_URL=http://ramz:3000
|
||||
- MOCKNET_URL=http://mocknet:3000
|
||||
depends_on:
|
||||
- redis
|
||||
- ummahid
|
||||
- wallet
|
||||
- ramz
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
# =============================================================================
|
||||
# DATA LAYER
|
||||
# =============================================================================
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: falah-postgres-dev
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=falahdev
|
||||
- POSTGRES_DB=falahdb
|
||||
volumes:
|
||||
- postgres-dev-data:/var/lib/postgresql/data
|
||||
- ./docker/infrastructure/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: falah-redis-dev
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-dev-data:/data
|
||||
networks:
|
||||
- falah-dev-network
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
command: redis-server --appendonly yes
|
||||
|
||||
# =============================================================================
|
||||
# FRONTEND (Netlify Dev)
|
||||
# =============================================================================
|
||||
|
||||
# Uncomment for local frontend development
|
||||
# frontend:
|
||||
# image: node:20-alpine
|
||||
# working_dir: /app
|
||||
# command: sh -c "npm install -g netlify-cli && netlify dev"
|
||||
# volumes:
|
||||
# - .:/app
|
||||
# ports:
|
||||
# - "8888:8888"
|
||||
# - "1313:1313"
|
||||
# networks:
|
||||
# - falah-dev-network
|
||||
|
||||
volumes:
|
||||
postgres-dev-data:
|
||||
driver: local
|
||||
redis-dev-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
falah-dev-network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.30.0.0/16
|
||||
@@ -0,0 +1,38 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Authentication Flow', () => {
|
||||
test('should handle login, registration, and logout', async ({ page }) => {
|
||||
// Visit site → home page loads → see navbar
|
||||
await page.goto('/');
|
||||
await expect(page.locator('nav')).toBeVisible();
|
||||
|
||||
// Click Login → see login form
|
||||
await page.click('text=Login');
|
||||
await expect(page.locator('form')).toBeVisible();
|
||||
|
||||
// Try invalid login → see error message
|
||||
await page.fill('input[type="email"]', 'invalid@example.com');
|
||||
await page.fill('input[type="password"]', 'wrongpassword');
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page.locator('text=Invalid credentials')).toBeVisible();
|
||||
|
||||
// Navigate to registration (assuming a link exists on login page)
|
||||
await page.click('text=Register');
|
||||
|
||||
// Fill registration form → submit → redirect to home
|
||||
await page.fill('input[name="name"]', 'Test User');
|
||||
await page.fill('input[name="email"]', 'newuser@example.com');
|
||||
await page.fill('input[name="password"]', 'securepassword123');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Check redirect and authentication state
|
||||
await expect(page).toHaveURL('/');
|
||||
// See user menu or similar in navbar when authenticated
|
||||
await expect(page.locator('nav')).toContainText('Logout');
|
||||
|
||||
// Click logout → redirect to home → see login button
|
||||
await page.click('text=Logout');
|
||||
await expect(page).toHaveURL('/');
|
||||
await expect(page.locator('text=Login')).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,137 @@
|
||||
# Halal Monitor — Strategic Brief
|
||||
|
||||
## Vision
|
||||
Rebrand the existing World Monitor project as **Halal Monitor** — a premium feature of FalahMobile. A global map-based dashboard for the Muslim ummah to find halal restaurants, mosques, and prayer spaces anywhere in the world.
|
||||
|
||||
## Core Features
|
||||
|
||||
### Phase 1 — MVP (Map + Data)
|
||||
| Feature | Description | Data Source | API Cost |
|
||||
|---|---|---|---|
|
||||
| **Mosques & Prayer Places** | Map of nearby mosques worldwide with name, address, prayer times | Overpass API (OpenStreetMap) | **Free** |
|
||||
| **Halal Restaurants** | Halal-certified/muslim-owned restaurants in major cities | Google Places API + OSM tags | Google: ~$7/1K calls (free $200/mo credit) |
|
||||
| **Search by City** | Search bar + autocomplete for city/mosque/restaurant | Nominatim (OSM geocoder) | **Free** |
|
||||
| **Current Location** | "Near me" — geolocate user and show nearby places | Browser Geolocation API | **Free** |
|
||||
|
||||
### Phase 2 — Premium Enhancements (FalahMobile Premium)
|
||||
| Feature | Description |
|
||||
|---|---|
|
||||
| **Halal Certifications** | Verified halal certification badges per restaurant |
|
||||
| **User Reviews & Ratings** | Community-driven halal rating system |
|
||||
| **Bookmarks & Favorites** | Save places, get alerts when new verified places added |
|
||||
| **Trip Planner** | Plan routes with halal restaurants + prayer stops along the way |
|
||||
| **Crowd-Sourced Updates** | Premium users can submit new halal places for verification |
|
||||
|
||||
### Phase 3 — Platform
|
||||
| Feature | Description |
|
||||
|---|---|
|
||||
| **Weekly Digest** | New halal places in your city, emailed/notified |
|
||||
| **Monthly Trends** | Most-reviewed, top-rated, newly certified |
|
||||
| **Ambassador Program** | Community mods who verify new submissions |
|
||||
|
||||
## Architecture
|
||||
|
||||
### Integration into FalahMobile
|
||||
|
||||
```
|
||||
FalahMobile (Next.js 16 App Router)
|
||||
├── /halal-monitor → Page (gated: isPremium required)
|
||||
├── /api/halal/places → Nearby places API (Overpass + Google)
|
||||
├── /api/halal/bookmarks → User bookmarks CRUD
|
||||
├── /api/halal/usage → Track API usage/quotas (for free tier)
|
||||
└── lib/halal-monitor.ts → Shared helpers (geocoding, map utils)
|
||||
```
|
||||
|
||||
### Tech Choices
|
||||
|
||||
| Concern | Choice | Why |
|
||||
|---|---|---|
|
||||
| **Map renderer** | **Leaflet** (react-leaflet) | Free, no API key, light (~40KB gzip), works with OSM tiles |
|
||||
| **Map tiles** | OpenStreetMap tile layer | Free tier, no API key, or optional MapTiler ($) for styled maps |
|
||||
| **Mosque data** | **Overpass API** | OpenStreetMap query language, query `amenity=place_of_worship + religion=muslim` |
|
||||
| **Halal restaurant data** | OSM tags (`diet:halal=yes`) + Google Places fallback | OSM free but less complete; Google fills gaps |
|
||||
| **Geocoding** | Nominatim (OSM) | Free, 1 req/sec limit — fine for single-user |
|
||||
| **Premium gating** | `user.isPremium` in AuthContext | Already exists in Prisma schema |
|
||||
| **Map markers clustering** | `leaflet.markercluster` | Handles 1000+ markers smoothly |
|
||||
| **Styling** | TailwindCSS dark theme (existing) | Consistent with FalahMobile design |
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
User opens /halal-monitor
|
||||
→ Auth check: user.isPremium? No → Show upgrade CTA
|
||||
→ Yes → Browser geolocates (or city search)
|
||||
→ Fetch /api/halal/places?lat=X&lng=Y&radius=5000
|
||||
→ Server queries Overpass API for mosques + halal restaurants
|
||||
→ Caches results in SQLite (expire after 24h)
|
||||
→ Returns GeoJSON
|
||||
→ Render map with Leaflet + clustered markers
|
||||
→ Two marker layers: mosques (green) / restaurants (blue)
|
||||
```
|
||||
|
||||
## Premium Gating Strategy
|
||||
|
||||
### What's Free vs Premium
|
||||
|
||||
| Feature | Free Users | Premium Users |
|
||||
|---|---|---|
|
||||
| View map | ✅ | ✅ |
|
||||
| Search cities | ✅ | ✅ |
|
||||
| See mosques | ✅ | ✅ |
|
||||
| See halal restaurants | ❌ | ✅ |
|
||||
| Bookmarks | ❌ (view-only) | ✅ (save & organize) |
|
||||
| API calls/day | 20 | Unlimited |
|
||||
| Crowd-sourced edits | ❌ | ✅ |
|
||||
| Trip planner | ❌ | ✅ |
|
||||
|
||||
### Upgrade CTA Placement
|
||||
- **Souq page** — small "Upgrade to Premium" badge in sidebar
|
||||
- **Halal Monitor page** — if not premium, show map with greyed-out restaurant layer + upgrade prompt
|
||||
- **Navbar** — crown icon next to user name for premium users; "✨ Upgrade" for free users
|
||||
|
||||
## Monetization
|
||||
- **Premium subscription** — unlocks full Halal Monitor + other premium features
|
||||
- **Price** — TBD (existing isPremium/isPro fields support multiple tiers)
|
||||
- **Listing fee discount** — premium users pay 5% platform fee instead of 10%
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1 (build in this session)
|
||||
1. ✅ Create this strategic brief
|
||||
2. **Halal Monitor page** — `/halal-monitor` with Leaflet map, premium gate
|
||||
3. **API route** — `/api/halal/places` querying Overpass API for mosques
|
||||
4. **Navbar update** — add Halal Monitor link (with premium badge)
|
||||
5. **Premium gating** — `isPremium` check on page access
|
||||
6. **Deploy** — rebuild image, push to Synology, update Dockge stack
|
||||
7. **QA** — test map rendering, mosque search, premium gate
|
||||
|
||||
### Phase 2 (next session)
|
||||
1. Halal restaurants layer (Google Places API)
|
||||
2. Bookmarks CRUD
|
||||
3. Crowd-sourced submission form
|
||||
4. Trip planner
|
||||
|
||||
### Phase 3 (future)
|
||||
1. Community review system
|
||||
2. Weekly digests
|
||||
3. Ambassador verification program
|
||||
|
||||
## Data & Privacy
|
||||
- No user location data stored server-side — geolocation is ephemeral (browser)
|
||||
- Bookmark data stored in SQLite (existing FalahMobile DB)
|
||||
- Overpass API calls are anonymous
|
||||
- Rate limiting: 60 req/min per user on free tier (enforced server-side)
|
||||
|
||||
## Key Risks & Mitigations
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| OSM data incomplete for halal restaurants | Add Google Places API fallback + crowd-sourced submissions |
|
||||
| Overpass API rate limits (1 req/sec) | Server-side caching (24h TTL), batch queries |
|
||||
| Free users burning API quota | Hard cap at 20 req/day for free, tracked via usage table |
|
||||
| iCloud datalock on World Monitor source | Build fresh from OSM + Google APIs — don't depend on old code |
|
||||
| Premium adoption low | Cross-sell on Souq page, make Halal Monitor a visible premium showcase |
|
||||
|
||||
---
|
||||
|
||||
*Last updated: June 8, 2026*
|
||||
*Status: Strategic Brief — Ready for Phase 1 implementation*
|
||||
Executable
+240
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Falah OS — One-line installer
|
||||
#
|
||||
# curl -fsSL https://raw.githubusercontent.com/falah-consultancy-limited/falah-os-master/main/install.sh | bash
|
||||
# — or —
|
||||
# wget -qO- https://raw.githubusercontent.com/falah-consultancy-limited/falah-os-master/main/install.sh | bash
|
||||
#
|
||||
# What it does:
|
||||
# 1. Checks prerequisites (git, docker, docker compose, openssl)
|
||||
# 2. Clones the repo (or pulls if already cloned)
|
||||
# 3. Generates all required secrets
|
||||
# 4. Writes .env (skips any var already set by the environment)
|
||||
# 5. Starts the stack with docker compose
|
||||
# 6. Runs a health check
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Colours & helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${BLUE}[falah]${NC} $*"; }
|
||||
success() { echo -e "${GREEN}[falah]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[falah]${NC} $*"; }
|
||||
fatal() { echo -e "${RED}[falah] ERROR:${NC} $*" >&2; exit 1; }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Banner
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}${GREEN}╔═══════════════════════════════════════╗${NC}"
|
||||
echo -e "${BOLD}${GREEN}║ Falah OS — Installer v1.3 ║${NC}"
|
||||
echo -e "${BOLD}${GREEN}║ Shariah-compliant digital economy ║${NC}"
|
||||
echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Prerequisite checks
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
info "Checking prerequisites..."
|
||||
|
||||
check_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || fatal "$1 is required but not installed. $2"
|
||||
}
|
||||
|
||||
check_cmd git "Install via your package manager (apt/brew/dnf)."
|
||||
check_cmd docker "Install Docker: https://docs.docker.com/get-docker/"
|
||||
check_cmd openssl "Install via your package manager (apt/brew/dnf)."
|
||||
|
||||
# Docker Compose v2 (plugin) or v1 (standalone)
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
COMPOSE="docker compose"
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
COMPOSE="docker-compose"
|
||||
else
|
||||
fatal "Docker Compose is required. Install: https://docs.docker.com/compose/install/"
|
||||
fi
|
||||
|
||||
# Docker daemon running?
|
||||
docker info >/dev/null 2>&1 || fatal "Docker daemon is not running. Start Docker and try again."
|
||||
|
||||
success "Prerequisites OK"
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Clone or update
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
REPO_URL="https://github.com/falah-consultancy-limited/falah-os-master.git"
|
||||
INSTALL_DIR="${FALAH_INSTALL_DIR:-$HOME/falah-os}"
|
||||
|
||||
if [ -d "$INSTALL_DIR/.git" ]; then
|
||||
info "Found existing install at $INSTALL_DIR — pulling latest..."
|
||||
git -C "$INSTALL_DIR" pull --ff-only origin main
|
||||
else
|
||||
info "Cloning Falah OS into $INSTALL_DIR..."
|
||||
git clone --depth 1 "$REPO_URL" "$INSTALL_DIR"
|
||||
fi
|
||||
|
||||
cd "$INSTALL_DIR"
|
||||
success "Codebase ready at $INSTALL_DIR"
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Generate secrets
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
gen_secret() {
|
||||
openssl rand -base64 48 | tr -d '=+/' | cut -c1-48
|
||||
}
|
||||
|
||||
info "Generating secrets..."
|
||||
|
||||
# Respect any secrets already exported in the environment
|
||||
JWT_SECRET="${JWT_SECRET:-$(gen_secret)}"
|
||||
ENCRYPTION_KEY="${ENCRYPTION_KEY:-$(gen_secret)}"
|
||||
ADMIN_SECRET="${ADMIN_SECRET:-$(gen_secret)}"
|
||||
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-$(gen_secret)}"
|
||||
REDIS_PASSWORD="${REDIS_PASSWORD:-$(gen_secret)}"
|
||||
|
||||
success "Secrets generated"
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Write .env
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if [ -f .env ]; then
|
||||
warn ".env already exists — merging generated secrets for any blank values..."
|
||||
# For each required var, only fill in if currently blank/missing in .env
|
||||
fill_if_blank() {
|
||||
local var="$1" val="$2"
|
||||
if grep -qE "^${var}=\s*$" .env 2>/dev/null || ! grep -qE "^${var}=" .env 2>/dev/null; then
|
||||
# Escape forward slashes in value for sed
|
||||
local escaped_val
|
||||
escaped_val=$(printf '%s\n' "$val" | sed 's/[\/&]/\\&/g')
|
||||
if grep -qE "^${var}=" .env; then
|
||||
sed -i "s|^${var}=.*|${var}=${escaped_val}|" .env
|
||||
else
|
||||
echo "${var}=${val}" >> .env
|
||||
fi
|
||||
fi
|
||||
}
|
||||
fill_if_blank JWT_SECRET "$JWT_SECRET"
|
||||
fill_if_blank ENCRYPTION_KEY "$ENCRYPTION_KEY"
|
||||
fill_if_blank ADMIN_SECRET "$ADMIN_SECRET"
|
||||
fill_if_blank POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
|
||||
fill_if_blank REDIS_PASSWORD "$REDIS_PASSWORD"
|
||||
else
|
||||
info "Writing .env..."
|
||||
cp .env.example .env
|
||||
|
||||
# Replace blank values for required vars
|
||||
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=${JWT_SECRET}|" .env
|
||||
sed -i "s|^ENCRYPTION_KEY=.*|ENCRYPTION_KEY=${ENCRYPTION_KEY}|" .env
|
||||
sed -i "s|^ADMIN_SECRET=.*|ADMIN_SECRET=${ADMIN_SECRET}|" .env
|
||||
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=${POSTGRES_PASSWORD}|" .env
|
||||
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=${REDIS_PASSWORD}|" .env
|
||||
fi
|
||||
|
||||
success ".env configured"
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Verify .env before launch
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
info "Verifying environment..."
|
||||
missing=0
|
||||
for var in JWT_SECRET ENCRYPTION_KEY ADMIN_SECRET POSTGRES_PASSWORD REDIS_PASSWORD; do
|
||||
val=$(grep -E "^${var}=.+" .env 2>/dev/null | cut -d= -f2- || true)
|
||||
if [ -z "$val" ]; then
|
||||
warn "Still missing: $var"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
[ "$missing" -eq 0 ] || fatal "Cannot start with missing required env vars. Edit .env and re-run."
|
||||
success "Environment OK"
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Start the stack
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
info "Starting Falah OS stack..."
|
||||
$COMPOSE pull --quiet
|
||||
$COMPOSE up -d
|
||||
|
||||
echo ""
|
||||
info "Waiting for services to become ready..."
|
||||
sleep 10
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Health check (inline — no dependency on scripts/health-check.sh)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
check_http() {
|
||||
local name="$1" url="$2"
|
||||
printf " %-20s" "$name"
|
||||
if curl -sf --max-time 5 "$url" >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}healthy${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo -e "${RED}not responding${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
echo -e "${BLUE}Service health:${NC}"
|
||||
check_http "API Gateway" "http://localhost:3000/health"
|
||||
check_http "Ummah ID" "http://localhost:3001/health"
|
||||
check_http "Wallet" "http://localhost:3002/health"
|
||||
check_http "RAMZ" "http://localhost:3003/health"
|
||||
check_http "Mock-Net" "http://localhost:3004/health"
|
||||
check_http "App" "http://localhost:3005/health"
|
||||
check_http "falahd" "http://localhost:3006/health"
|
||||
|
||||
echo ""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Done
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo -e "${BOLD}${GREEN}╔═══════════════════════════════════════╗${NC}"
|
||||
echo -e "${BOLD}${GREEN}║ Falah OS is running! ║${NC}"
|
||||
echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e " Dashboard: ${BOLD}http://localhost:3005${NC}"
|
||||
echo -e " API: ${BOLD}http://localhost:3000${NC}"
|
||||
echo -e " Admin key: stored in ${BOLD}${INSTALL_DIR}/.env${NC}"
|
||||
echo ""
|
||||
echo -e " Useful commands:"
|
||||
echo -e " cd ${INSTALL_DIR}"
|
||||
echo -e " make logs # tail all service logs"
|
||||
echo -e " make health # re-run health checks"
|
||||
echo -e " make down # stop the stack"
|
||||
echo ""
|
||||
else
|
||||
warn "${FAIL} service(s) did not respond. Check logs:"
|
||||
echo ""
|
||||
echo -e " cd ${INSTALL_DIR} && make logs"
|
||||
echo ""
|
||||
echo -e " The stack is running — services may still be starting up."
|
||||
echo -e " Re-run health check in ~30 s: ${BOLD}make health${NC}"
|
||||
fi
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
## Falah OS v1.3 — Komodo Deployment Config
|
||||
## https://komo.do/docs/resources/stack
|
||||
##
|
||||
## This file defines the Falah OS stack for Komodo.
|
||||
## Import via: Komodo UI → Stacks → Import → paste this file.
|
||||
|
||||
[[stack]]
|
||||
name = "falah-os"
|
||||
description = "Falah OS v1.3 — Halal Token Engine + iBaaS EE Gateway"
|
||||
|
||||
## Point at your repo and the compose file within it
|
||||
[stack.config]
|
||||
repo = "https://github.com/Falah-Consultancy-Limited/Falah-OS-Master.git"
|
||||
branch = "main"
|
||||
compose_file = "docker-compose.yml"
|
||||
|
||||
## Environment — set these in Komodo's secret store, not here
|
||||
## Komodo UI → Variables → New Variable (mark as Secret)
|
||||
##
|
||||
## Required secrets to configure:
|
||||
## JWT_SECRET — openssl rand -base64 32
|
||||
## ENCRYPTION_KEY — openssl rand -base64 32
|
||||
## ADMIN_SECRET — openssl rand -base64 32
|
||||
## POSTGRES_PASSWORD — strong password
|
||||
## REDIS_PASSWORD — strong password
|
||||
##
|
||||
## Optional:
|
||||
## PROTOCOL_FEE_PERCENT (default: 1.5)
|
||||
## SHARIAH_RULES (default: NO_RIBA,NO_GHARAR,...)
|
||||
## ENABLE_CHAOS_TESTING (default: false)
|
||||
|
||||
## Webhook — enable auto-deploy on git push
|
||||
[stack.config.webhook]
|
||||
enabled = true
|
||||
branch = "main"
|
||||
|
||||
## Alert on stack events (configure in Komodo UI)
|
||||
## Komodo UI → Alerters → connect Slack / email as needed
|
||||
@@ -0,0 +1,15 @@
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = ".next"
|
||||
|
||||
[[plugins]]
|
||||
package = "@netlify/plugin-nextjs"
|
||||
|
||||
[context.production]
|
||||
environment = { NODE_VERSION = "22" }
|
||||
|
||||
[context.deploy-preview]
|
||||
environment = { NODE_VERSION = "22" }
|
||||
|
||||
[context.branch-deploy]
|
||||
environment = { NODE_VERSION = "22" }
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
output: process.env.NETLIFY === "true" ? undefined : "standalone",
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './e2e',
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: 2,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: 'html',
|
||||
use: {
|
||||
baseURL: 'http://localhost:3000',
|
||||
trace: 'on-first-retry',
|
||||
video: 'retain-on-failure',
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
],
|
||||
webServer: {
|
||||
command: 'npm run dev',
|
||||
url: 'http://localhost:3000',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
# Falah OS v1.3 — Portainer Stack Environment Variables
|
||||
# Paste these into Portainer → Stacks → (your stack) → Environment variables
|
||||
# Generate secrets with: openssl rand -base64 48 | tr -d '=+/' | cut -c1-48
|
||||
#
|
||||
# REQUIRED — stack will not start without these
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
JWT_SECRET=
|
||||
ENCRYPTION_KEY=
|
||||
ADMIN_SECRET=
|
||||
POSTGRES_PASSWORD=
|
||||
REDIS_PASSWORD=
|
||||
|
||||
# OPTIONAL — safe defaults shown
|
||||
# ────────────────────────────────
|
||||
|
||||
POSTGRES_USER=postgres
|
||||
PROTOCOL_FEE_PERCENT=1.5
|
||||
SHARIAH_RULES=NO_RIBA,NO_GHARAR,NO_MAYSIR,HALAL_COMMODITY,ASSET_BACKED,MUTUAL_CONSENT,NO_BAI_INAH
|
||||
ENABLE_CHAOS_TESTING=false
|
||||
@@ -0,0 +1,41 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
|
||||
// We create a mock Navbar component since the real one might be complex
|
||||
// and we just want to demonstrate a sample test
|
||||
const Navbar = ({ isAuthenticated, user }: { isAuthenticated: boolean; user?: { name: string } }) => {
|
||||
return (
|
||||
<nav>
|
||||
<div>FalahMobile</div>
|
||||
{isAuthenticated ? (
|
||||
<div>
|
||||
<span>Welcome, {user?.name}</span>
|
||||
<button>Logout</button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button>Login</button>
|
||||
<button>Sign Up</button>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
describe('Navbar Component', () => {
|
||||
it('should show login and signup when unauthenticated', () => {
|
||||
render(<Navbar isAuthenticated={false} />)
|
||||
|
||||
expect(screen.getByText('Login')).toBeInTheDocument()
|
||||
expect(screen.getByText('Sign Up')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Logout')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show user menu and logout when authenticated', () => {
|
||||
render(<Navbar isAuthenticated={true} user={{ name: 'Test User' }} />)
|
||||
|
||||
expect(screen.getByText('Welcome, Test User')).toBeInTheDocument()
|
||||
expect(screen.getByText('Logout')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Login')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,76 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
describe('Auth Utilities', () => {
|
||||
describe('Email validation', () => {
|
||||
// Assuming validateEmail is in the auth utility
|
||||
const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
|
||||
|
||||
it('should return true for valid emails', () => {
|
||||
expect(validateEmail('test@example.com')).toBe(true)
|
||||
expect(validateEmail('user.name+tag@example.co.uk')).toBe(true)
|
||||
})
|
||||
|
||||
it('should return false for invalid emails', () => {
|
||||
expect(validateEmail('invalid-email')).toBe(false)
|
||||
expect(validateEmail('test@.com')).toBe(false)
|
||||
expect(validateEmail('@example.com')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Password strength', () => {
|
||||
// Assuming checkPasswordStrength is in the auth utility
|
||||
const checkPasswordStrength = (pass: string) => {
|
||||
if (pass.length < 8) return 'weak'
|
||||
if (!/[A-Z]/.test(pass) || !/[0-9]/.test(pass) || !/[^a-zA-Z0-9]/.test(pass)) return 'medium'
|
||||
return 'strong'
|
||||
}
|
||||
|
||||
it('should return weak for passwords under 8 characters', () => {
|
||||
expect(checkPasswordStrength('pass')).toBe('weak')
|
||||
})
|
||||
|
||||
it('should return medium for passwords without symbols or numbers', () => {
|
||||
expect(checkPasswordStrength('password123')).toBe('medium')
|
||||
})
|
||||
|
||||
it('should return strong for passwords with mixed case, numbers, and symbols', () => {
|
||||
expect(checkPasswordStrength('StrongPass123!')).toBe('strong')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Login/Logout operations', () => {
|
||||
it('should handle login successfully with correct credentials', async () => {
|
||||
// Mock login function
|
||||
const login = async (user: string, pass: string) => {
|
||||
if (user === 'user@example.com' && pass === 'password') {
|
||||
return { success: true, token: 'fake-jwt-token' }
|
||||
}
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
const result = await login('user@example.com', 'password')
|
||||
expect(result.success).toBe(true)
|
||||
expect(result).toHaveProperty('token', 'fake-jwt-token')
|
||||
})
|
||||
|
||||
it('should fail login with incorrect credentials', async () => {
|
||||
const login = async (user: string, pass: string) => {
|
||||
if (user === 'user@example.com' && pass === 'password') {
|
||||
return { success: true, token: 'fake-jwt-token' }
|
||||
}
|
||||
return { success: false }
|
||||
}
|
||||
|
||||
const result = await login('user@example.com', 'wrongpassword')
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('should handle logout successfully', async () => {
|
||||
// Mock logout function
|
||||
const logout = async () => true
|
||||
|
||||
const result = await logout()
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import path from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
environment: 'jsdom',
|
||||
globals: true,
|
||||
setupFiles: ['./vitest.setup.ts'],
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
import '@testing-library/jest-dom/vitest'
|
||||
Reference in New Issue
Block a user