Skip to content
James Builds Tech
Go back

Certinance: from product build to commercial launch

Certinance product overview showing document control, renewal tracking and expiry alerts

Product case study · October 2026

I built Certinance for UK businesses to keep certificates and other records together, track expiry dates and send reminders. This case study covers the work on the app, subscription billing, testing and the October 2026 launch.

3subscription tiers
820tests passed at acceptance
14 daysfree trial
GOcommercial release status

The product

Certinance is aimed at teams in construction, property, maintenance and other businesses managing compliance documents. It keeps records, dates and supporting files together, with team permissions and options for sharing selected documents.

Certinance product overview featuring document control, expiry reminders, secure sharing and team access

A static frontend with service boundaries

I built the interface with Next.js, React, TypeScript and Tailwind CSS. Next.js exports the public site and application shell as static files for Firebase Hosting. The browser then resolves the signed-in user and their workspace through Firebase Authentication and Firestore. The static export keeps hosting separate from the services that handle billing, document access and reminders.

Firestore holds organisation membership, certificate records, document-version metadata and subscription state. Cloudflare Workers handle operations that need trusted server-side credentials. That includes creating Stripe sessions and authorising private document access; neither operation relies on a secret shipped in the frontend.

Workspace membership is part of the data model

A signed-in account alone is not enough to access an organisation's records. Firestore rules and the Worker authorisation layer check active workspace membership, organisation scope and role. Owners, administrators and viewers have different permissions. Write operations also check the subscription or trial entitlement and applicable usage limits.

This distinction matters when a subscription changes or a member leaves. The interface can explain why an action is unavailable, but the backend still needs to enforce that decision independently. The rules and services are tested for those boundaries as well as the normal customer workflow.

Billing state comes from Stripe, not the success page

The billing Worker creates Stripe Checkout and Customer Portal sessions after checking the workspace owner. Checkout handles the subscription purchase; the portal gives the customer a way to manage the plan. The documented launch behaviour applies upgrades immediately with proration and downgrades at renewal.

Returning from Checkout is not treated as proof of payment. Signed Stripe webhooks drive the stored subscription state. The service retrieves the subscription, checks its organisation and billing mode, then projects the result into Firestore. Event handling distinguishes applied, duplicate, stale and ignored updates, so repeated notifications do not become repeated state changes.

Keeping a PDF and its record in sync

The customer PDF implementation uses Cloudinary authenticated assets behind a Cloudflare Worker. Firestore stores the document record and immutable file-version metadata. Before an upload or download, the service checks the user, workspace and relevant entitlement. Upload completion verifies the provider response and file identity before updating the current-version pointer.

That separation is useful for replacements: a certificate can point to a newer PDF while its previous version remains identifiable. Downloads require authorisation rather than exposing a permanent public file URL. The repository also contains an R2 storage implementation; it should not be confused with the customer Cloudinary path described here.

Scheduled reminders and delivery history

The reminder service runs in a scheduled Cloudflare Worker and sends transactional email through Resend. It reads configured reminder rules, selects recipients and records delivery state. A Durable Object coordinates claims and retries so the same expiry milestone is not repeatedly sent to the same recipient.

Provider acceptance and inbox delivery are different events. The implementation uses signed provider webhooks to update the delivery history rather than presenting a successful API request as confirmed delivery. It also keeps operational delivery records separate from the notification preferences a customer can edit.

Testing across the browser and services

The 27 October acceptance record brings together unit tests, Worker tests and Firebase rules tests: 672, 38 and 110 passing respectively. Those make up the recorded 820 passes; two optional scanner integrations were skipped. TypeScript, ESLint, the production build and SEO checks were also part of the release gate.

The production acceptance work went beyond compiling the app. It exercised document saving, private PDF handling, administrator permissions, notification persistence and scheduled delivery. The release received GO status for its approved commercial scope. These are dated acceptance results, not a claim that every later release or deployment has been checked in the same way.

Development timeline

Here’s how the launch came together. October’s work covered the commercial terms, billing, expiry notifications and the final production checks.

Development Deployment Testing Commercial
October 2026
Commercial

Commercial foundations

I set up the UK business-to-business model, subscription pricing, 14-day free trial and customer data-retention policies.

23 Oct 2026
Deployment

Live subscription billing

I activated live Stripe billing and Checkout: Starter at £19/month, Business at £49/month and Professional at £99/month.

Development

Self-service plan management

I added the Stripe Customer Portal so customers could change plans themselves. Upgrades apply immediately with proration; downgrades take effect at the next renewal.

Deployment

Automated expiry notifications

The reminder system went live with configurable schedules, a choice of team recipients and notification history.

27 Oct 2026
Commercial

LiveShare publicly announced

I announced LiveShare through the company LinkedIn page. This is the announcement date, not a claim about when development was completed.

Testing

Production hardening completed

The final production checks covered authentication, billing, document handling, secure downloads, permissions, notifications, quotas and audit records.

820 automated tests passed 2 optional malware-scanner tests skipped 0 outstanding confirmed P0/P1 defects

These were the acceptance results on 27 October 2026, rather than a guarantee about every future release.

Commercial

Commercially ready

The production release received GO status for the approved commercial scope.

Commercial

Customer acquisition phase

After release, I shifted my attention to finding customers, business outreach and subscription revenue.

A look at the app

What I worked on

Product designDesigning the document register, expiry views and renewal workflow.
Full-stack engineeringBuilding access controls, subscriptions, document handling, notifications and reporting.
Release disciplineChecking the release and reviewing defects before going live.
Commercial executionSetting pricing and trial terms, connecting billing and preparing to find customers.
Businesses and teams Certinance is designed to support

Share this post on:

Previous Post
Building QuikTax: four days, from iPhone to web
Next Post
Mixwell: a watercolour mixing companion