🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 24 Min Lesezeit
0

From Zero to Hero: My Journey Building a Property Rental Website and Mobile App

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




Contents




  1. Introduction

  2. Tech Stack

  3. Quick Overview

  4. Live demo

  5. API

  6. Frontend

  7. Mobile App

  8. Admin Dashboard

  9. Points of Interest

  10. Resources



Source code:






Introduction



The idea emerged from a desire to build without boundaries – a fully customizable and operational property rental website and mobile app where every aspect is within your control:





  • Own the UI/UX: Design unique customer experiences without fighting against template limitations


  • Control the Backend: Implement custom business logic and data structures that perfectly match the requirements


  • Master DevOps: Deploy, scale, and monitor the application with preferred tools and workflows


  • Extend Freely: Add new features and integrations without platform constraints or additional fees



Technical Requirements:





  • Payment Gateway:


    • Implement a secure, internationally supported payment gateway

    • Ensure compatibility across multiple countries and currencies








  • DevOps:


    • Deploy using Docker containers for consistency and scalability

    • Host on minimal infrastructure (1GB RAM server)

    • Maintain monthly hosting costs under $5 using providers like

    • Optimize resource usage for efficient operation











Tech Stack



Here's the tech stack that made it possible:




  • TypeScript

  • Node.js

  • MongoDB

  • React

  • MUI

  • React Native

  • Expo

  • Stripe

  • Docker



A key design decision was made to use TypeScript due to its numerous advantages. TypeScript offers strong typing, tooling, and integration, resulting in high-quality, scalable, more readable and maintainable code that is easy to debug and test.



I chose React for its powerful rendering capabilities, MongoDB for flexible data modeling, and Stripe for secure payment processing.



By choosing this stack, you're not just building a website and mobile app – you're investing in a foundation that can evolve with your needs, backed by robust open-source technologies and a growing developer community.



React stands out as an excellent choice due to its:




  1. Component-Based Architecture


    • Lets you break down complex UIs into smaller, reusable pieces

    • Makes code more maintainable and easier to test

    • Enables better code organization and reusability



  2. Virtual DOM Performance


    • React's virtual DOM efficiently updates only what's necessary

    • Results in faster page loads and better user experience

    • Reduces unnecessary re-renders



  3. Rich Ecosystem


    • Vast library of pre-built components

    • Extensive tooling

    • Large community for support and resources



  4. Strong Developer Experience


    • Hot reloading for immediate feedback

    • Excellent debugging tools

    • JSX makes writing UI code more intuitive



  5. Industry Support


    • Backed by Meta (formerly Facebook)

    • Used by many major companies

    • Continuous development and improvements



  6. Flexibility


    • Works well for both small and large applications

    • Can be integrated gradually into existing projects

    • Supports multiple rendering strategies (client-side, server-side, static)








Quick overview



In this section, you'll see the main pages of the frontend, the admin dashboard and the mobile app.






Frontend



From the frontend, the customer can search for available properties, choose a property and checkout.



Below is the main page of the frontend where the customer can a location point and time, and search for available properties.





Below is the page where the customer can view the details of the property:





Below is the checkout page where the customer can set rental options and checkout. If the customer is not registered, he can checkout and register at the same time. He will receive a confirmation and activation email to set his password if he is not registered yet.





Below is the sign up page.





Below is the page where the customer can see a booking in detail.





Below is the page where the customer can manage his settings.





That's it. That's the main pages of the frontend.






Admin Dashboard



Three types of users:




  • Admins: They have full access to the admin dashboard. They can do everything.

  • Agencies: They have limited access on the admin dashboard. They can only manage their properties, bookings and customers.

  • Customers: They have access to the frontend and the mobile app only. They cannot access the admin dashboard.



The platform is designed to work with multiple agencies. Each agency can manage its properties, customers and bookings from the admin dashboard. The platform can also work with only one agency as well.



From the backend, admins can create and manage agencies, properties, locations, customers and bookings.



When new agencies are created, they receive an email prompting them to create their account to access the admin dashboard so they can manage their properties, customers and bookings.



Below is the sign in page of the admin dashboard.





If the status of a booking changes, the related customer will receive a notification and an email.



Below is the page where properties are displayed and can be managed.





Below is the page where admins and agencies can edit properties.





Below is the page where to create bookings if the agency wants to create a booking from the admin dashboard. Otherwise, bookings are created automatically when the checkout process is completed from the frontend or the mobile app.





Below is the page where to manage agencies.





Below is the page where to edit agencies.





Below is the page where to see customer's bookings.





There are other pages but these are the main pages of the admin dashboard.



That's it. That's the main pages of the admin dashboard.






Live Demo






Frontend




  • URL:

  • Login:






    How to install the Mobile App on Android




    • On devices running Android 8.0 (API level 26) and higher, you must navigate to the Install unknown apps system settings screen to enable app installations from a particular location (i.e. the web browser you are downloading the app from).


    • On devices running Android 7.1.1 (API level 25) and lower, you should enable the Unknown sources system setting, found in Settings > Security on your device.







    Alternative Way



    You can also install the Android App by directly downloading the APK and installing it on any Android device.






    • The API exposes all functions needed for the admin dashboard, the frontend and the mobile app. The API follows the MVC design pattern. JWT is used for authentication. There are some functions that need authentication such as functions related to managing properties, bookings and customers, and others that do not need authentication such as retrieving locations and available properties for non authenticated users:




      • ./api/src/models/ folder contains MongoDB models.

      • ./api/src/routes/ folder contains Express routes.

      • ./api/src/controllers/ folder contains controllers.

      • ./api/src/middlewares/ folder contains middlewares.

      • ./api/src/config/env.config.ts contains the configuration and TypeScript type definitions.

      • ./api/src/lang/ folder contains localization.

      • ./api/src/app.ts is the main server where routes are loaded.

      • ./api/index.ts is the main entry point of the API.



      index.ts is the main entry point of the API:




      CODE
      import 'dotenv/config'
      import process from 'node:process'
      import fs from 'node:fs/promises'
      import http from 'node:http'
      import https, { ServerOptions } from 'node:https'
      import app from './app'
      import * as databaseHelper from './common/databaseHelper'
      import * as env from './config/env.config'
      import * as logger from './common/logger'

      if (
      await databaseHelper.connect(env.DB_URI, env.DB_SSL, env.DB_DEBUG)
      && await databaseHelper.initialize()
      ) {
      let server: http.Server | https.Server

      if (env.HTTPS) {
      https.globalAgent.maxSockets = Number.POSITIVE_INFINITY
      const privateKey = await fs.readFile(env.PRIVATE_KEY, 'utf8')
      const certificate = await fs.readFile(env.CERTIFICATE, 'utf8')
      const credentials: ServerOptions = { key: privateKey, cert: certificate }
      server = https.createServer(credentials, app)

      server.listen(env.PORT, () => {
      logger.info('HTTPS server is running on Port', env.PORT)
      })
      } else {
      server = app.listen(env.PORT, () => {
      logger.info('HTTP server is running on Port', env.PORT)
      })
      }

      const close = () => {
      logger.info('Gracefully stopping...')
      server.close(async () => {
      logger.info(`HTTP${env.HTTPS ? 'S' : ''} server closed`)
      await databaseHelper.close(true)
      logger.info('MongoDB connection closed')
      process.exit(0)
      })
      }

      ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => process.on(signal, close))
      }






      This is a TypeScript file that starts a server using Node.js and Express. It imports several modules including dotenv, process, fs, http, https, mongoose, and app. It then checks if the HTTPS environment variable is set to true, and if so, creates an HTTPS server using the https module and the provided private key and certificate. Otherwise, it creates an HTTP server using the http module. The server listens on the port specified in the PORT environment variable.



      The close function is defined to gracefully stop the server when a termination signal is received. It closes the server and the MongoDB connection, and then exits the process with a status code of 0. Finally, it registers the close function to be called when the process receives a SIGINT, SIGTERM, or SIGQUIT signal.



      app.ts is the main entry point of the api:




      CODE
      import express from 'express'
      import compression from 'compression'
      import helmet from 'helmet'
      import nocache from 'nocache'
      import cookieParser from 'cookie-parser'
      import i18n from './lang/i18n'
      import * as env from './config/env.config'
      import cors from './middlewares/cors'
      import allowedMethods from './middlewares/allowedMethods'
      import agencyRoutes from './routes/agencyRoutes'
      import bookingRoutes from './routes/bookingRoutes'
      import locationRoutes from './routes/locationRoutes'
      import notificationRoutes from './routes/notificationRoutes'
      import propertyRoutes from './routes/propertyRoutes'
      import userRoutes from './routes/userRoutes'
      import stripeRoutes from './routes/stripeRoutes'
      import countryRoutes from './routes/countryRoutes'
      import * as helper from './common/helper'

      const app = express()

      app.use(helmet.contentSecurityPolicy())
      app.use(helmet.dnsPrefetchControl())
      app.use(helmet.crossOriginEmbedderPolicy())
      app.use(helmet.frameguard())
      app.use(helmet.hidePoweredBy())
      app.use(helmet.hsts())
      app.use(helmet.ieNoOpen())
      app.use(helmet.noSniff())
      app.use(helmet.permittedCrossDomainPolicies())
      app.use(helmet.referrerPolicy())
      app.use(helmet.xssFilter())
      app.use(helmet.originAgentCluster())
      app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' }))
      app.use(helmet.crossOriginOpenerPolicy())

      app.use(nocache())
      app.use(compression({ threshold: 0 }))
      app.use(express.urlencoded({ limit: '50mb', extended: true }))
      app.use(express.json({ limit: '50mb' }))

      app.use(cors())
      app.options('*', cors())
      app.use(cookieParser(env.COOKIE_SECRET))
      app.use(allowedMethods)

      app.use('/', agencyRoutes)
      app.use('/', bookingRoutes)
      app.use('/', locationRoutes)
      app.use('/', notificationRoutes)
      app.use('/', propertyRoutes)
      app.use('/', userRoutes)
      app.use('/', stripeRoutes)
      app.use('/', countryRoutes)

      i18n.locale = env.DEFAULT_LANGUAGE

      helper.mkdir(env.CDN_USERS)
      helper.mkdir(env.CDN_TEMP_USERS)
      helper.mkdir(env.CDN_PROPERTIES)
      helper.mkdir(env.CDN_TEMP_PROPERTIES)
      helper.mkdir(env.CDN_LOCATIONS)
      helper.mkdir(env.CDN_TEMP_LOCATIONS)

      export default app






      First of all, we retrieve MongoDB connection string, then we establish a connection with MongoDB database. Then we create an Express app and load middlewares such as cors, compression, helmet, and nocache. We set up various security measures using the helmet middleware library. we also import various route files for different parts of the application such as supplierRoutes, bookingRoutes, locationRoutes, notificationRoutes, propertyRoutes, and userRoutes. Finally, we load Express routes and export app.



      There are 8 routes in the API. Each route has its own controller following the MVC design pattern and SOLID principles. Below are the main routes:




      • userRoutes: Provides REST functions related to users

      • agencyRoutes: Provides REST functions related to agencies

      • countryRoutes: Provides REST functions related to countries

      • locationRoutes: Provides REST functions related to locations

      • propertyRoutes: Provides REST functions related to properties

      • bookingRoutes: Provides REST functions related to bookings

      • notificationRoutes: Provides REST functions related to notifications

      • stripeRoutes: Provides REST functions related to Stripe payment gateway



      We are not going to explain each route one by one. We'll take, for example, propertyRoutes and see how it was made. You can browse the and see each one.






      Mobile App



      The platform provides a native mobile app for Android and iOS. The mobile app is built with React Native, Expo and TypeScript. Like for the frontend, the mobile app allows the customer to search for available cars depending on pickup and drop-off points and time, choose a car and proceed to checkout.



      The customer receives push notifications if his booking is updated from the backend. Push notifications are built with Node.js, Expo Server SDK and Firebase.




      • ./mobile/assets/ folder contains images.

      • ./mobile/screens/ folder contains main React Native screens.

      • ./mobile/components/ folder contains React Native components.

      • ./mobile/services/ contains api client services.

      • ./mobile/App.tsx is the main React Native App.



      TypeScript type definitions are defined in:




      • ./mobile/types/index.d.ts

      • ./mobile/types/env.d.ts

      • ./mobile/miscellaneous/movininTypes.ts



      ./mobile/types/ is loaded in ./mobile/tsconfig.json as follow:




      CODE
      {
      "extends": "expo/tsconfig.base",
      "compilerOptions": {
      "strict": true,
      "typeRoots": [
      "./types"
      ]
      }
      }






      App.tsx is the main entry point of the React Native app:




      CODE
      import 'react-native-gesture-handler'
      import React, { useCallback, useEffect, useRef, useState } from 'react'
      import { RootSiblingParent } from 'react-native-root-siblings'
      import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native'
      import { StatusBar as ExpoStatusBar } from 'expo-status-bar'
      import { SafeAreaProvider } from 'react-native-safe-area-context'
      import { Provider } from 'react-native-paper'
      import * as SplashScreen from 'expo-splash-screen'
      import * as Notifications from 'expo-notifications'
      import { StripeProvider } from '@stripe/stripe-react-native'
      import DrawerNavigator from './components/DrawerNavigator'
      import * as helper from './common/helper'
      import * as NotificationService from './services/NotificationService'
      import * as UserService from './services/UserService'
      import { GlobalProvider } from './context/GlobalContext'
      import * as env from './config/env.config'

      Notifications.setNotificationHandler({
      handleNotification: async () => ({
      shouldShowAlert: true,
      shouldPlaySound: true,
      shouldSetBadge: true,
      }),
      })

      //
      // Prevent native splash screen from autohiding before App component declaration
      //
      SplashScreen.preventAutoHideAsync()
      .then((result) => console.log(`SplashScreen.preventAutoHideAsync() succeeded: ${result}`))
      .catch(console.warn) // it's good to explicitly catch and inspect any error

      const App = () => {
      const [appIsReady, setAppIsReady] = useState(false)

      const responseListener = useRef<Notifications.Subscription>()
      const navigationRef = useRef<NavigationContainerRef<StackParams>>(null)

      useEffect(() => {
      const register = async () => {
      const loggedIn = await UserService.loggedIn()
      if (loggedIn) {
      const currentUser = await UserService.getCurrentUser()
      if (currentUser?._id) {
      await helper.registerPushToken(currentUser._id)
      } else {
      helper.error()
      }
      }
      }

      //
      // Register push notifiations token
      //
      register()

      //
      // This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
      //
      responseListener.current = Notifications.addNotificationResponseReceivedListener(async (response) => {
      try {
      if (navigationRef.current) {
      const { data } = response.notification.request.content

      if (data.booking) {
      if (data.user && data.notification) {
      await NotificationService.markAsRead(data.user, [data.notification])
      }
      navigationRef.current.navigate('Booking', { id: data.booking })
      } else {
      navigationRef.current.navigate('Notifications', {})
      }
      }
      } catch (err) {
      helper.error(err, false)
      }
      })

      return () => {
      Notifications.removeNotificationSubscription(responseListener.current!)
      }
      }, [])

      setTimeout(() => {
      setAppIsReady(true)
      }, 500)

      const onReady = useCallback(async () => {
      if (appIsReady) {
      //
      // This tells the splash screen to hide immediately! If we call this after
      // `setAppIsReady`, then we may see a blank screen while the app is
      // loading its initial state and rendering its first pixels. So instead,
      // we hide the splash screen once we know the root view has already
      // performed layout.
      //
      await SplashScreen.hideAsync()
      }
      }, [appIsReady])

      if (!appIsReady) {
      return null
      }

      return (
      <GlobalProvider>
      <SafeAreaProvider>
      <Provider>
      <StripeProvider publishableKey={env.STRIPE_PUBLISHABLE_KEY} merchantIdentifier={env.STRIPE_MERCHANT_IDENTIFIER}>
      <RootSiblingParent>
      <NavigationContainer ref={navigationRef} onReady={onReady}>
      <ExpoStatusBar style="light" backgroundColor="rgba(0, 0, 0, .9)" />
      <DrawerNavigator />
      </NavigationContainer>
      </RootSiblingParent>
      </StripeProvider>
      </Provider>
      </SafeAreaProvider>
      </GlobalProvider>
      )
      }

      export default App






      We are not going to cover each screen of the mobile app, but you can browse the and see each one.






      Points of Interest



      Building the mobile app with React Native and Expo is very easy. Expo makes mobile development with React Native very simple.



      Using the same language (TypeScript) for backend, frontend and mobile development is very convenient.



      TypeScript is a very interesting language and has many advantages. By adding static typing to JavaScript, we can avoid many bugs and produce high quality, scalable, more readable and maintainable code that is easy to debug and test.



      That's it! I hope you enjoyed reading this article.






      Resources



























        1. Logs


        Vollständiger Original-Bericht
        Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
        ↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
1 Quelle
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
1 Quelle
Major AI platforms go down in unprecedented simultaneous outage
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten From Zero to Hero: My Journey Building a Property Rental Website and Mobile App

Thematisch verwandte Begriffe: From, Zero, Hero, Journey · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...