inflatehq/README.md
chris 27589ab99f Initial commit: InflateHQ — Square to CalDAV approval app
Ingests Square invoices/payments, extracts event scheduling from order
notes, and pushes approved entries to a CalDAV calendar after human
review.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 15:19:05 -04:00

3.5 KiB

Order to Calendar

Pulls invoices and payments from Square, lets a human review and edit each one, and pushes approved entries to a CalDAV calendar. Mobile-friendly (works as a PWA — "Add to Home Screen"), multi-user login, ships as a single Docker image plus Postgres.

How it works

  1. A background job (or the "Sync now" button) polls the Square Invoices and Payments APIs and turns new/updated invoices and payments into candidate calendar entries with status PENDING.
  2. Signed-in users review the pending queue on any device, edit fields if needed (title, date/time, description, location, customer info, amount), and either Approve or Reject each one.
  3. Approving creates (or updates) an event on your CalDAV calendar. Nothing reaches the calendar without a human approving it first.

Requirements

  • A Square account with API credentials (developer.squareup.com → your app → Credentials).
  • A CalDAV calendar (Nextcloud, Fastmail, iCloud, or self-hosted) — see docs/caldav-setup.md.
  • Docker + Docker Compose on the server you're deploying to.

Deploying

cp .env.example .env
# edit .env: JWT_SECRET, BOOTSTRAP_ADMIN_*, POSTGRES_*, SQUARE_*, CALDAV_*
docker compose up -d --build

The app listens on port 3000 (PORT in .env) — put your existing reverse proxy (nginx, Caddy, Traefik, etc.) in front of it for TLS. On first boot it runs database migrations and creates the initial admin account from BOOTSTRAP_ADMIN_EMAIL / BOOTSTRAP_ADMIN_PASSWORD. Log in as that admin, then create accounts for everyone else from Admin → New user — there is no open self-registration.

To go live, generate a real Square access token for SQUARE_ENVIRONMENT=production once you've verified the sandbox flow end to end.

Updating

git pull
docker compose up -d --build

Migrations run automatically on container start; existing data in the db-data volume is preserved.

Local development

npm install
npm run prisma:generate
# start a local Postgres however you like, then create the schema:
DATABASE_URL=postgresql://... npx prisma migrate dev --schema server/prisma/schema.prisma

npm run dev:server   # backend on :3000
npm run dev:web      # frontend on :5173, proxies /api to :3000

Configuration reference

See .env.example for every environment variable, with comments.

Key ones worth knowing:

Variable Purpose
SQUARE_LOCATION_ID Leave blank to sync every location on the account, or set a comma-separated list to scope it.
SYNC_INTERVAL_CRON How often the background sync runs (default: every 15 minutes).
PAYMENT_DEFAULT_DURATION_MINUTES Payments have no inherent duration in Square — this sets the calendar event length.
CALDAV_CALENDAR_URL Must be the specific calendar collection URL, not just the server root, and must end with /.

Architecture notes

  • Idempotent sync: re-running sync never duplicates a candidate (unique on Square ID + source type + environment). Once a candidate is approved or rejected it's frozen — a later Square-side edit won't silently overwrite a human decision.
  • Idempotent CalDAV writes: each approved candidate keeps its CalDAV event UID/URL/etag, so editing an already-approved item and re-approving updates the existing event instead of creating a duplicate.
  • Auth: httpOnly JWT cookie sessions (no separate session store), passwords hashed with argon2id.