A modern, bilingual real estate listing platform for Afghanistan
- Overview
- Features
- Screenshots
- Tech Stack
- Architecture
- Getting Started
- Project Structure
- API Documentation
- Deployment
- Contributing
- License
- Contact
Manzil (منزل) is a comprehensive real estate listing platform built for the Afghan market. It connects property seekers with real estate agents and developers, offering a seamless experience for browsing, listing, and managing properties.
The platform supports bilingual content (English and Farsi) and handles various property types including sales, rentals, collateral (Bai Wafa), partnerships (Sharik Abad), and fully-furnished accommodations.
- 🌍 Bilingual Support: Full internationalization in English and Farsi (Dari)
- 📱 Responsive Design: Optimized for desktop, tablet, and mobile devices
- 🔐 Role-Based Access: Admin, Agent, and User roles with approval workflows
- 🗺️ Location-Based Search: District and neighborhood filtering for Kabul
- 🏗️ Project Listings: Showcase property development projects
- ⚡ Real-time Updates: Live data synchronization with Firebase
- 🔍 Advanced Search: Filter by property type, district, neighborhood, price range, bedrooms, and more
- 🏠 Property Types: Browse sales, rentals, Bai Wafa, Sharik Abad, and fully-furnished properties
- 📍 Location Filtering: Search by Kabul districts (1-22) and popular neighborhoods
- ❤️ Favorites: Save preferred listings for later viewing
- 📞 Direct Contact: Contact agents via phone, WhatsApp, or email
- 🗺️ Map Integration: View property locations on interactive maps
- 📝 Create Listings: Add new properties with detailed information
- 🖼️ Image Upload: Upload multiple property photos to Firebase Storage
- ⏳ Approval Workflow: Submit listings for admin approval
- 📊 Dashboard: Manage your listings and track their status
- ✏️ Edit Listings: Update property information (requires re-approval)
- 👥 User Management: Manage user roles (admin, agent, user)
- ✅ Approval System: Review and approve agent submissions
- 🗑️ Delete Requests: Handle agent deletion requests
- 📈 Analytics: Track platform activity and listings
- 🔧 Full Control: Direct CRUD operations on all listings and projects
For testing and demonstration purposes, you can use the following admin account:
- Email:
Panjshirtv1@gmail.com - Password:
Asanmanziladmin$1
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS v3.4
- State Management: Zustand
- UI Components: Custom components with Tailwind
- Icons: Lucide React
- Authentication: Firebase Auth
- Database: Cloud Firestore
- Storage: Firebase Storage
- Hosting: Vercel (recommended)
- i18n: next-intl
- Languages: English (en), Farsi/Farsi (fa)
- Library: Leaflet with React-Leaflet
- Vercel Analytics: Built-in performance and usage analytics
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Next.js App │────▶│ Firebase Auth │ │ Cloud Firestore │
│ (Frontend) │ │ (Authentication)│ │ (Database) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Zustand Store │ │ Firebase Storage│ │ Security Rules │
│ (State Mgmt) │ │ (Images) │ │ (Access Control) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- User Authentication: Firebase Auth handles sign-in/sign-up with email/password
- Role Management: User roles stored in Firestore (
userscollection) - Listing Management:
- Admins: Direct CRUD operations
- Agents: Create/Update/Delete requests → Admin approval
- Image Storage: Firebase Storage with organized paths (
/listings/{id}/,/projects/{id}/) - Real-time Updates: Firestore listeners for live data updates
- Firestore Rules: Role-based access control (see
firestore.rules) - Storage Rules: Authenticated users can upload, public read access
- Client-side Validation: Input validation before Firebase operations
- Server-side Validation: Firestore rules enforce data integrity
- Node.js: 18.x or higher
- npm: 9.x or higher (or yarn/pnpm)
- Firebase Project: Create a project at Firebase Console
-
Clone the repository
git clone https://github.com/yourusername/home-listing-website.git cd home-listing-website -
Install dependencies
npm install
-
Set up environment variables
cp .env.example .env.local
Edit
.env.localand add your Firebase configuration:NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_id NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id
-
Configure Firebase
- Enable Email/Password authentication in Firebase Console
- Deploy Firestore rules:
firebase deploy --only firestore:rules - Deploy Storage rules:
firebase deploy --only storage
-
Run the development server
npm run dev
-
Open your browser Navigate to http://localhost:3000
- Go to Firebase Console → Authentication → Sign-in method
- Enable Email/Password provider
- (Optional) Enable Google sign-in for social authentication
- Create a Firestore database in native mode
- Start in production mode (we'll configure rules)
- Deploy the rules from
firestore.rules
- Enable Firebase Storage
- Deploy the rules from
storage.rules
The project includes pre-configured security rules:
firestore.rules: Role-based access for listings, projects, and usersstorage.rules: Controlled access to images based on user roles
home-listing-website/
├── 📁 app/ # Next.js App Router
│ ├── 📁 [locale]/ # Localized routes (en, fa)
│ │ ├── 📁 admin/ # Admin dashboard
│ │ ├── 📁 agent/ # Agent dashboard
│ │ ├── 📁 listings/ # Property listings
│ │ ├── 📁 projects/ # Development projects
│ │ ├── 📁 profile/ # User profiles
│ │ ├── 📁 login/ # Authentication
│ │ ├── 📁 favorites/ # Saved listings
│ │ ├── 📁 converter/ # Currency converter
│ │ ├── layout.tsx # Root layout with i18n
│ │ └── page.tsx # Home page
│ ├── 📁 maintenance/ # Maintenance mode page
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Locale redirect
│ └── globals.css # Global styles
│
├── 📁 components/ # React components
│ ├── 📁 admin/ # Admin components
│ ├── 📁 auth/ # Authentication components
│ ├── 📁 layout/ # Layout components (Navbar, Footer)
│ ├── 📁 listings/ # Listing components
│ ├── 📁 projects/ # Project components
│ ├── 📁 providers/ # Context providers
│ ├── 📁 ui/ # Reusable UI components
│ └── 📁 maps/ # Map components
│
├── 📁 lib/ # Core libraries
│ ├── 📁 firebase/ # Firebase configuration
│ ├── 📁 services/ # API services
│ │ ├── auth.service.ts # Authentication
│ │ ├── listings.service.ts # Listings CRUD
│ │ ├── projects.service.ts # Projects CRUD
│ │ ├── storage.service.ts # File uploads
│ │ └── user.service.ts # User management
│ ├── 📁 store/ # Zustand stores
│ ├── 📁 types/ # TypeScript types
│ └── 📁 utils/ # Utility functions
│
├── 📁 messages/ # i18n translations
│ ├── en.json # English
│ └── fa.json # Farsi
│
├── 📁 public/ # Static assets
│ └── 📁 home/ # Hero images
│
├── 📁 i18n/ # i18n configuration
├── .env.example # Environment template
├── firestore.rules # Firestore security rules
├── storage.rules # Storage security rules
├── tailwind.config.js # Tailwind configuration
├── next.config.ts # Next.js configuration
└── tsconfig.json # TypeScript configuration
// Sign up new user
authService.signUp(email: string, password: string, displayName: string): Promise<User>
// Sign in existing user
authService.signIn(email: string, password: string): Promise<User>
// Sign out
authService.signOut(): Promise<void>
// Get current user
authService.getCurrentUser(): Promise<User | null>
// Listen to auth state changes
authService.onAuthStateChanged(callback: (user: User | null) => void): Unsubscribe
// Send password reset email
authService.sendPasswordReset(email: string): Promise<void>// Fetch all active listings (public)
listingsService.fetchListings(): Promise<Listing[]>
// Fetch single listing by ID
listingsService.fetchListingById(id: string): Promise<Listing | null>
// Fetch listing by property ID (e.g., "AM1000")
listingsService.fetchListingByPropertyId(propertyId: string): Promise<Listing | null>
// Create new listing (admin/agent)
listingsService.createListing(data: CreateListingInput, userId: string, userRole: string, images: string[]): Promise<Listing>
// Update listing (admin/agent)
listingsService.updateListing(id: string, data: UpdateListingInput, userRole: string, images?: string[]): Promise<void>
// Delete listing (admin/agent)
listingsService.deleteListing(id: string, userRole: string): Promise<void>
// Fetch pending approvals (admin only)
listingsService.fetchPendingApprovals(): Promise<Listing[]>
// Fetch pending deletes (admin only)
listingsService.fetchPendingDeletes(): Promise<Listing[]>
// Approve/reject operations (admin only)
listingsService.approveNewListing(id: string): Promise<void>
listingsService.rejectNewListing(id: string): Promise<void>
listingsService.approveEdit(id: string): Promise<void>
listingsService.rejectEdit(id: string): Promise<void>
listingsService.approveDelete(id: string): Promise<void>
listingsService.rejectDelete(id: string): Promise<void>// Fetch all projects (public)
projectsService.fetchProjects(): Promise<Project[]>
// Fetch single project by ID
projectsService.fetchProjectById(id: string): Promise<Project | null>
// Create new project (admin/agent)
projectsService.createProject(data: CreateProjectInput, userId: string): Promise<Project>
// Update project (admin/agent)
projectsService.updateProject(id: string, data: UpdateProjectInput, userId: string, userRole: string): Promise<void>
// Delete project (admin/agent)
projectsService.deleteProject(id: string, userId: string, userRole: string): Promise<void>See lib/types/ for complete TypeScript definitions:
listing.types.ts- Listing and property typesproject.types.ts- Project typesuser.types.ts- User and authentication types
-
Push to GitHub
git push origin main
-
Import in Vercel
- Go to vercel.com
- Click "Add New Project"
- Import your GitHub repository
-
Configure Environment Variables
- Add all variables from
.env.localto Vercel Environment Variables - Set
NEXT_PUBLIC_FIREBASE_*variables
- Add all variables from
-
Deploy
- Vercel will automatically build and deploy
- Each push to main will trigger a new deployment
# Build the application
npm run build
# Start production server
npm start# Deploy Firestore rules
firebase deploy --only firestore:rules
# Deploy Storage rules
firebase deploy --only storage
# Deploy Hosting (if using Firebase Hosting)
firebase deploy --only hostingWe welcome contributions! Please see our Contributing Guide for details.
Important: This is a proprietary project. By contributing, you agree that your contributions will be licensed under the same license.
- Fork the repository (if you have access)
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
Please read our Code of Conduct before contributing.
All Rights Reserved
This software is proprietary and confidential. Unauthorized copying, transfer, or reproduction of this software, or any portion of it, by any means is strictly prohibited.
See LICENSE for full details.
For licensing inquiries, please contact: info@asanmanzil.vercel.app
- Website: asanmanzil.vercel.app
- Email: info@asanmanzil.vercel.app
- Phone: +93 772 654 965
- Address: Kabul, Afghanistan
- Next.js - The React Framework
- Firebase - Backend services
- Tailwind CSS - Utility-first CSS framework
- Vercel - Deployment platform
- Leaflet - Open-source JavaScript library for mobile-friendly interactive maps
Made with ❤️ in Afghanistan

