Property management portal
A community portal for a property owners' association, with a custom CMS where staff build pages and forms without a developer, and residents search deed restrictions, submit requests and pay online.
- Role
- Full-stack engineer
- Status
- Live in production
- Client
- Property owners' association
- React
- Redux
- Tailwind CSS
- Node.js
- Express
- Knex
- MySQL
- Stripe

The problem
- Context
- A property owners' association needed a community website its own staff could run, and a resident area where owners find deed restrictions, submit forms, request paid house-checks while away, and pay online. The association's people and property records already lived in a separate legacy membership system.
- Constraints
- The legacy system stays the source of truth, so the portal keeps its own copy of residents and properties in step with it automatically and creates resident logins as new contacts appear. Staff build pages and forms without a developer, and the schema had to keep evolving for years without losing old form submissions.
- What was at stake
- The portal is live for the association's whole membership. A bad sync could orphan or delete residents' accounts and history, and dues and house-check requests take real payments, so payment records have to be complete and trustworthy.
What I built
Staying in step with a legacy system
Scheduled one-way sync
A scheduled job reads properties, contacts and their links from the legacy database in small batches and updates the portal's copy, creating a resident login when a new contact appears. It is deliberately gentle on the legacy server; the trade-off is that a bad record is skipped and logged rather than blocking the run.
Removals reconciled too
A second job removes residents and properties that no longer exist in the legacy system, together with everything attached to them, so the portal never shows people who have left.
A data model keyed to properties
As the sync matured, the schema moved from user-centred records to property-centred ones, with documents, house-checks, payments and form submissions linked to the property.
Content management
Forms with version history
Every edit to a form saves a new version, and each submission stays linked to the version it was filled in on. Staff can change a form without breaking the meaning of last year's answers.
Pages and menus staff control
Staff manage nested pages, drafts, menus, the home page, sliders and FAQs, and each page can be limited to particular roles.
Deed-restriction search
Residents search deed restrictions by street address, with indexes added once the data grew large enough to make searches slow.
Payments
Card and bank-account payments
Checkout supports cards and US bank accounts with instant verification, and payment notifications are verified against the raw request before they are trusted.
A complete payment ledger
Each payment records its breakdown, total, status, payer and property, including paid house-check requests, so staff can answer any 'did this go through?' question.
Operations
Large exports queued, not blocking
Staff queue exports of users or payment history; a background job builds the spreadsheet and emails it, so a big export never times out a page.
Residents' services and newsletters
Lost-and-found pets, newsletter subscriptions and an email send log run as resident services alongside the CMS.
Tell me what you’re building and where it’s stuck.
I’ll tell you the cleanest path forward, including if it’s “don’t build that.”
Or write tocontact@alihassan.dev
