2026-07-02 13:42:34 -04:00
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
# DigitalOcean App Platform spec — Property Management Network
|
|
|
|
|
#
|
2026-07-03 04:45:24 -04:00
|
|
|
# Deploy: doctl apps create --spec .do/app.yaml (or the DO MCP apps-create)
|
2026-07-02 13:42:34 -04:00
|
|
|
# Update: doctl apps update <APP_ID> --spec .do/app.yaml
|
|
|
|
|
#
|
2026-07-03 04:45:24 -04:00
|
|
|
# SOURCE: App Platform builds the Dockerfile directly from GitHub
|
|
|
|
|
# (github.com/silkoserfo/property-management-network). Pushes to `main`
|
|
|
|
|
# auto-redeploy (deploy_on_push). No DOCR image build/push needed.
|
2026-07-02 13:42:34 -04:00
|
|
|
#
|
|
|
|
|
# SECRETS: values marked `type: SECRET` are placeholders — set the real values in
|
2026-07-03 04:45:24 -04:00
|
|
|
# the App Platform dashboard (App → Settings → Environment Variables) or via the
|
|
|
|
|
# create spec. Never commit real secrets to this file.
|
2026-07-02 13:42:34 -04:00
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
name: property-management-network
|
|
|
|
|
region: nyc
|
|
|
|
|
|
|
|
|
|
services:
|
|
|
|
|
- name: web
|
2026-07-03 04:45:24 -04:00
|
|
|
# Built by App Platform from GitHub using the repo Dockerfile.
|
|
|
|
|
github:
|
|
|
|
|
repo: silkoserfo/property-management-network
|
|
|
|
|
branch: main
|
|
|
|
|
deploy_on_push: true
|
|
|
|
|
dockerfile_path: Dockerfile
|
2026-07-02 13:42:34 -04:00
|
|
|
instance_count: 1
|
|
|
|
|
instance_size_slug: apps-s-1vcpu-1gb
|
|
|
|
|
http_port: 3000
|
|
|
|
|
health_check:
|
|
|
|
|
http_path: /api/health
|
|
|
|
|
initial_delay_seconds: 20
|
|
|
|
|
period_seconds: 30
|
|
|
|
|
timeout_seconds: 5
|
|
|
|
|
success_threshold: 1
|
|
|
|
|
failure_threshold: 3
|
|
|
|
|
envs:
|
|
|
|
|
# ── App URLs ──────────────────────────────────────────────────────────
|
2026-07-03 04:45:24 -04:00
|
|
|
# NEXT_PUBLIC_* are inlined into the client bundle at BUILD time, so they
|
|
|
|
|
# must be RUN_AND_BUILD_TIME with the literal domain we serve on.
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: NEXT_PUBLIC_APP_URL
|
2026-07-03 04:45:24 -04:00
|
|
|
scope: RUN_AND_BUILD_TIME
|
|
|
|
|
value: https://propertymanagement.network
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: BETTER_AUTH_URL
|
|
|
|
|
scope: RUN_TIME
|
2026-07-03 04:45:24 -04:00
|
|
|
value: https://propertymanagement.network
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: NEXT_PUBLIC_APP_NAME
|
2026-07-03 04:45:24 -04:00
|
|
|
scope: RUN_AND_BUILD_TIME
|
2026-07-02 13:42:34 -04:00
|
|
|
value: Property Management Network
|
|
|
|
|
|
2026-07-03 04:45:24 -04:00
|
|
|
# ── Admin & auth policy ───────────────────────────────────────────────
|
|
|
|
|
- key: ADMIN_EMAILS
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: leon@phluit.com
|
|
|
|
|
- key: REQUIRE_EMAIL_VERIFICATION
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: "true"
|
|
|
|
|
|
|
|
|
|
# ── Database (managed Postgres — PRIVATE host, direct port 25060) ──
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: DATABASE_URL
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
2026-07-03 04:45:24 -04:00
|
|
|
# Verified TLS: DO's Managed Postgres CA isn't in the system trust store, so
|
|
|
|
|
# paste the cluster CA PEM (repo root ca-certificate.crt) into DATABASE_CA.
|
|
|
|
|
# With `require` + a valid CA the app connects verified; without a valid CA
|
|
|
|
|
# it fails loud rather than run unverified.
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: DATABASE_SSL
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: require
|
|
|
|
|
- key: DATABASE_CA
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
2026-07-03 04:45:24 -04:00
|
|
|
# Schema is migrated out-of-band (as doadmin), NOT on boot.
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: RUN_MIGRATIONS_ON_START
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: "false"
|
|
|
|
|
|
|
|
|
|
# ── Better Auth ───────────────────────────────────────────────────────
|
|
|
|
|
- key: BETTER_AUTH_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
2026-07-03 04:45:24 -04:00
|
|
|
# Google OAuth (optional — leave blank to disable the Google button).
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: GOOGLE_CLIENT_ID
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
2026-07-03 04:45:24 -04:00
|
|
|
value: ""
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: GOOGLE_CLIENT_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
2026-07-03 04:45:24 -04:00
|
|
|
value: ""
|
2026-07-02 13:42:34 -04:00
|
|
|
|
|
|
|
|
# ── Stripe ────────────────────────────────────────────────────────────
|
|
|
|
|
- key: STRIPE_SECRET_KEY
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
- key: STRIPE_WEBHOOK_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
|
2026-07-03 04:45:24 -04:00
|
|
|
# ── AI provider (Anthropic default; OpenAI optional) ──────────────────
|
|
|
|
|
- key: ANTHROPIC_API_KEY
|
2026-07-02 13:42:34 -04:00
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
2026-07-03 04:45:24 -04:00
|
|
|
- key: ANTHROPIC_MODEL
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: claude-haiku-4-5
|
|
|
|
|
- key: OPENAI_API_KEY
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: ""
|
2026-07-02 13:42:34 -04:00
|
|
|
|
|
|
|
|
# ── Email (SMTP — SMTP2GO) ────────────────────────────────────────────
|
|
|
|
|
- key: SMTP_HOST
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: mail.smtp2go.com
|
|
|
|
|
- key: SMTP_PORT
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: "2525"
|
|
|
|
|
- key: SMTP_USER
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
- key: SMTP_PASS
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
- key: EMAIL_FROM
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: postmaster@propertymanagement.network
|
|
|
|
|
|
2026-07-03 04:45:24 -04:00
|
|
|
# ── Cloudflare Turnstile (site key public; baked at build time) ──
|
2026-07-02 13:42:34 -04:00
|
|
|
- key: NEXT_PUBLIC_TURNSTILE_SITE_KEY
|
2026-07-03 04:45:24 -04:00
|
|
|
scope: RUN_AND_BUILD_TIME
|
2026-07-02 13:42:34 -04:00
|
|
|
value: 0x4AAAAAADuDQverznfv1a60
|
|
|
|
|
- key: TURNSTILE_SECRET_KEY
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
|
|
|
|
|
# ── Object storage (DigitalOcean Spaces + CDN) ────────────────────────
|
|
|
|
|
- key: SPACES_KEY
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
- key: SPACES_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
|
|
|
|
- key: SPACES_REGION
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: nyc3
|
|
|
|
|
- key: SPACES_BUCKET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: property-management-network
|
|
|
|
|
- key: SPACES_ENDPOINT
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: https://nyc3.digitaloceanspaces.com
|
|
|
|
|
- key: SPACES_CDN_ENDPOINT
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: https://nyc3.cdn.digitaloceanspaces.com
|
|
|
|
|
|
2026-07-03 04:45:24 -04:00
|
|
|
# ── Accounting sync (optional — per-landlord QuickBooks / Xero OAuth) ──
|
|
|
|
|
- key: QBO_CLIENT_ID
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: ""
|
|
|
|
|
- key: QBO_CLIENT_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: ""
|
|
|
|
|
- key: QBO_ENVIRONMENT
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: production
|
|
|
|
|
- key: XERO_CLIENT_ID
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: ""
|
|
|
|
|
- key: XERO_CLIENT_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: ""
|
|
|
|
|
- key: XERO_SALES_ACCOUNT_CODE
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: "200"
|
|
|
|
|
- key: XERO_EXPENSE_ACCOUNT_CODE
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: "400"
|
|
|
|
|
|
|
|
|
|
# ── Error monitoring (Sentry — DSN is public; browser DSN baked at build) ──
|
|
|
|
|
- key: SENTRY_DSN
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: https://ef6aa585a080711e14a855b6cc024e9a@o4509830676873216.ingest.us.sentry.io/4511667160219648
|
|
|
|
|
- key: NEXT_PUBLIC_SENTRY_DSN
|
|
|
|
|
scope: RUN_AND_BUILD_TIME
|
|
|
|
|
value: https://ef6aa585a080711e14a855b6cc024e9a@o4509830676873216.ingest.us.sentry.io/4511667160219648
|
|
|
|
|
- key: SENTRY_ENVIRONMENT
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
value: production
|
|
|
|
|
|
2026-07-02 13:42:34 -04:00
|
|
|
# ── Cron (Bearer token the DO Function sends to /api/cron/*) ──
|
|
|
|
|
- key: CRON_SECRET
|
|
|
|
|
scope: RUN_TIME
|
|
|
|
|
type: SECRET
|
|
|
|
|
value: REPLACE_IN_DASHBOARD
|
2026-07-03 04:45:24 -04:00
|
|
|
|
|
|
|
|
# ── Custom domains (DNS hosted on Cloudflare — set CNAMEs there, DNS-only) ──
|
|
|
|
|
domains:
|
|
|
|
|
- domain: propertymanagement.network
|
|
|
|
|
type: PRIMARY
|
|
|
|
|
- domain: www.propertymanagement.network
|
|
|
|
|
type: ALIAS
|