DEV Community

Cover image for Build a Serverless, P2P Real Estate Application in One File with GenosDB
Esteban Fuster Pozzi
Esteban Fuster Pozzi

Posted on • Originally published at genosdb.com

Build a Serverless, P2P Real Estate Application in One File with GenosDB


Imagine building a real-time application where users can register with biometrics, publish secure data, share editing rights, and visualize geolocation on a map — all without deploying a backend server.In this tutorial, we are going to build dProp, a decentralized real estate marketplace. We will use GenosDB, a P2P database that runs entirely in the browser, to handle authentication, data storage, and real-time synchronization.By the end of this guide, you will have a single-file HTML application with:- Real-time updates (Reactive UI).- Biometric Authentication (WebAuthn).- Granular Access Control (ACLs) for collaborative editing.- Dark Mode support.

The Stack

- Frontend: Vanilla JS + HTML5.- Styling: TailwindCSS (via CDN).- Maps: Leaflet.js.- DB: GenosDB (P2P, Client-side).

Step 1: The Setup

We start with a basic HTML5 structure. Because GenosDB is modular and efficient, we can build this entire app in a single file using ES modules.HTML

                import { gdb } from "https://cdn.jsdelivr.net/npm/genosdb@latest/dist/index.min.js";        // Application logic will go here        
Enter fullscreen mode Exit fullscreen mode

We add a simple Dark Mode toggle script that checks localStorage or system preferences to apply the .dark class to the HTML tag.

Step 2: Initializing the P2P Database

To make our app “Real-time” and “Secure,” we need to initialize GenosDB with specific modules enabled.JavaScript

const APP_ROLES = {    admin: { can: ["deleteAny"], inherits: ["user"] },    user: { can: ["write", "link"], inherits: ["guest"] },    guest: { can: ["read"] }};async function initApp() {    // Initialize GenosDB    db = await gdb("dprop-v2", {        rtc: true, // Enables WebRTC for P2P sync        sm: {            superAdmins: ["0x..."], // Required for boot            customRoles: APP_ROLES,            acls: true // Enables Node-Level Permissions        }    });    // Reactive Auth Listener    db.sm.setSecurityStateChangeCallback(updateAuthUI);}
Enter fullscreen mode Exit fullscreen mode

What’s happening here?- rtc: true: Activates the P2P layer so browsers can exchange data directly.- sm** (Security Manager): Activates the cryptographic identity system. Users are identified by Ethereum addresses, not database IDs.- **acls: true: This is crucial. It enables Access Control Lists, allowing us to define exactly who can edit a specific property.

Step 3: Biometric Authentication (No Passwords!)

Forget storing hashed passwords. We use GenosDB’s built-in Identity Management to generate a cryptographic wallet and protect it with WebAuthn (FaceID, TouchID).JavaScript

// 1. Generate a new Identity (Mnemonic based)window.generateIdentity = async () => {    const id = await db.sm.startNewUserRegistration();    // Display id.mnemonic to the user securely};// 2. Protect it with Biometricswindow.protectIdentity = async () => {    await db.sm.protectCurrentIdentityWithWebAuthn();    // The private key is now encrypted with the device's hardware security module};// 3. Loginwindow.loginWebAuthn = async () => {    await db.sm.loginCurrentUserWithWebAuthn();};
Enter fullscreen mode Exit fullscreen mode

When a user logs in, db.sm signs every database operation they perform. This guarantees data authenticity without a server verifying sessions.

Step 4: Publishing Secure Data with ACLs

When a user publishes a house, we don’t just dump JSON into the DB. We use ACLs (Access Control Lists) to ensure only the owner can edit it later.JavaScript

const propertyData = {    type: 'Property',    title: 'Luxury Villa',    price: 500000,    owner: currentUserAddress, // Stored for UI logic    status: 'available'};// Save with ACL protectionawait db.sm.acls.set(propertyData);
Enter fullscreen mode Exit fullscreen mode

By using db.sm.acls.set, the node is created, and the creator is automatically assigned Owner privileges (Read, Write, Delete). Any attempt by another peer to modify this node will be rejected by the P2P validation middleware.

Step 5: The “Magic” Real-Time Stream

This is the heart of dProp. We want the UI to update instantly when anyone changes a property status or adds a listing. We use db.map() in realtime mode.JavaScript

async function performSearch() {    // 1. Define Query    const query = { type: 'Property', status: { $ne: 'deleted' } };// 2. Subscribe to changes    const { unsubscribe } = await db.map({        query: query,        realtime: true, //  {        // This callback fires on 'initial', 'added', 'updated', or 'removed'        handleRealtimeUpdate(id, value, action);    });}
Enter fullscreen mode Exit fullscreen mode

How it works:- realtime: true: Keeps the connection open.- action: Tells us if a node was added, updated, or removed.- Cursor Pagination: We can use $after to implement "Load More" functionality without re-fetching the whole list.

Step 6: Collaborative Editing (Sharing Access)

A unique feature of dProp is allowing owners to share write access with other users (e.g., a real estate agent).JavaScript

window.confirmShare = async () => {    const propertyId = document.getElementById('share-node-id').value;    const collaboratorAddress = document.getElementById('share-address').value;// Grant 'write' permission to the specific address    await db.sm.acls.grant(propertyId, collaboratorAddress, 'write');    // Update metadata so the UI knows this person is a collaborator    const { result: node } = await db.get(propertyId);    node.value.collaborators[collaboratorAddress] = 'write';    await db.sm.acls.set(node.value, propertyId);};
Enter fullscreen mode Exit fullscreen mode

Now, the collaborator’s browser will validate that they have permission to edit the property, and the network will accept their signed updates.

Step 7: Atomic UI Updates

To ensure the app feels like a native 60fps experience, we don’t reload the page. We perform surgical DOM updates in our callback.JavaScript

function handleRealtimeUpdate(id, value, action) {    const existingCard = document.getElementById(`card-${id}`);    const newCard = createCardHTML({ id, ...value }); // Generate HTML string        if (action === 'removed') {        existingCard?.remove();    } else if (existingCard) {        // Atomic Replacement: Update status/price instantly        existingCard.replaceWith(newCard);     } else {        // Append new item        grid.appendChild(newCard);    }        // Update Map Marker concurrently    updateMapMarker({ id, ...value });}
Enter fullscreen mode Exit fullscreen mode

This logic handles everything: initial load, price changes, status updates (Available -> Sold), and deletion.

What You Built

We just built a Full-Stack application using only frontend code.- Database? Local & P2P (GenosDB).- Auth? Cryptographic & Biometric (Security Manager).- API? None (Direct Peer Sync).This architecture drastically reduces infrastructure costs and increases data resilience. dProp isn’t just a demo; it’s a glimpse into the future of serverless, decentralized web applications.

Resources

- GenosDB Documentation- Live Demo- Full Source Code (GitHub)


This article is part of the official documentation of GenosDB (GDB).
GenosDB is a distributed, modular, peer-to-peer graph database built with a Zero-Trust Security Model, created by Esteban Fuster Pozzi (estebanrfp).

📄 Whitepaper | overview of GenosDB design and architecture

🛠 Roadmap | planned features and future updates

💡 Examples | code snippets and usage demos

📖 Documentation | full reference guide

🔍 API Reference | detailed API methods

📚 Wiki | additional notes and guides

💬 GitHub Discussions | community questions and feedback

🗂 Repository | Minified production-ready files

📦 Install via npm | quick setup instructions

🌐 Website | GitHub | LinkedIn

Top comments (0)