Recursivity
All projects
Private Featured

Quartz

Multi-tenant SaaS for project, financial, and donor management

LanguageRuby on Rails 8
ModelMulti-tenant SaaS
HostingHeroku + AWS sidecar
StatusPrivate
  • A project dashboard: cash position, AP and AR aging, and what is waiting on approval.
    A project dashboard: cash position, AP and AR aging, and what is waiting on approval.
  • The accounts-payable queue, filtered by approval state across every project.
    The accounts-payable queue, filtered by approval state across every project.
  • Incoming donations awaiting review before they become QuickBooks invoices.
    Incoming donations awaiting review before they become QuickBooks invoices.
  • The QuickBooks ledger, mirrored per project and per class.
    The QuickBooks ledger, mirrored per project and per class.
  • Aging reports, read from the accounting system rather than recomputed locally.
    Aging reports, read from the accounting system rather than recomputed locally.
  • FreshDesk tickets synced two ways — public replies only, never the internal notes.
    FreshDesk tickets synced two ways — public replies only, never the internal notes.
  • Twelve integrations, each connected per organization.
    Twelve integrations, each connected per organization.
  • The audit log, including the impersonation request / grant / start / end chain.
    The audit log, including the impersonation request / grant / start / end chain.

Running against seeded demo data — an invented foundation, invented staff, invented funders.

Quartz is a multi-tenant SaaS platform: many customer organizations share one running application, and each organization's data is isolated from every other one's. Projects are the central entity — they carry milestones, resources, members, expense and income requests, tickets, and financials — and around them sit a donor management module, a billing system, and twelve outside integrations.

It is the largest thing here: 63 models, policies on everything, and a documented security posture written for the people who ask for one.

Tenancy is enforced twice

The active organization is chosen per session rather than by subdomain or URL path, which means the tenant is not something a URL can assert. TenantScoped resolves it on every request and validates it against the user's memberships; Tenantable stamps organization_id on creation from a thread-safe Current context.

Login is the other half. A Warden hook normalizes the session's organization at authentication time: if the stored value is not one of the user's memberships, it is reset before the first request runs. Between the two, a user can never operate under an organization they don't belong to — not by tampering, and not by holding a stale session from a revoked membership.

Twelve integrations, two auth patterns

OAuth for QuickBooks, HubSpot, Zoho, Salesforce, FreshBooks, and Xero; API keys for Stripe, Monday, Zendesk, FreshDesk, and Bill.com. Every token and key is encrypted at rest, and connections are unique per organization.

The FreshDesk sync is the one that earned its complexity. It is two-way, and the interesting parts are all about not leaking things:

Rules that encode who may do what

The submitter of an expense or income request can never approve it — project admins, org admins, and superadmins alike. Deny, mark-paid, and mark-processed are deliberately not gated: refusing your own request is no conflict of interest, and post-decision bookkeeping already required someone else's approval.

The one carve-out is the project with a single person on it, where there is nobody to hand the decision to. When the bar does apply, the page renders an explicit notice rather than silently dropping the approval panel, so the rule is visible instead of looking like a bug.

Billing, and the second Stripe

Quartz bills through its own Stripe account, which is deliberately distinct from the customer-owned Stripe integration — two namespaces, two credential sets, no chance of one being mistaken for the other. It is sales-led: superadmins manage subscriptions internally and all customer-facing billing UI is Stripe-hosted.

The Subscription record is an opaque mirror of Stripe's state, with a plain string status and no enum, because inventing a local state machine for someone else's system is how the two fall out of sync. Organizations with no subscription at all are grandfathered rather than locked out.

Stack and infrastructure

FrameworkRails 8.1 on Ruby 3.4, Hotwire over importmap, Tailwind, Propshaft
DataPostgreSQL; Active Record encryption for every third-party token
AuthDevise with 2FA; Pundit policies with role-based access
Background workSolid Queue, with a superadmin-only jobs dashboard
Notificationsnoticed for in-app and email, plus outgoing interceptors for bounces, opt-outs, and suspended accounts
HardeningRack::Attack, Brakeman and bundler-audit on pre-push, RSpec with Pundit and Shoulda matchers
HostingHeroku, with an AWS sidecar providing S3, SES, and a narrowly scoped IAM user
AlternativeA parked Terraform stack for an all-AWS deploy — ECS Fargate, RDS, ALB, ACM — kept for the day it is needed