Property Management Network replaces the spreadsheet-and-WhatsApp chaos that most small landlords live with. It gives a solo landlord or a small team a single source of truth for their whole portfolio — and the automation, AI, and integrations to run it hands-off.
Everything is **multi-tenant and team-aware**: each landlord operates on their own isolated portfolio, and Landlord/Lifetime accounts can invite teammates with scoped roles.
### 🧰 What you can do
**Core operations**
- 🏢 **Properties & units** — manage your whole portfolio with live occupancy tracking and a map view (addresses are auto-geocoded).
- 👥 **Tenants** — profiles, lease history, payment records, and a private **tenant portal** (token-based, no login required).
- 💵 **Rent tracking** — log payments, send **Stripe or PayPal** payment links, and auto-mark balances overdue with automatic late fees.
- 🔧 **Maintenance** — full status workflow (Open → In Progress → Resolved), with tenant-submitted requests from the portal.
| 🪝 **Outbound webhooks / Zapier** | Subscribe to events (`tenant.created`, `payment.paid`, `maintenance.updated`, …). Deliveries are **HMAC-signed**, retried with backoff, and Zapier-compatible via the REST-hook subscribe/unsubscribe pattern. |
| 🏆 **Landlord** | $59/mo | Unlimited properties, team access, white-label, AI (200/mo) |
| ♾️ **Lifetime** | $199 once | Everything in Landlord, forever |
Billing runs through **Stripe** or **PayPal**. Stripe products/prices are resolved by stable lookup keys and auto-created on first checkout, so going live is just an API-key swap — no price IDs to wire up.
`.env.local` holds your database URL, auth secret, and credentials for Stripe/PayPal, OpenAI, SMTP, and object storage. **Every variable is documented inline in `.env.example`**, and the full production reference lives in **[DIGITALOCEAN.md](DIGITALOCEAN.md)**. Never commit real secrets.
- **Stripe** — set the API keys, then add a webhook at `https://yourdomain.com/api/stripe/webhook` for `checkout.session.completed`, the `customer.subscription.*` events, `invoice.payment_failed`, and `payment_intent.succeeded`.
- **Email** — verify a sending domain with your SMTP provider (e.g. SMTP2GO) and set the `SMTP_*` + `EMAIL_FROM` vars.
- **Google / PayPal / OpenAI / accounting / e-sign** — each is optional and activates once its env vars are present.
The repo ships a production `Dockerfile` (Next.js standalone), an App Platform spec at [`.do/app.yaml`](.do/app.yaml), DO Functions cron under [`functions/`](functions/), and a `/api/health` probe. Follow **[DIGITALOCEAN.md](DIGITALOCEAN.md)** for the full walkthrough.
> 🔐 **Tenancy is enforced in the application layer.** Every query scopes by the resolved **account owner id** (team-aware), never the raw session user. There is no database RLS, so this scoping must be preserved on every new route — see `lib/account.ts` (`getEffectiveOwnerId`).
- 🔑 API keys are stored as SHA-256 hashes; the plaintext is shown once.
- 🪝 Webhook payloads are **HMAC-SHA256 signed** (`X-PMN-Signature`); endpoint URLs are **SSRF-guarded** (private/loopback/metadata ranges blocked).
- 📁 Uploaded files are served only through an auth-gated route; object storage is required in production (uploads **fail loud** rather than silently hit ephemeral disk).
- 🛢️ Verified TLS to Postgres in production (`DATABASE_SSL=require` + CA).
- ⏱️ Cron endpoints use a constant-time bearer check and fail closed.
This source code is proprietary and confidential. No license or permission is granted to use, copy, modify, merge, publish, distribute, sublicense, or sell any part of it without the prior written consent of the copyright holder. See [LICENSE](LICENSE).