NewIntroducing PartnerView. Software built for partner services firms.Read the field note →
Trust

How we built something you can put your commission data in.

Engineering rigor and access controls, in specifics. No buzzwords, no checkmark logos, no claims we cannot back up.

Why this page exists

A reasonable question we get from anyone evaluating a small product is whether a small team can be trusted with the data that runs the firm. Commission economics, revenue recognition, client requirements, partner subcontracting terms. These are not playground data. If the tool breaks, real money breaks with it.

The default trade for a small product is "move fast, ship every day, apologize when something breaks." That is rational for consumer apps and irrational for software that handles a firm's money.

We made the opposite trade.

Engineering quality, in numbers

These are facts about the current production codebase, not aspirations.

  • 1781 automated tests. A full test suite covering smoke, integration, and user-acceptance layers, plus a flow-based persona-journey UAT layer on top of feature-isolated tests. The suite runs on every change. We do not ship if any of them fail.
  • Zero TypeScript errors maintained as a baseline. Strict typing across the entire codebase. The class of bugs where a field is the wrong shape is closed by the compiler before it can reach a user.
  • Architectural review on every meaningful change. Not a checklist. A read by a second engineer with the authority to say "no, this is not how we do it." Slower than a thumbs-up. Catches what a thumbs-up does not.
  • Most tests are about money. Commission math, snapshot-rate freezing, revenue recognition by pricing model, invoice rollups. The math that matters is the math we test hardest.

A recent architectural review surfaced seven findings: one urgent privilege-escalation hole, one critical transaction-safety gap, three structural issues, and two smaller items. All seven shipped clean in a single day, each as its own verified change. A follow-on security audit closed four additional URL-bypass authorization holes on detail pages. The process is not "we never have issues." The process is "we find them and close them, on a timeline measured in hours, not weeks."

A separate codebase-wide audit on 2026-05-15 surveyed 464 source files and 59,876 lines of code, across 82 pages, 177 API routes, and 94 client components. The audit produced 47 findings: 0 critical, 6 high, 21 medium, 20 low. All 6 high findings were addressed in a single stage and shipped clean.

A second codebase audit on 2026-05-16, after the first audit's findings had been remediated, surveyed the new code shipped in the intervening week and produced 23 additional findings: 0 critical, 3 high, 11 medium, 9 low. All 3 highs and 4 MUST-FIX mediums were addressed in a single follow-on stage. The pattern is deliberate. We audit, fix, ship, and audit again.

Access control, in specifics

A partner services firm is not one homogeneous team. It is staff and contractors and partners and sometimes vendor-side users, all looking at overlapping data, all needing different access. The permission system was built for that reality, not against it.

  • Role-based access with six default roles: Admin, Sales, Solutions Engineer, Delivery, Finance, and Independent Contractor. Each role has a sensible default set of permissions.
  • Granular permission keys. Every meaningful action in the product has its own permission key. The role builder reads the permission catalog dynamically, so new permissions become configurable toggles automatically.
  • Per-user overrides. Permissions can be granted or revoked on top of any role, per user.
  • Record-level scope enforcement, not just route-level. A user with "view only my own" cannot URL-hop to records they do not own. The detail routes enforce per-record scope using server-side helpers, not just layout-level role gates. A systematic detail-page audit closed every gap in this class.
  • Sidebar and dashboard items hide when the viewer lacks permission. Not a generic "no access" error; the navigation itself reflects what the user can actually do.
  • Three-tier permission hierarchy: org, team, user. Effective permission resolves user, then team, then org. Most specific wins. Source of truth is the permission_grants table.
  • 117 permission keys cover every protected surface.
  • 18 permissions are sticky-on-admin and cannot be revoked from an admin without a code change. permission_audit_log writes a row on every grant or revoke with actor, target, scope, key, before / after, and reason.
  • Financial, compensation, and governance reports are permission-gated at both page and export level. The right people see the right numbers. Sensitive reports (firm-wide P&L, per-person compensation, partner payout governance, audit-log exports) require explicit role grants to view, and a separate permission to export. We do not ship a mode where everyone sees everything.
  • Permission matrix proof. A single integration test asserts that every protected surface is gated by the right permission key. The test runs on every commit. An unguarded surface fails CI before it can ship.
  • Dashboard data scoping proof. A separate integration test asserts that no widget on the personal dashboard surfaces data outside the viewer's visibility scope. If a hidden record's existence could leak through a count or a rollup, the test fails CI.

How money math is protected

This is the part of the product where mistakes cost the most. It is built with that in mind.

  • Commission rate snapshots. At deal close, the active commission rule freezes onto the deal. A later rule change applies only to deals closed after it. Closed deals are immutable. The class of bug where "a rule change retroactively altered last quarter's commissions" is closed by design.
  • Multi-write operations are atomic. Operations that have to write to several tables together (a quote acceptance, a deal-to-project handoff, a change order approval) are wrapped in database transactions. They either fully complete or fully roll back. There is no half-done state.
  • Cached aggregates are recomputed on write. Project hours, retainer period usage, and other derived totals are recomputed inside the same transaction that updates the source data. The cached number is never stale by even a moment.
  • Versioned database migrations. Schema changes preserve data, not recreate it. Fourteen versioned migrations shipped to date.
  • Time-period lock workflow. Weekly periods move from open to submitted to approved to locked. Locked periods reject writes with HTTP 423. Admin unlock requires a written reason and writes to an append-only audit log. Period status and rollover history are reportable.
  • Field Guide. Every entity, route, table, and permission key is documented as a self-derived schema at /admin/field-guide. The Field Guide is generated from the codebase, so it cannot drift from what is actually shipped.

Authentication hardening

  • App-level email-OTP sign-in cutover. The Cloudflare Access SSO bridge was retired in favor of the app's own OTP path, so the audit chain is single-source.
  • Per-org sign-in policy. Configurable OTP code length, expiry, per-email and per-IP rate-limit thresholds at /admin/settings/auth.
  • New-device notification. First sign-in from an unseen device fingerprint writes an in-app inbox item and emails the user.
  • Admin unlock at /admin/users/[id]/unlock for locked-out users. A written reason is required. The unlock writes to the sign-in audit log.
  • Sign-in audit log on every success and every failure. The full record of who signed in, from where, and what failed is queryable.

Trash, retention, and restore

  • Soft-delete on every entity. 14 retention policies cover leads, deals, projects, tasks, time, expenses, invoices, payments, quotes, escalations, escalation closeouts, action items, comments, attachments, and audit rows. Each has a default window plus a per-entity admin override.
  • Cascade trash. Trashing a parent trashes its children, logged per row with the originating cascade run id. Restoring the parent restores the cascaded children that came with it.
  • Daily auto-purge cron at 04:00 UTC sweeps every entity table, hard-deletes rows past their policy threshold, and emits a summary audit row.
  • Snapshot on purge. Every row about to hard-delete is first serialized to a purge_snapshots table with a 30-day recovery deadline. Emergency restore re-hydrates the row through an admin-only endpoint within those 30 days.
  • 7-year invoice retention default. Tightening it requires an admin override with a written audit reason.

Entity history (every write, every diff)

  • Every insert, update, soft-delete, and restore writes a snapshot of the post-write row to entity_history with the actor, timestamp, action, and full row JSON.
  • Per-snapshot changed_fields summary lets history feeds and diffs render without parsing the JSON on every row.
  • Diff view. Field-level, word-level for long text, child-array summaries for line items and action items.
  • Cross-entity batch restore via change_batch_id. A single user action that edited a deal, its quote, and three tasks can be rewound as one transaction.
  • 365-day default retention, per-entity-type override at /admin/entity-history-policies, daily 04:00 UTC purge with a dryRun=1 preview.

Daily off-site backups

  • Daily R2 backup cron at 06:00 UTC. 7-day retention. Per-environment folder layout (production, staging, dev).
  • Admin console at /admin/backups lists every snapshot.
  • Force-backup button gated on admin.force_backup (sticky on admin).
  • Restore dry-run previews table and row counts before the restore button writes anything.
  • Backup audit log captures every force-run and restore attempt.

Audit log discipline

  • Append-only audit rows across permission grants, settings edits, retention policy edits, lock/unlock cycles, trash/restore/purge events, and import batches.
  • 3-year retention by policy.
  • No UI or API path can mutate or delete an audit row.
  • Audit viewer at /admin/audit-log with filters.

What we deliberately do not ship

A short list of things we will not do, even though some of them would help sell the product.

  • No AI in the money math. Every suggestion the product surfaces (the Insights pane on each project, for example) is a deterministic rule we can explain in one sentence. Money should not be advised by a model that cannot show its work. If we ever ship anything backed by a model, it will be in places where being right matters less than being interesting.
  • No silent failures. Non-fatal failures surface as warnings, not as hidden errors. If a template fails to apply during a project handoff, you see a yellow banner that says exactly what went wrong. The system does not pretend things worked when they did not.
  • No "all-in-one" claims we cannot back up. PartnerView is a CRM and a PSA. It is not a replacement for your accounting system, your file storage, or your communication tools. We say this on purpose.

What we have not done yet

In the same spirit, these are real gaps. They are on the roadmap. They are not done.

  • SOC 2 audit. Not currently certified. The engineering controls that would back a SOC 2 audit are in place; the audit itself is not.
  • Google SSO. Planned. Username and password authentication is current.
  • Customer portal. Planned. Clients today see status reports and approvals through links you send, not a portal they log into.

We list these here because pretending they exist would be the exact opposite of the point of this page.

What we want this to feel like

If you are evaluating PartnerView and the objection in your head is "they are too small for me to trust with this," the answer is not that we are not small. The answer is that we know exactly what kind of product this is, and we are not running it like a five-person consumer app.

A boutique tool can be a high-quality tool. We are trying very hard to prove the case.

For more detail on any of the above, the field notes cover several of these topics in longer form. The features catalog lists every shipped capability without marketing varnish.

The shadow ledger is over. Run the real one.

PartnerView is in pilot with select monday.com and HubSpot partners. If you're a partner services firm doing $1M–$10M of services revenue, we'd like to talk.

Get a demo