# SweetHome — Full Project Analysis **Project:** SweetHome Next.js Real Estate Application **Date:** June 16, 2026 **Framework:** Next.js 16.1.6 (App Router) + React 18.3.1 **Language:** JavaScript (no TypeScript) **Styling:** Tailwind CSS v4 + DaisyUI (unused) + Flowbite (unused) **API:** Custom `.NET` backend at `https://45.93.137.91.nip.io/api` --- ## 1. Project Structure ### Directory Tree (Top 3 Levels) ``` SweetHome/ ├── .gitea/workflows/ # CI/CD deployer ├── app/ # ★ MAIN APP (112 source files) │ ├── account-verification/ # OTP email/phone verification │ ├── auth/choose-role/ # Owner/Tenant/Agent role picker │ ├── blocked/ # Blocked account page │ ├── booked-properties/ # User's booked properties │ ├── change-password/ # Change password form │ ├── components/ # ★ 14 reusable components │ │ ├── home/ # HeroSearch, PropertyMap │ │ ├── property/ # BookingCalendar, PropertyMap │ │ ├── ratings/ # StarRating, PropertyRatingForm, etc. │ │ ├── BottomNav.js # Mobile bottom nav │ │ ├── FloatingSidebar.js # Desktop floating sidebar │ │ ├── NavLinks.js # Nav link atoms │ │ ├── NotificationHandler.js # Firebase FCM handler │ │ └── PropertyMapWithMarkers.js # Standalone Leaflet map │ ├── contexts/ # ★ 3 context providers │ │ ├── FavoritesContext.js │ │ ├── NotificationsContext.js │ │ └── PropertyContext.js # ORPHANED (never mounted) │ ├── enums/ # 20 enum constant files │ ├── faq/ # FAQ accordion page │ ├── favorites/ # Favorites list page │ ├── forgot-password/ # 3-step forgot password │ ├── i18n/ # i18next config (Arabic/English) │ ├── login/ # 2-step login (credential + OTP) │ ├── my-rates/ # Ratings received from owners │ ├── notifications/ # Notifications list page │ ├── onboarding/ # 3-step intro wizard │ ├── owner/ # ★ Owner dashboard (6 sub-routes) │ │ ├── account-book/ # Financial dashboard │ │ ├── bookings/ # Booking management │ │ ├── calendar/ # Monthly calendar view │ │ ├── profits/ # Revenue/profit stats │ │ ├── properties/ # CRUD property management │ │ └── reservations/ # Reservation requests │ ├── payments/ # Deposit payment page │ ├── privacy/ # Privacy policy │ ├── profile/ # User profile CRUD │ ├── properties/ # Property listings grid │ ├── property/[id]/ # Property detail (dynamic route) │ ├── register/ # Registration (tenant/owner/agent) │ ├── reports/ # 3-tab report submission │ ├── reservations/ # Customer reservations │ ├── services/ # AuthService.js │ ├── settings/ # Account settings │ ├── support/ # Support contact form │ ├── terms/ # Terms of service │ ├── utils/ # ★ api.js, calculations, firebase, etc. │ ├── ClientLayout.js # Client layout shell (804 lines) │ ├── layout.js # Root server layout │ ├── globals.css # Tailwind + custom fonts │ ├── page.js # Home page │ ├── error.js # Error boundary │ ├── loading.js # Loading state │ └── not-found.js # 404 page ├── public/ # Static files (fonts, images, APK) │ ├── files/SweetHome.apk # Android APK │ ├── fonts/ # Madani Arabic (woff2 + ttf) │ └── firebase-messaging-sw.js # FCM service worker ├── package.json # 18 prod + 7 dev dependencies ├── next.config.mjs # Next.js config ├── postcss.config.mjs # PostCSS + Tailwind ├── jsconfig.json # Path aliases (@/* → ./) └── security-audit-report.md # Previous security audit ``` ### Route Summary (33 pages) | Type | Routes | Count | |------|--------|-------| | Public | `/`, `/login`, `/register/*`, `/forgot-password`, `/auth/choose-role`, `/properties`, `/property/[id]`, `/terms`, `/privacy`, `/faq`, `/support`, `/onboarding` | 14 | | Protected (auth only) | `/profile`, `/settings`, `/change-password`, `/account-verification`, `/favorites`, `/booked-properties`, `/reservations`, `/notifications`, `/payments`, `/my-rates`, `/reports`, `/blocked` | 12 | | Owner only | `/owner/properties`, `/owner/properties/add`, `/owner/reservations`, `/owner/bookings`, `/owner/calendar`, `/owner/profits`, `/owner/account-book` | 7 | --- ## 2. Architecture Overview ### Layout Hierarchy ``` app/layout.js (Server Component — root HTML, fonts, metadata) └── app/ClientLayout.js (Client Component — 804 lines) ├── (context) │ └── (context) │ └──
{children}
├── (mobile, authenticated only) └── (FCM push notifications) ``` - **No nested layouts** — flat route structure - **No `middleware.js`** — all route protection is client-side only - Nav bar hidden on auth pages (`/login`, `/register/*`, `/blocked`, `/forgot-password`, `/auth/choose-role`) ### Data Flow Pattern ``` Page (useEffect on mount) → API call (apiFetch from app/utils/api.js) → AuthService.getToken() → Authorization: Bearer → fetch() to https://45.93.137.91.nip.io/api/{endpoint} → Response: auto-unwrap { data: ... } envelope → Return parsed data or throw on non-ok → Component state (useState) → Render UI with Tailwind classes ``` --- ## 3. API Layer **File:** `app/utils/api.js` (1198 lines — 370 commented legacy + 828 active) **Ratings API:** `app/utils/ratings.js` (separate file with own `apiFetch`) ### Fetch Helpers | Function | Lines | Method | Auth | Error Handling | Return Type | |----------|-------|--------|------|----------------|-------------| | `apiFetch(endpoint, options)` | 421-478 | Any | Auto Bearer | Throws on non-ok (except 206) | `data` (auto-unwrapped) | | `authFetch(endpoint, body, token)` | 483-524 | POST | Manual param | Returns `{status,data,ok,message}` | Object | | `reportFetch(endpoint, body)` | 526-558 | POST | None | Returns `{status,data,ok,message}` | Object | | `multipartAuthFetch(endpoint, formData)` | 772-803 | POST | Auto Bearer | Returns `{status,data,ok,message}` | Object | ### Exported API Functions (47 total) | Category | Functions | Count | |----------|-----------|-------| | Rent Properties | `getRentProperties`, `getRentProperty`, `getRentPropertyLocations`, `filterRentProperties` | 4 | | Sale Properties | `getSaleProperties`, `getSaleProperty`, `getSalePropertyById` | 3 | | Generic Property | `getProperty` | 1 | | Recommendations | `getRecommendations`, `getTopRecommendations` | 2 | | Reservations | `getAvailableDateRanges`, `getReservations`, `getReservation`, `checkAvailability`, `bookReservation`, `getUserReservations`, `getOwnerReservationRequests`, `getOwnerReservationsByStatuses`, `ownerConfirmReservation`, `confirmDepositPayment`, `adminConfirmDeposit`, `updateBookingStatus`, `payDeposit` | 13 | | Owner Management | `getMyRentListings`, `getMySaleListings`, `addRentProperty`, `addSaleProperty`, `editRentProperty`, `editSaleProperty`, `updateRentPropertyStatus`, `updateSalePropertyStatus`, `getOwnerContactInformation`, `getOwnerStatistics` | 10 | | Auth | `loginWithEmail`, `loginWithPhone`, `sendEmailOTP`, `sendPhoneOTP`, `verifyEmail`, `verifyPhone`, `changePassword`, `requestForgetPasswordOtp`, `verifyForgetPasswordOtp`, `resetPassword`, `deleteMyAccount` | 11 | | Registration | `addOwner`, `addCustomer`, `registerRealEstateAgent` | 3 | | Favorites | `getUserFavoriteProperties`, `addFavoriteProperty`, `removeFavoriteProperty` | 3 | | Notifications | `getUserNotifications`, `setFCMToken` | 2 | | Terms | `getARTerms`, `getENTerms`, `addOrUpdateTerms` | 3 | | Currencies | `getCurrencies` | 1 | | Files | `uploadPicture` | 1 | | Reports | `sendGeneralReport`, `submitReport`, `submitReservationReport`, `updateReservationReport`, `submitSaleReport`, `updateSaleReport` | 6 | | Profile | `getCustomerByUserId`, `getOwnerByUserId` | 2 | ### Ratings API (5 functions) `addPropertyRating`, `addCustomerRating`, `getPropertyRatings`, `getCustomerRatings`, `getPropertyAverageRating` ### API Endpoint Coverage | HTTP Method | Count | Examples | |-------------|-------|----------| | GET | 26 | `/RentProperties/GetRentProperties`, `/Reservations/GetAvailableDates/available/${id}` | | POST | 17 | `/Auth/LogInWithEmail`, `/Reservations/PayDeposit/pay-deposit`, `/Rating/AddPropertyRating` | | PUT | 8 | `/RentProperties/EditRentProperty/${id}`, `/Reservations/AdminConfirmDeposit/admin-confirm-deposit` | | DELETE | 2 | `/FavoriteProperty/Remove`, `/User/DeleteMyAccount` | --- ## 4. State Management ### Context Providers | Context | File | State | Consumers | Status | |---------|------|-------|-----------|--------| | **FavoritesProvider** | `app/contexts/FavoritesContext.js` | `favorites[]`, `isLoading` | `FloatingSidebar`, `/favorites`, `/properties`, `/property/[id]` | ✅ Active | | **NotificationsProvider** | `app/contexts/NotificationsContext.js` | `notifications[]`, `unreadCount`, `isLoading` | `BottomNav`, `FloatingSidebar` | ✅ Active | | **PropertyContext** | `app/contexts/PropertyContext.js` | `properties[]`, `loading`, `error` | None | ❌ Orphaned (never mounted) | | **PropertyContext** | `app/utils/PropertyContext.js` | Same as above | None | ❌ Orphaned duplicate | ### localStorage Keys (10 actively written, ~5 legacy read-only) | Key | Data | Written By | Read By | |-----|------|------------|---------| | `auth_token` | JWT string | `AuthService.addToken()` | `AuthService.getToken()`, `firebase.js` | | `cached_user` | User profile JSON | `AuthService.cacheUser()` | `AuthService.getCachedUser()` | | `language` | "en" or "ar" | `ClientLayout.js` | `ClientLayout.js` | | `sweethome_onboarding_completed` | "true" | `/onboarding/page.js` | `/onboarding/page.js` | | `ownerProperties` | Properties array JSON | `/owner/properties/page.js` | `/owner/calendar/page.js` | | `ownerBookings` | Bookings array JSON | `/owner/bookings/page.js` | `/owner/bookings/page.js` | | `ownerProfitsTable` | Profit data JSON | `/owner/profits/page.js` | `/owner/profits/page.js` | | `userProfile` | Profile form data JSON | `/profile/page.js` | `/profile/page.js` | | `userAvatar` | Base64 data URL | `/profile/page.js` | `/profile/page.js` | | `token`, `accessToken`, `authToken` | (legacy reads only) | — | `/settings`, `/payments`, `/reservations` | ### Auth Flow ``` Login (app/login/page.js) → loginWithEmail() / loginWithPhone() → authFetch(POST /Auth/LogInWithEmail, { credential, password, device: 0 }) → 200: AuthService.addToken(token) → localStorage.setItem('auth_token', token) → 206: OTP required → sendEmailOTP() → verifyEmail(code) → get final token → AuthService.cacheUser(user) → localStorage.setItem('cached_user', ...) → router.push('/') ClientLayout.js (every page navigation) → AuthService.getUser() → decode JWT payload (base64 atob) → setUser({ name, email, phone, role: isOwner() ? 'owner' : 'customer' }) → UI branches on user.role (show owner nav / customer nav / guest nav) Page-level checks → Each protected page independently calls: AuthService.isAuthenticated() → else router.push('/login') AuthService.isOwner() → else router.push('/') ``` --- ## 5. Component Architecture ### Component Inventory (14 reusable components) | Component | File | Lines | Purpose | State | |-----------|------|-------|---------|-------| | HeroSearch | `components/home/HeroSearch.js` | 321 | Hero search with filters | `filters`, login dialog | | PropertyMap (home) | `components/home/PropertyMap.js` | 287 | Map with markers + popup | `selectedProperty`, map ref | | PropertyMap (property) | `components/property/PropertyMap.js` | 166 | Map at property detail | Tooltip state | | BookingCalendar | `components/property/BookingCalendar.js` | 124 | Monthly booking grid | `currentMonth`, `selectedStart` | | PropertyMapWithMarkers | `components/PropertyMapWithMarkers.js` | 100 | Generic Leaflet map | Map ref, markers ref | | StarRating | `components/ratings/StarRating.js` | 134 | 5-star input | `hoverRating` | | PropertyRatingList | `components/ratings/PropertyRatingList.js` | 286 | Paginated reviews | `ratings`, `page`, `loading` | | PropertyRatingForm | `components/ratings/PropertyRatingForm.js` | 317 | 4-field rating form | Clean/services/owner/experience | | CustomerRatingForm | `components/ratings/CustomerRatingForm.js` | 92 | 3-field rating form | Furn/terms/behavior | | BottomNav | `components/BottomNav.js` | 58 | Mobile bottom bar | Badge from context | | FloatingSidebar | `components/FloatingSidebar.js` | 158 | Quick-access buttons | Framer-motion variants | | NavLinks | `components/NavLinks.js` | 42 | Nav link atoms | `usePathname` active | | NotificationHandler | `components/NotificationHandler.js` | 151 | FCM push handler | Permission state | ### Largest Page Files | Rank | File | Lines | Complexity | |------|------|-------|------------| | 1 | `api.js` | 1198 | 60+ functions, 4 fetch helpers, 370 lines commented | | 2 | `PropertyDetail.js` | 1743 | 56 imports, 8+ state vars, booking calendar, image gallery, owner check, ratings, map | | 3 | `owner/properties/page.js` | 2057 | CRUD + modals + localStorage caching + API calls | | 4 | `ClientLayout.js` | 804 | Nav (desktop+mobile), user menu, language switcher, context providers | | 5 | `owner/properties/add/page.js` | 700+ | Multi-step form with map, image upload, pricing | | 6 | `app/page.js` (Home) | 623 | Property fetching, multi-filter, hero, map, feature cards | --- ## 6. Key Patterns ### Data Fetching (4 Patterns) | Pattern | Usage | Found In | |---------|-------|----------| | `useEffect` + `useState` | ~90% of pages | Most pages | | Context-level fetch | 2 providers | `FavoritesContext`, `NotificationsContext` | | localStorage cache | Owner dashboards | `owner/bookings`, `owner/calendar`, `owner/profits` | | Mock data fallback | 3 owner pages | `owner/bookings`, `owner/calendar`, `owner/profits` | ### Styling - 100% Tailwind CSS v4 (utility classes, no CSS modules) - Custom `globals.css`: Madani Arabic fonts (9 weights), Leaflet overrides, keyframe animations - Color palette: `amber-500/600` (primary), `#ede6e6` (bg), `#156874` (accent teal) - RTL-first with dynamic LTR switching via `currentLanguage` state ### Animations (Framer Motion v12.29.2) - `initial/animate` opacity + y/x translations (section reveals) - `whileHover`/`whileTap` scale (buttons, interactive elements) - `AnimatePresence` (property popups, user menus) - `whileInView` + `viewport` (scroll-triggered animations on home page) - `staggerChildren` (hero text) - Spring transitions `{ type: "spring", damping: 25, stiffness: 300 }` ### Form Handling - **All forms**: Controlled `useState` — no React Hook Form, Formik, or `useReducer` - **Validation**: Inline `value === 0 &&

مطلوب

` - **No form libraries** — all hand-rolled ### Responsive Breakpoints | Breakpoint | Layout | |------------|--------| | Default (mobile) | Single column, BottomNav, hamburger menu | | `md:` (768px) | Desktop nav, 2-3 column grids | | `lg:` (1024px) | PropertyDetail sidebar, 3-column grids | --- ## 7. Owner Pages Analysis (Dashboard Section) | Route | File | Lines | Status | Data Source | |-------|------|-------|--------|-------------| | `/owner/properties` | `owner/properties/page.js` | 2057 | ✅ Active | API (`getMyRentListings`, `getMySaleListings`) + localStorage cache | | `/owner/properties/add` | `owner/properties/add/page.js` | 700+ | ✅ Active | API (`addRentProperty`, `addSaleProperty`, `uploadPicture`) | | `/owner/reservations` | `owner/reservations/page.js` | 1400+ | ❌ Commented out | Mock data (commented) | | `/owner/bookings` | `owner/bookings/page.js` | 560+ | ⚠️ Demo | localStorage mock data only | | `/owner/calendar` | `owner/calendar/page.js` | 580+ | ⚠️ Demo | localStorage mock data only | | `/owner/profits` | `owner/profits/page.js` | 600+ | ⚠️ Demo | localStorage mock data only | | `/owner/account-book` | `owner/account-book/page.js` | 500+ | ✅ Active | API (`getOwnerStatistics`) | --- ## 8. Admin Functionality | Component | Status | Data Source | |-----------|--------|-------------| | BookingRequests | ✅ Active | Real API (`getReservations`, `adminConfirmDeposit`) | | Users | ❌ Not implemented | — | | Properties | ❌ Not implemented | — | | LedgerBook | ⚠️ Mock only | 3 hardcoded mock transactions | | Dashboard | ❌ Not implemented | — | Designed for internal admin use at `/admin` — tabs for Bookings/Users/Properties/Ledger/Dashboard. --- ## 9. Known Technical Debt ### Dead Code | File | Dead Lines | Issue | |------|-----------|-------| | `api.js` | Lines 1-370 (370 lines) | Entire legacy version commented out | | `StarRating.js` | Lines 1-93 (93 lines) | Old framer-motion version commented out | | `PropertyRatingList.js` | ~150 lines | Old version commented out | | `PropertyRatingForm.js` | ~220 lines | Old version commented out | | `contexts/PropertyContext.js` | Entire file | Never mounted | | `utils/PropertyContext.js` | Entire file | Duplicate orphan | ### Code Duplication | Pattern | Files | Description | |---------|-------|-------------| | Leaflet maps | 3 separate files | `PropertyMapWithMarkers.js`, `home/PropertyMap.js`, `property/PropertyMap.js` — all setup Leaflet identically | | Rating forms | `PropertyRatingForm.js` (317) + `CustomerRatingForm.js` (92) | ~75% code overlap; both define identical `RatingField` inline | | formatCurrency | 4+ locations | Scattered across files with slightly different logic | | Image URL building | 4+ locations | Different implementations for same task | | Notifications page | `/notifications/page.js` vs `NotificationsContext` | Page duplicates all context state/logic | ### Architecture Issues | Issue | Impact | |-------|--------| | No middleware.js | All route protection is client-side only | | JWT in localStorage | XSS-vulnerable token storage | | Client-side role checks | Users can modify JWT to elevate privileges | | Owner pages use mock data | `/owner/bookings`, `/owner/calendar`, `/owner/profits` are demo-only | | 3 unused UI libraries | DaisyUI, Flowbite, Yandex Maps imported but never used | | No TypeScript | 112 JS files, no type safety | | No ESLint | No linting configured | | No testing framework | Zero tests | | Flat route structure | No nested layouts; all pages share root layout | | Active console.log | ~30+ files with console.log statements (security risk) | --- ## 10. Dependencies ### Production (18) | Package | Version | Purpose | |---------|---------|---------| | next | 16.1.6 | Framework | | react / react-dom | ^18.3.1 | UI | | firebase | ^12.11.0 | FCM push notifications | | leaflet / react-leaflet | 1.9.4 / 4.2.1 | Maps | | @pbe/react-yandex-maps | ^1.2.5 | Yandex Maps (unused) | | framer-motion | ^12.29.2 | Animations | | lucide-react | ^0.563.0 | Icons | | flowbite / flowbite-react | 4.0.1 / 0.12.16 | UI library (unused) | | react-hot-toast | ^2.6.0 | Toasts | | i18next / react-i18next / i18next-browser-languagedetector | 25.8 / 16.5 / 8.2 | i18n | | jspdf / html2canvas | 4.2.1 / 1.4.1 | PDF generation | | xlsx | ^0.18.5 | Excel export | | react-intersection-observer | ^10.0.3 | Scroll detection | ### Dev (7) | Package | Version | Purpose | |---------|---------|---------| | tailwindcss | ^4.1.18 | CSS framework | | @tailwindcss/postcss | ^4 | PostCSS plugin | | postcss / autoprefixer | ^8.5.6 / ^10.4.23 | CSS processing | | daisyui | ^5.5.14 | UI components (unused) | | babel-plugin-react-compiler | 1.0.0 | React compiler optimization | ### Missing (notable absences) - No TypeScript - No ESLint - No testing (Jest, Playwright, Cypress) - No state management library (Redux, Zustand) - No data fetching library (React Query, SWR) - No form library (React Hook Form, Formik) - No security lib (helmet, cors, csurf) - No HTTP client (axios, ky) - No JWT lib (jsonwebtoken, jose) --- ## 11. Security Summary *(See `security-audit-report.md` for full details)* | # | Finding | Severity | |---|---------|----------| | 1 | JWT in localStorage (XSS-theft) | 🔴 Critical | | 2 | Stored XSS via Leaflet popup HTML | 🔴 Critical | | 3 | OTP code logged to console | 🔴 Critical | | 4 | No server-side middleware | 🔴 Critical | | 5 | Passwords in URL query params | 🔴 Critical | | 6 | IDOR on property edit/status APIs | 🔴 Critical | | 7 | Client-only role checks | 🟠 High | | 8 | HTTP endpoints leak tokens | 🟠 High | | 9 | No CSP/security headers | 🟠 High | | 10 | Mass assignment via spread | 🟠 High | | 11 | Error messages leak internals | 🟠 High | | 12 | Hardcoded IPs (10+ files) | 🟡 Medium | --- ## 12. File Size Heatmap | Size Range | Files | Examples | |------------|-------|----------| | 1500-2100 lines | 2 | `PropertyDetail.js` (1743), `owner/properties/page.js` (2057) | | 600-1200 lines | 6 | `api.js` (1198), `ClientLayout.js` (804), `login/page.js` (800+), `owner/properties/add/page.js` (700+), `app/page.js` (623), `owner/bookings/page.js` (560+) | | 200-600 lines | 15 | Most page files | | < 200 lines | ~70 | Enum files, smaller components, error/loading pages |