<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aldo Montenegro</title>
    <description>The latest articles on DEV Community by Aldo Montenegro (@aldomontenegro).</description>
    <link>https://dev.to/aldomontenegro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3837558%2F7bd53f2a-a33a-46ec-af97-d51b0199913c.jpg</url>
      <title>DEV Community: Aldo Montenegro</title>
      <link>https://dev.to/aldomontenegro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aldomontenegro"/>
    <language>en</language>
    <item>
      <title>Replacing 5 Tools with 1: Building an All-in-One Condo Management Platform for the Mexican Market</title>
      <dc:creator>Aldo Montenegro</dc:creator>
      <pubDate>Sat, 21 Mar 2026 20:03:59 +0000</pubDate>
      <link>https://dev.to/aldomontenegro/replacing-5-tools-with-1-building-an-all-in-one-condo-management-platform-for-the-mexican-market-1d7g</link>
      <guid>https://dev.to/aldomontenegro/replacing-5-tools-with-1-building-an-all-in-one-condo-management-platform-for-the-mexican-market-1d7g</guid>
      <description>&lt;p&gt;Managing a residential building in Mexico today looks something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Communication:&lt;/strong&gt; A WhatsApp group with 200 residents where important announcements get buried under memes and complaints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finances:&lt;/strong&gt; An Excel spreadsheet that only the administrator understands, shared as an email attachment once a month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access control:&lt;/strong&gt; A paper logbook at the guard booth, where visitors sign their name illegibly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Bank transfers with no automatic reconciliation, or cash collected in person&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance requests:&lt;/strong&gt; Verbal complaints to the guard who may or may not pass them along&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not an exaggeration. This is the reality for the vast majority of the 65,000+ residential condominiums in Mexico.&lt;/p&gt;

&lt;p&gt;We built &lt;a href="https://www.popservices.net" rel="noopener noreferrer"&gt;AdminCondo&lt;/a&gt; to replace all of it with a single platform — a web admin panel for building managers and a mobile app for residents and security guards.&lt;/p&gt;

&lt;p&gt;Here's what we learned building SaaS for a market that mostly runs on WhatsApp.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Was Solving Well
&lt;/h2&gt;

&lt;p&gt;Property management software exists. There are global players like Buildium and AppFolio. But they are built for the US rental market: single landlords managing scattered properties, collecting rent in USD via ACH, sending English-language communications.&lt;/p&gt;

&lt;p&gt;The Mexican condominium market has fundamentally different needs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The legal structure is different.&lt;/strong&gt; Mexican condos are governed by owner assemblies with elected board members, mandatory reserve funds, and specific rules under each state's condominium law.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Payment infrastructure is different.&lt;/strong&gt; Mexico runs on SPEI (the interbank electronic payment system) and bank transfers, not credit cards. Residents pay their maintenance fees by transferring to the condo's bank account, then telling the administrator they paid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Invoicing has specific requirements.&lt;/strong&gt; Mexican tax law requires CFDI — standardized electronic invoices validated by the government's tax authority (SAT). If a resident wants a tax-deductible receipt, the condo must issue a CFDI 4.0 compliant invoice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Security is physical, not digital.&lt;/strong&gt; Mexican residential buildings have security guards 24/7. Access control isn't about smart locks — it's about a guard at a booth who needs to verify visitors, call residents for authorization, and keep a log.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Built
&lt;/h2&gt;

&lt;p&gt;AdminCondo has three components: a Node.js/Express backend with PostgreSQL, a React web dashboard for administrators, and a React Native mobile app for residents and security guards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Financial Management That Understands Mexican Condos
&lt;/h3&gt;

&lt;p&gt;We built a financial module that handles maintenance charges, extraordinary charges, payment recording and reconciliation, CFDI invoicing via Facturama's API, late fee automation, a real-time collection dashboard, and categorized expense tracking with petty cash management.&lt;/p&gt;

&lt;p&gt;The key insight was that payments in Mexican condos don't follow a subscription model. They follow a charge-and-collection model. We generate charges and then record payments that get applied against those charges through a many-to-many relationship.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access Control Built Around the Guard Booth
&lt;/h3&gt;

&lt;p&gt;Instead of trying to replace the security guard with technology, we built technology that makes the guard more effective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visitor QR codes:&lt;/strong&gt; Residents generate a single-use QR code through the app. The guard scans it, the system verifies it, logs the entry, and optionally triggers elevator access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VoIP intercom:&lt;/strong&gt; When an unexpected visitor arrives, the guard calls the resident directly through the app using WebRTC. On iOS, incoming calls show the native phone UI through CallKit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication That Isn't WhatsApp
&lt;/h3&gt;

&lt;p&gt;We replaced WhatsApp chaos with structured channels: announcements with push notifications, direct messaging, polls for assembly voting, and maintenance request tracking with photos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons from Building SaaS for the Mexican Market
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Spanish-First Isn't Just Translation
&lt;/h3&gt;

&lt;p&gt;Every string was written in Spanish first. Date formats, currency formatting, address formats — all need to be native. Even UX patterns are different.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. You're Competing with "Good Enough"
&lt;/h3&gt;

&lt;p&gt;WhatsApp groups cost nothing. Excel is already installed. Your biggest competitor isn't another SaaS product — it's the inertia of free tools that sort-of-work. The only way to win is to solve a pain point that free tools genuinely cannot.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Onboarding Must Be Ruthlessly Simple
&lt;/h3&gt;

&lt;p&gt;We rebuilt onboarding as a 4-step wizard that takes under 10 minutes for a 50-unit building. We also added bulk operations early — an administrator managing 200 units is not going to create them one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Multi-Tenancy Is Table Stakes
&lt;/h3&gt;

&lt;p&gt;Many property management companies manage multiple condominiums. We implemented multi-tenancy with JWT-based condo switching — same login, select which building you're managing.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Government Compliance Is a Moat
&lt;/h3&gt;

&lt;p&gt;CFDI invoicing, late fee regulations, reserve fund requirements — once you build them, they become a genuine competitive advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Node.js with Express, PostgreSQL with Knex, Redis, Socket.io&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web dashboard:&lt;/strong&gt; React 18 with TypeScript, Vite, TailwindCSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile app:&lt;/strong&gt; React Native with Expo, WebRTC, Firebase&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; DigitalOcean, Docker Compose, Caddy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invoicing:&lt;/strong&gt; Facturama API for CFDI 4.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where We Are Today
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.popservices.net" rel="noopener noreferrer"&gt;AdminCondo&lt;/a&gt; is live and handling real operations for residential buildings in Mexico. The most satisfying metric isn't a vanity number. It's hearing from an administrator who says: "I used to spend my entire Saturday building the monthly financial report. Now I just open the dashboard."&lt;/p&gt;

&lt;p&gt;That's the tool we replaced: an entire Saturday.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you're building for the Latin American market and want to compare notes on SPEI integration, CFDI compliance, or any of the challenges discussed here, I'd love to connect in the comments.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you manage a condominium in Mexico, visit &lt;a href="https://www.popservices.net" rel="noopener noreferrer"&gt;popservices.net&lt;/a&gt; to see AdminCondo in action.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the author:&lt;/strong&gt; Aldo Montenegro is the founder of &lt;a href="https://www.popservices.net" rel="noopener noreferrer"&gt;PopServices&lt;/a&gt;, a software company building technology for property management in Latin America.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>startup</category>
      <category>proptech</category>
      <category>entrepreneurship</category>
    </item>
    <item>
      <title>How We Built a WebRTC-Based Intercom System for Residential Buildings</title>
      <dc:creator>Aldo Montenegro</dc:creator>
      <pubDate>Sat, 21 Mar 2026 20:01:41 +0000</pubDate>
      <link>https://dev.to/aldomontenegro/how-we-built-a-webrtc-based-intercom-system-for-residential-buildings-4m1o</link>
      <guid>https://dev.to/aldomontenegro/how-we-built-a-webrtc-based-intercom-system-for-residential-buildings-4m1o</guid>
      <description>&lt;p&gt;When we set out to build &lt;a href="https://www.popservices.net" rel="noopener noreferrer"&gt;AdminCondo&lt;/a&gt; — a property management platform for residential buildings in Mexico — we knew we needed more than dashboards and payment tracking. Security guards needed to call residents directly from their phone. Residents needed to answer from anywhere — even when the app was killed.&lt;/p&gt;

&lt;p&gt;We needed a full intercom system, built into a mobile app, that worked as reliably as a phone call.&lt;/p&gt;

&lt;p&gt;This is the story of how we built it with WebRTC, Socket.io, and a lot of pain navigating iOS background restrictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture at a Glance
&lt;/h2&gt;

&lt;p&gt;Our intercom system has four layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│  React Native App (iOS / Android)   │
│  react-native-webrtc + CallKit      │
├─────────────────────────────────────┤
│  Socket.io Signaling Server         │
│  (Node.js / Express)                │
├─────────────────────────────────────┤
│  STUN / TURN Servers                │
│  (NAT traversal for cellular nets)  │
├─────────────────────────────────────┤
│  Push Notification Layer            │
│  iOS: PushKit VoIP  |  Android: FCM │
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow for a guard calling a resident looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Guard taps "Call"&lt;/strong&gt; in the app, which emits a make-call event via Socket.io&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signaling server&lt;/strong&gt; looks up the resident's extension, sends a push notification (PushKit on iOS, FCM on Android)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resident's phone wakes up&lt;/strong&gt; — iOS shows the native CallKit incoming call screen; Android shows a foreground service notification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resident answers&lt;/strong&gt; — the server brokers the WebRTC offer/answer exchange&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peer connection established&lt;/strong&gt; — audio flows directly between the two devices via STUN/TURN&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Hardest Part: Waking Up iOS
&lt;/h2&gt;

&lt;p&gt;On Android, receiving a call when the app is backgrounded or killed is relatively straightforward — FCM data messages plus a foreground service gets the job done.&lt;/p&gt;

&lt;p&gt;iOS is a different beast entirely.&lt;/p&gt;

&lt;p&gt;Apple requires VoIP apps to use &lt;strong&gt;PushKit&lt;/strong&gt; for incoming call notifications. PushKit notifications are special: they wake your app even when it's been killed by the OS, and they are &lt;em&gt;mandatory&lt;/em&gt; to pair with a CallKit reportNewIncomingCall. If you receive a PushKit notification and don't report a call to CallKit within a few seconds, Apple will terminate your app and eventually revoke your push privileges.&lt;/p&gt;

&lt;p&gt;The tricky part is &lt;strong&gt;timing&lt;/strong&gt;. When the app is killed, PushKit wakes it, but your JavaScript bridge (React Native) hasn't loaded yet. The native layer &lt;em&gt;must&lt;/em&gt; show the CallKit UI immediately. Only later, once JS is ready, does the app connect to the signaling server and complete the WebRTC handshake.&lt;/p&gt;

&lt;p&gt;We solved this with a "pending call" pattern: the native layer stores the call metadata, and once the JS context boots, it queries both local storage and the signaling server for any active calls that need to be joined.&lt;/p&gt;

&lt;h2&gt;
  
  
  The WebRTC Offer/Answer Timing Problem
&lt;/h2&gt;

&lt;p&gt;A subtle bug that cost us days: &lt;strong&gt;don't create the WebRTC offer before the callee is ready&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In early versions, the caller would create a RTCPeerConnection and generate an offer immediately after tapping "Call." The problem? ICE candidate gathering starts as soon as you create an offer. Those candidates get sent to the signaling server, which tries to relay them to the callee — but the callee hasn't connected yet. By the time they answer, the candidates have been lost.&lt;/p&gt;

&lt;p&gt;The fix was to defer offer creation — wait for the server to confirm that the callee has joined the call before creating the PeerConnection and generating the offer. This ensures that by the time ICE candidates start flowing, both peers are connected to the signaling server and ready to receive them.&lt;/p&gt;

&lt;h2&gt;
  
  
  CallKit Audio Session Management
&lt;/h2&gt;

&lt;p&gt;Another iOS-specific challenge: &lt;strong&gt;CallKit owns the audio session&lt;/strong&gt;. When a call starts, CallKit activates an AVAudioSession on your behalf. If your WebRTC stack also tries to manage the audio session, you get conflicts — silence on one end, or audio routing to the wrong output.&lt;/p&gt;

&lt;p&gt;The solution is to tell WebRTC to use "manual audio mode" and then bridge CallKit's audio session events. The order matters enormously here. You must wait for the audio session activation before trying to play ringback tones or capture microphone audio.&lt;/p&gt;

&lt;h2&gt;
  
  
  NAT Traversal: Why You Need a TURN Server
&lt;/h2&gt;

&lt;p&gt;STUN servers work great when both devices are on Wi-Fi. But in production, we found that roughly 15-20% of connections failed — especially when one party was on a cellular network behind carrier-grade NAT.&lt;/p&gt;

&lt;p&gt;The fix was deploying our own TURN server (we use coturn). TURN acts as a relay — if direct peer-to-peer fails, audio is routed through your server. It uses more bandwidth, but the connection actually works. For an intercom system where reliability is non-negotiable, TURN is not optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;After shipping this to production and handling real calls between security guards and residents, here are our key takeaways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;iOS PushKit is non-negotiable for VoIP.&lt;/strong&gt; Regular push notifications are too unreliable for time-sensitive calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never reorder the call setup sequence.&lt;/strong&gt; CallKit, audio session, ringback, socket signaling — this is a tightly coupled pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Defer the WebRTC offer.&lt;/strong&gt; Creating the offer before both peers are online leads to lost ICE candidates and failed connections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy your own TURN server.&lt;/strong&gt; STUN-only works in development. In production, carrier-grade NAT will break 15-20% of your connections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Heartbeats matter.&lt;/strong&gt; You need to know if a user is truly online before deciding whether to signal via socket or push notification.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test on real cellular networks.&lt;/strong&gt; Wi-Fi-to-Wi-Fi testing hides most of the real-world problems.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What We're Building Next
&lt;/h2&gt;

&lt;p&gt;We're exploring adding video calling for visitor verification (guard shows the visitor on camera, resident confirms identity before granting access) and group conference calls for emergency situations.&lt;/p&gt;

&lt;p&gt;If you're building something similar or have questions about implementing WebRTC in React Native, I'd be happy to discuss in the comments.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the author:&lt;/strong&gt; Aldo Montenegro is the founder of &lt;a href="https://www.popservices.net" rel="noopener noreferrer"&gt;PopServices&lt;/a&gt;, a software company building technology for property management in Latin America. AdminCondo is their flagship product, used by residential buildings across Mexico.&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>reactnative</category>
      <category>ios</category>
      <category>voip</category>
    </item>
  </channel>
</rss>
