Initial setup
This guide takes a board member or property manager from an empty CondoPulse install to a working status page: the building modelled, assets tracked, and the operational plumbing (secrets, cron, email) configured.
The model you’re building
Section titled “The model you’re building”CondoPulse models one property (the building/complex, with a street address and a timezone - get the timezone right, it drives the per-day uptime slats), containing:
- Towers - e.g. Tower A, Tower B.
- Units - per tower, with a number (
"1204") and floor. Units let residents report in-suite and location-specific issues (“Urine in Tower B stairwell, floor 3” is a unit/common-area incident). - Assets - the systems and amenities you want uptime history for. Each
asset has a name, a category (
elevator,pool,gym,garden,fire_alarm,parking,hvac,laundry,common_area,other), a live status (operational | degraded | down | maintenance), and an optional tower - leave the tower empty for property-wide assets like the pool.
Choosing your asset list
Section titled “Choosing your asset list”Granularity is the key decision. Recommendations:
- One asset per elevator (Elevator A1, Elevator A2, Elevator B1) - not “Elevators”. Per-car uptime is exactly the evidence you’ll want when a vendor contract comes up for renewal.
- One asset per amenity residents care about: Pool, Gym, Parking Garage Door, Fire Alarm System, Tower A HVAC.
- Split things that fail independently; merge things that don’t. “Garden - North Bed” is a fine asset if it generates recurring reports.
Assets are managed in the admin area, /admin → Assets tab. Create them
once; residents do the rest.
Environment configuration
Section titled “Environment configuration”The web app reads its configuration from .env (start from .env.example).
The operational variables you should know about:
| Variable | Purpose |
|---|---|
DATABASE_URL | Postgres connection string (Neon in production; a dev branch locally) |
BETTER_AUTH_SECRET | Session signing secret - set it (openssl rand -hex 32) |
BETTER_AUTH_URL | Public base URL; also used to build QR sticker links |
MOBILE_API_KEY | Bearer key the mobile app uses (default dev-mobile-key in dev) |
CRON_SECRET | Guards POST /api/cron/sweep and POST /api/cron/digest |
INBOUND_EMAIL_SECRET | Guards POST /api/inbound-email |
SLA_HOURS_CRITICAL/HIGH/MEDIUM/LOW | Override SLA acknowledgement targets (defaults 4/24/72/168) |
SMTP_URL | Outgoing mail. Optional - when unset, every email is written to .data/outbox/*.eml.html instead, so you can preview without a mail server |
DIGEST_FROM | From-address for digest and notification email |
STORAGE_DRIVER | local (default, photos under .data/uploads/) or s3 with S3_BUCKET, S3_ENDPOINT, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY (works with R2/MinIO) |
EXPO_PUSH_ENABLED | true to deliver mobile push notifications |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | Optional Google SSO on /login; SSO users start as residents until promoted |
ANTHROPIC_API_KEY | Optional - enables the AI triage suggestions on the report form |
Data lives in the Postgres database DATABASE_URL points at (Neon in
production, which keeps point-in-time restore). Uploaded photos land in
.data/uploads/ with the local driver (or in your S3/R2 bucket); un-sent
email in .data/outbox/. The database plus the photo store together are the
building’s record.
Demo data
Section titled “Demo data”npm run seed creates a deterministic demo building - “Harborview Towers”,
two towers, 12 units each, nine assets, ~25 incidents over 90 days, plus demo
logins (resident@demo.test, board@demo.test, manager@demo.test,
admin@demo.test, password demo1234). It’s idempotent (wipes and
re-creates), which makes it great for evaluation and fatal for production -
don’t run it against a live database.
The admin surface
Section titled “The admin surface”Everything operational lives at /admin, in tabs:
| Tab | What it’s for |
|---|---|
| Triage | Untriaged (email-sourced) and SLA-breached incidents first, with inline assign/acknowledge - see Triage queue & email-in |
| Assets | Create/edit assets, set category, tower, live status |
| Maintenance | Planned windows with recurrence - see Maintenance windows |
| Contacts | The public directory: property manager, superintendent, vendors, emergency line - name, label, phone, email, notes, sort order |
| Residents | The resident directory (staff-only view of who’s in which unit) |
| Webhooks | Outgoing webhook CRUD - see Webhooks & n8n |
| Audit | The append-only audit log, filterable, 50 per page - see Exports & audit log |
| Digest | Preview of the weekly board digest - see Weekly digest |
| Insights | Assets ranked by health score (uptime, incident trend, recency), with downtime hours and 365-day repair costs - the “replace this elevator” view |
| Organization | Org-level settings and feature flags (cost_tracking, asset_health, ai_triage) |
Setup checklist
Section titled “Setup checklist”- Property basics - name, address, and the correct IANA timezone.
- Towers and units - enter every tower, then its units with floors.
- Assets - create your asset list (
/admin→ Assets) with sensible categories; set each one’s current status honestly. - Contacts - fill the directory (
/admin→ Contacts). Residents see this at/directory; include the after-hours emergency line. - Secrets - set
BETTER_AUTH_SECRET,CRON_SECRET,INBOUND_EMAIL_SECRET, and a realMOBILE_API_KEY. - Cron - schedule the SLA sweep (hourly) and the weekly digest. Exact crontab and n8n examples are in SLA policy & escalation and Weekly digest.
- Email - set
SMTP_URLandDIGEST_FROM(or accept outbox-only mode while testing). - Maintenance windows - add known recurring work (monthly fire-alarm test!) so planned work paints blue, not red.
- Roles - promote your board and manager accounts at
/admin(admin-only) - see Roles & permissions. - Surfaces - put the kiosk on the lobby TV (Kiosk mode) and print QR stickers for assets (QR stickers).