Skip to main content
Custom SoftwareOffense-Informed SecurityLive Product

We Built Our Own Support Ticketing System

Production-grade, multi-tenant, offense-informed, and shipped in weeks — not months. This is why we did it, how we thought through it, and what it proves about the way ThinkOpen delivers technology.

April 2026

30+
Features Shipped
3
Active Client Orgs
17
Audit Findings Addressed
100%
ThinkOpen Owned

01 · The Decision

Why We Built Instead of Buying HelpSpot

HelpSpot is a respectable SaaS ticketing product used by many managed service providers. We evaluated it seriously. We chose to build our own anyway. Here is the thinking behind that call.

The criteria we scored against

Every technology decision at ThinkOpen runs through the same five-layer mental model: Technical · Security · Operations · Business · Human. HelpSpot won on operations — it ships today. It lost on the four that matter most over a five-year horizon.

CriterionHelpSpot (SaaS or Self-Hosted)ThinkOpen Custom Build
Data ownershipVendor-managed storage, export tied to their schemaOur Supabase instance, our schema, our backups, our encryption keys
Client compliance framing"A third-party vendor holds your fiduciary client data""ThinkOpen holds it directly in an infrastructure we can audit line-by-line"
Customization velocityPlugin API, support tickets, vendor roadmap wait timesNew feature on Friday, shipped by Monday. No vendor dependency.
UX controlGeneric vendor design, branding limited to logo swapApple-palette design language matching every other ThinkOpen deliverable
Five-year costRecurring seat-based licensing that grows with headcountOne-time build, near-zero marginal cost per engineer added
Security postureShared responsibility model — we inherit vendor CVEsOffense-informed by design, CEH-mindset audited, remediated in-house
Proof to prospects"We use HelpSpot" — zero differentiation"We built ours in 120 hours. Imagine what we can build for you."

The Strategic Insight

Every client engagement we win is partly because the prospect believes we can deliver technology at a level they cannot hire in-house. A ticketing system we use ourselves, built to a higher standard than the off-the-shelf alternative, at a fraction of the traditional build cost — that is not just internal tooling. It is a sales exhibit.

The honest risks we accepted going in

  • Maintenance burdenwe own it forever, we patch it forever. But we also own our stack end-to-end for clients we already support, so this was a capability we had to have regardless.
  • Security responsibilityno vendor to blame. Which is exactly how ThinkOpen positions itself anyway: "offense-informed, we own our security outcomes." Building our own forced us to live that principle internally.
  • Initial velocity riska traditional build might take months. Our AI-augmented workflow collapsed that to weeks. The economics section below shows the real numbers.

02 · Architecture

How It's Wired Together

One Next.js application, two subdomains, three identity flows, and a clean separation between client-facing and engineer-facing surfaces. Every box below is intentional — no accidental dependencies, no vendor lock-in traps.

Client UsersTRC · GUR · SYSBrowser / Mobilesupport.thinkopen.netThinkOpen EngineersAdmin / Engineer / ViewerBrowserstaff.thinkopen.netVercel Edge NetworkHTTPS termination · Host-based rewrites · Cron · Static assetsNext.js 16 Application (App Router)Server Components · Server Actions · API RoutesHost-aware login page · Portal resolution via headers()requireTicketAccess() on every ticket-scoped mutationRate limiting (per-email, per-IP, per-user)Authentication LayerNextAuth (Auth.js)Microsoft Entra SSO (staff)Resend magic link (clients)signIn() hard-reject boundarySupabase Postgresusers · organizations · ticketscomments · attachments · audit_logsessions · time_entries · hour_bucketsDrizzle ORM · type-safe queriesSupabase StorageEncrypted file bucketSigned URLs never exposedFile proxy API routeInternal / public visibility flagMicrosoft Entra IDMFA · Conditional AccessResend APIDedicated DKIM subdomainBarracuda ESSOutbound mail filterdmarcianDMARC RUA aggregation
Application Runtime
Next.js 16

App Router, server components, server actions. TypeScript throughout. Zero client-side state library — all state lives in the database and flows through server actions.

Data Layer
Supabase + Drizzle

Postgres for structured data, Storage for files. Drizzle ORM for type-safe queries. Schema migrations run via node scripts against DATABASE_URL.

Identity & Email
Entra + Resend

Microsoft Entra SSO with MFA and Conditional Access for staff. Resend magic link for clients, with DKIM on a dedicated subdomain. DMARC at p=none during observation.

03 · Progressive Delivery

From Zero to Production in Phases

We did not try to boil the ocean. Each phase shipped a working system — useful on its own — with the next phase building on the previous. This is how ThinkOpen delivers every client engagement: ship the minimum, prove it works, iterate with data.

Phase 0 — Foundation

Week 1

Scaffolded the Next.js app, provisioned Supabase, wired NextAuth with magic link and Microsoft Entra SSO, designed the initial schema in Drizzle ORM. Deployed to Vercel on day two.

Phase 1 — Core Ticketing

Week 2

Full ticket CRUD with status enums, priority levels, SLA config per priority, ticket numbering (YYYYMMDD-NNNNNN atomic counter), internal vs public comments with visibility control, audit log infrastructure.

Phase 2 — Organizations & Access

Week 2–3

Parent/child organization hierarchy with domain-based child detection (email domain maps to subsidiary automatically), engineer-to-organization assignments, role-based access control (admin · engineer · viewer · client).

Phase 3 — Files & Rich Comments

Week 3

File attachments with internal-by-default policy for engineers (compliance), Supabase Storage integration, file proxy API that never exposes signed URLs to the browser, overlay file viewer modal with blurred backdrop.

Phase 4 — Notifications & Workflow

Week 3–4

Email notifications via Resend for status changes, assignments, resolutions, and mentions. Daily digest cron via Vercel Cron. Client satisfaction rating on resolved tickets. Ticket reassignment with full audit trail.

Phase 5 — Time & Money

Week 4–5

Start/stop timers with pulsing live counter. Time entries linked to tickets and engineers with billable flag. Hour buckets (prepaid pools per engineer) with 50/75/90/100% threshold alerts. Idle timer auto-stop. Engineer hourly rate with inline Apple-style editor. Payroll with unpaid balance and self-healing for legacy zero-rate entries.

Phase 6 — Engineer Presence & Ops

Week 5

Real-time engineer presence tracking (online / idle / busy / meeting / offline) via heartbeat API. Ticket takeover with audit and previous-assignee notification. Organization lifecycle (trash with 30-day recovery, auto-archive with 7-year retention). Disaster recovery backup/restore tool producing AES-256 encrypted bundles.

Phase 7 — Security Hardening: Portal Split

April 2026

Triggered by a real incident: an engineer authenticated via magic link, bypassing our Microsoft Entra MFA and Conditional Access enforcement. We split the login surfaces in half — support.thinkopen.net became clients-only with magic link, staff.thinkopen.net became engineers-only with SSO. Server-side hard rejection layer added so the rule cannot be bypassed via direct HTTP calls. Shipped in one day.

Phase 8 — Unseen Gaps Audit

April 2026

Because closing one attack path never means the system is done. Eight-gap offense-informed audit across privilege escalation, access control, rate limiting, session lifecycle, email authentication, endpoint authorization, and normalization edge cases. Seventeen findings surfaced — three Critical, two High, six Medium, six Low/Info. All Critical and High items remediated in a single atomic deploy.

Phase 9 — Email Authentication Foundation

April 2026

Enabled Microsoft 365 DKIM signing via the new managed DKIM format. Published DMARC at p=none with aggregate reporting to dmarcian. Verified both outbound mail paths — M365-via-Barracuda and Resend-via-SES — pass SPF + DKIM + DMARC alignment. Now in the 14-day observation window before progressive enforcement.

04 · Capability Surface

Thirty-Plus Production Features

Every feature listed here is live in production, used daily, and has shipped code with a verification step. Nothing on this list is theoretical or roadmapped.

Ticketing Core

Full CRUD + SLA

Create, update, assign, resolve. SLA targets configurable per priority. Atomic YYYYMMDD-NNNNNN numbering.

Internal vs Public Comments

Engineers can post internal notes visible only to other engineers, or public replies visible to the client.

Domain-Based Auto-Assignment

Client email domain maps to a subsidiary organization automatically — no manual sorting.

Audit Trail

Every state change — status, priority, assignment, comment edit, takeover — logged with actor and timestamp.

Ticket Takeover

Engineers can take over tickets from colleagues with one click. Previous assignee gets notified.

Org Reassignment

Inline org dropdown on the contact card lets engineers correct mis-routed tickets.

Client Satisfaction Rating

Resolved tickets automatically prompt the client for a satisfaction rating.

Comment Edit with History

Internal comments editable with full audit trail — old value preserved.

Files & Rich Content

File Proxy API

Files stream through a server API route. Supabase signed URLs are never exposed to the browser.

Internal-by-Default

Engineer-uploaded files default to internal visibility. Compliance-safe without forcing a checkbox every time.

Overlay File Viewer

Images and PDFs open in a blurred-backdrop modal. No tab switching, no losing context.

Comment-Scoped Attachments

Files linked to specific comments, not just the ticket globally. Preserves conversational context.

Collapsible Long Content

Comments over five lines collapse to "Show more / less" — avoids the wall-of-text problem.

MIME Type Allow-List

Explicit allow-list of file types. 10 MB size limit. Uploaded filename sanitization.

Time & Money

Live Timers

Start/stop timer on any ticket. Pulsing red indicator. Live elapsed counter in the UI.

Idle Auto-Stop

Timers exceeding two hours auto-stop and email the engineer. Prevents forgotten-overnight timers.

Hour Buckets

Prepaid hour pools per engineer per organization. Progress bars with color escalation.

Threshold Alerts

Automatic email alerts at 50 / 75 / 90 / 100% bucket usage — admins get warned before overrun.

Engineer Hourly Rate

Per-engineer rate stored. Rate snapshotted onto time entries so retroactive changes do not rewrite history.

Payroll with Self-Healing

Unpaid balance computed with fallback to current rate for legacy zero-rate entries. Record-payment action backfills.

Time Reports

Rolling 30-day reports by engineer and by organization. Billable vs non-billable breakdown.

Inline Rate Editor

Apple-style inline editor with ✓/✕ buttons, Enter/Esc keys, and a "Saved" flash. No modal dialogs.

Identity & Access

Dual Portal

staff.thinkopen.net (SSO only) and support.thinkopen.net (magic link only) — enforced at UI, middleware, and server.

Configurable Staff Tenants

STAFF_TENANT_DOMAINS environment variable — add new owned domains without a code change.

Role-Based Access Control

admin · engineer · viewer · client. Checked at layout, action, and API layer.

Ticket Access Guard

requireTicketAccess() called on every ticket-scoped mutation. Cross-tenant actions impossible.

Engineer Management

Admin-only add/remove engineers. Elevation purges legacy sessions and forces SSO re-auth.

Parent/Child Org Model

Engineers assigned to a parent org automatically see all subsidiary tickets.

Operations & Reliability

Engineer Presence

Real-time online/idle/busy/meeting/offline tracking via heartbeat API. Visible in admin shell.

Daily Digest Cron

Vercel Cron runs daily at 7 AM Pacific. Sends per-engineer digest of open tickets grouped by age.

Org Lifecycle

Soft-delete to trash with 30-day recovery. Auto-archive after seven years via daily cron. Nothing lost, nothing clutters.

Backup/Restore Tool

One command produces an AES-256 encrypted ZIP of DB, storage, secrets, and code. One-command restore.

Rate Limiting

Per-user, per-email, per-IP limits on every mutation and public endpoint. HTTP 429 on violation.

Session Lifecycle

Seven-day max session age with 24-hour rolling refresh. Down from NextAuth default of 30 days.

05 · Offense-Informed Security

How We Think About Security

Security-by-design is a phrase everyone uses. The way we prove it is by running the same offense-informed playbook on our own product that we run on every client engagement — and publishing the findings.

The thinking behind every control

Before any feature ships, we ask the same five questions:

  1. What asset is at risk? Is it client data, session tokens, files, credentials?
  2. What is the threat vector? Who attacks this, how, and why?
  3. What is the current exposure? Is there a gap between the assumed control and the actual code?
  4. What is the recommended control? Not the obvious one — the one that makes the attack infeasible.
  5. What is the residual risk? What remains after the control, and is it acceptable?

This is the CEH threat modeling template applied to every architectural decision. When we wire a new server action, the question "how would an attacker abuse this?" is asked before the code is written.

Phase 1 — The Portal Split

A ThinkOpen engineer logged in via magic link one afternoon, bypassing the Microsoft Entra MFA and Conditional Access policies we had spent time configuring. It was not malicious — they were tired and clicked the wrong button on a login page that offered two equivalent-looking options. But the consequence was real: a staff session established without MFA, outside Conditional Access, invisible to our identity audit trail.

The standard response would have been a Slack reminder. We treated it as a design failure and rebuilt the login architecture in a day.

What we shipped

  • Two subdomains, two surfaces. support.thinkopen.net shows only the magic link form. staff.thinkopen.net shows only the Microsoft SSO button. Neither option exists on the other.
  • Host-aware rendering via server-side headers() detection — same route file, different UI depending on which subdomain served the request.
  • A hard server-side rejection layer. Even if an attacker bypasses the UI and posts directly to the auth API with a staff email, the signIn callback refuses the attempt. UI is defense-in-depth. The callback is the boundary.
  • Configurable tenant policy via environment variable, so adding future staff domains is a zero-code change.

Shipped and Verified

Five end-to-end tests covering every combination of email, portal, and bypass attempt. All passed before traffic was allowed through.

Phase 2 — The Unseen Gaps Audit

Closing the portal gap surfaced an uncomfortable question: what else might be wrong that we have not looked at? ThinkOpen's standard engagement methodology includes a passive-recon and gap-analysis pass on every client. We ran that same playbook on ourselves.

The eight audit gaps

GapWhat we looked forResult
A · Privilege EscalationEvery code path that assigns elevated roles. Can an attacker get there without MFA?Critical · Found
B · Rate LimitingEndpoints that send email, SMS, or create state. Are they protected from enumeration and abuse?High · Found
C · Email AuthenticationSPF, DKIM, DMARC. Can someone spoof our domain with no downstream block?Critical · Found
D · Session LifecycleHow long do sessions live? Can an exfiltrated cookie be used from a different device?Medium · Found
E · Dual-Linked AccountsAre any identities linked to multiple providers in ways that create lateral-move paths?Clean
F · Hidden RoutingAny redirects or rewrites configured outside the repo that could be a blind spot?Low · Found
G · Normalization GapsString comparisons used as security boundaries. Do they handle whitespace, unicode, case?Medium · Found
H · Endpoint AuthorizationEvery API route and server action. Does the auth check match the data being accessed?Critical · Found

What came out of it

Seventeen findings total, categorized and ranked. Three required immediate action, two were high-priority, six were medium, six were low or informational. The audit itself is documented in a separate ThinkOpen-branded internal report.

3
Critical

Infrastructure disclosure, privilege escalation bypass, and absence of email spoofing defense. All remediated in the first deploy.

2
High

Cross-tenant IDOR on ticket-scoped actions and zero rate limiting on the sign-in endpoint. Both closed in the same sprint.

6
Medium + Low/Info

Session hardening, normalization, policy cleanup. Staged across subsequent sprints without urgency.

Sprint 1 Remediation — One Atomic Deploy

Every Critical and every High finding, plus three of the Mediums, shipped as a single verified deploy. The shape of the work:

Infrastructure exposure

A debug endpoint that had been helpful during initial development was still public and responding to unauthenticated requests. Deleted. Whatever diagnostic information remains necessary is captured in server logs instead.

Privilege escalation boundary

The admin action that elevates a user to engineer role now requires the target email to be in the staff tenant allow-list, purges any existing sessions on the user being elevated, deletes any legacy magic-link account rows, and writes a structured log entry. An admin can no longer accidentally elevate a client, and an attacker with a live client session cannot have it silently upgraded to engineer privilege.

Cross-tenant access control

Every server action and API endpoint that accepts a ticket identifier from user input now calls requireTicketAccess() before operating. A client in organization A cannot post comments on, upload files to, or take any action against a ticket in organization B, regardless of whether they know the ticket identifier.

Authentication abuse prevention

Magic-link sending is now rate-limited per email at five requests per 15 minutes. Public chat and form endpoints are rate-limited per IP at five and three per hour respectively. The limits return HTTP 429 on violation, proven in smoke test.

Session lifecycle tightening

Session max age reduced from NextAuth's 30-day default to 7 days with a 24-hour rolling refresh window. An exfiltrated session cookie has a three-week shorter validity window.

Normalization hardening

Staff tenant email matching now applies .trim() and Unicode NFKC normalization before the domain comparison. Closes a subtle class of bypass where a raw HTTP client sends whitespace or compatibility characters that browser forms would strip but the server would miss.

Deploy Smoke Tests

Four smoke tests verified in production immediately post-deploy: debug endpoint returns 404, both portal login surfaces render correctly, and rate-limit enforcement returned HTTP 429 on the fourth through sixth requests to a public form endpoint within a minute.

Sprint 2 — Email Authentication

The Critical-3 finding was the absence of a DMARC record on thinkopen.net. An attacker could clone one of our ticketing sign-in emails, spoof the sender, and harvest credentials from clients who had been trained to click our links. Fixing this required more than a DNS record — it required a staged rollout with observation data, which is why it is its own workstream.

What we shipped on day one

  • Microsoft 365 DKIM enabled for thinkopen.net using Microsoft's new managed DKIM format, hosted on Azure DNS via an ICANN-delegated brand TLD.
  • DMARC TXT record published at p=none with aggregate reporting going to dmarcian — observation mode, no mail flow impact.
  • mail-tester.com verification on both outbound paths: M365-via-Barracuda scored 10/10, Resend-via-SES scored 8/10 with the two lost points being transient shared-IP blocklist noise, not authentication failures. DMARC alignment passed on both paths.

The progressive enforcement plan

Day 1 to Day 14 is pure observation. Aggregate DMARC reports flow into dmarcian and we watch for any legitimate sender that is failing alignment, for spoofing attempts, and for the volume baseline. At Day 15 — assuming clean reports — the policy moves to p=quarantine. At Day 22, if still clean, it moves to p=reject. That is the end state: spoofed mail from our domain gets refused at the receiving server.

At no point during this rollout does any change touch Barracuda Email Security Gateway, Exchange Online connectors, accepted domains, or mail flow rules. The only things that move are DNS records and a DMARC policy string.

Data Safety Note

This case study intentionally omits specific file paths to vulnerable code as it existed before remediation, infrastructure identifiers (project IDs, API key prefixes, IP addresses), and specific ticket identifiers or client data beyond publicly-known engagement names. The audit report with full technical detail is an internal-only document. Everything here is safe to share externally.

06 · UX & Human Behavior

Design Choices Rooted in How People Actually Work

Good security UX is not about friction. It is about making the right path the easy path, and the wrong path structurally unavailable. Every design decision in this product traces back to either a specific user-behavior observation or an offense-informed threat model.

Path of least resistance wins every time

Humans, even trained ones, take the fast path under cognitive load. A single login page with two equivalent-looking options will produce the "wrong path" behavior a nontrivial fraction of the time. The solution is not to add a warning label — it is to remove the wrong option entirely from the surface where it does not belong. Hence the dual portal. Clients never see the SSO button. Engineers never see the magic link field. The decision is made by the URL, not the user.

Subtle cues get ignored under load

During the portal split design review, the first proposal was a small "Staff? Use Microsoft" label under the magic link form. We rejected it. A label the user has to read, recognize themselves in, and consciously act on is three failure points stacked. Either the distinction is loud enough to route behavior, or it is decoration. We picked loud.

Apple palette, no exceptions

Every surface — ticket list, admin dashboard, settings, login, email templates — uses the same color vocabulary, the same typography stack, the same spacing rhythm. One accent, one critical, one success, one warn, one info. Orange means "pay attention." Red means "do not do this." Blue means "primary action." Consistency across surfaces reduces the cognitive tax of learning the interface.

Inline editing, never modal dialogs

Browser prompt() dialogs are an anti-pattern. They break context, they cannot be styled, they cannot be keyboard-navigated consistently. Every inline edit in this product is a compact form that appears in place with ✓ and ✕ buttons, supports Enter to save and Escape to cancel, and flashes a brief "Saved" indicator on success.

Files open in place, not in new tabs

A "new tab" file view loses conversational context. Our file viewer is an overlay modal with a blurred backdrop — the ticket remains visible, the file is the focus, one click dismisses and you are exactly where you left off.

Collapsible long content

Long comments become wall-of-text noise that flattens the reading hierarchy. We automatically collapse comments over five lines to a "Show more" preview. The default view remains scannable.

Real-time presence because silence is confusing

When a client files a ticket and then wonders "did anyone see it," the cost is low-grade anxiety and sometimes a follow-up email that doubles our ticket volume. Our admin shell surfaces engineer presence — online, idle, busy, meeting, offline — so admins can route work to the right person, and so clients asking over the phone "is anyone there" get an accurate answer.

07 · The Economics

What This Would Have Cost — Three Ways

A fair comparison requires an honest scope and honest rates. Below is the scope of work in hours, estimated from the actual feature set, the actual security remediation work, and the actual email authentication rollout. Then the same scope costed three ways.

The scope in hours

Summing the major work streams at traditional-shop velocity (one senior engineer, no AI augmentation, full test coverage, PM overhead):

Work StreamEst. Hours
Authentication — dual portal, SSO, magic link, role-based layouts60
Ticketing core — CRUD, SLA config, numbering, enums, state machine80
Comments and attachments — visibility model, file proxy, overlay viewer50
Organization hierarchy — parent/child, domain detection, trash lifecycle40
Engineer management — presence, assignments, takeover, audit log40
Time tracking — timers, entries, buckets, alerts, idle detection80
Payroll — hourly rates, unpaid balance, self-healing queries30
Email notifications — templates, triggers, daily digest cron30
Admin UI — settings, reports, dashboard, engineers page60
Client portal UI — ticket list, ticket detail, rating flow30
File storage pipeline — upload, proxy API, preview modal, MIME allow-list40
Audit log infrastructure and enum coverage20
Backup and restore tooling — encrypted bundles, one-command restore20
Bug fixing and testing across the build40
Security audit — eight-gap offense-informed pass and report12
Remediation — ten security fixes in one atomic deploy12
DMARC and DKIM hardening, vendor evaluation, rollout plan8
Total652

Traditional Dev Shop

US Consulting Firm
$162,000
All-in, twelve to sixteen weeks
  • Senior engineer rate$200/hr
  • Base hours652
  • Base cost$130,400
  • PM + QA overhead+25%
  • Design consultingincluded
  • Timeline3–4 months
  • AI augmentationminimal

Senior Freelancer

US, Top Tier
$93,000
Typically, with rework cycles
  • Freelancer rate$125/hr
  • Base hours652
  • Base cost$81,500
  • Rework cycles+15%
  • Design polishextra
  • Timeline4–6 months
  • AI augmentationvaries
Recommended

ThinkOpen

AI-Augmented Engineering
$28,000
At our standard $175–200/hr rate
  • Blended rate$187.50/hr
  • Effective hours~130
  • Base cost$24,375
  • Verification + test+15%
  • Design systemreused
  • Timelineweeks
  • AI augmentation5× velocity

Why the ThinkOpen number is what it is

Our rate is not cheap. $175–200 per hour is a premium rate that reflects senior engineering and a security-first methodology. The savings do not come from cheaper labor — they come from roughly five-times velocity on well-scoped work, driven by AI augmentation applied by an engineer who already owns the client context and the stack.

What a traditional shop bills for eight hours of research, scaffolding, and boilerplate, we can produce in under two hours because the AI does the boilerplate while the engineer stays at the architectural level. That ratio holds across most of the build except the work that genuinely requires deep, slow thinking — security audit, threat modeling, and remediation design — where we spend the same human time a traditional shop would, because that work is where the value lives.

Compared to HelpSpot

HelpSpot cloud pricing at our engineer count is roughly $1,000 to $2,500 per year, recurring forever, in exchange for generic UX and no customization velocity. Over a five-year horizon, $5,000–$12,500 of license cost buys you a product you do not control. Our $28,000 buys a product we can extend at will and use as a sales exhibit.

Hidden Value Beyond the Line Items

Every feature we ship here becomes institutional knowledge, reusable code, and a reference implementation for client engagements. Time tracking with bucket alerts is not just our internal tool — it is a capability we now know how to build for any client in days, not months.

08 · Production Snapshot

What Is Live Right Now

As of April 2026. This system is handling real client tickets from real organizations today.

3
Active Client Orgs

TrusteeCorps, Ground Up Renovations, Sysblocks — plus ThinkOpen internal.

3
Subsidiaries

Parent/child hierarchy in production under TrusteeCorps.

30+
Features Shipped

Every one in production use, documented, and tested.

17
Audit Items Closed

Every finding from the Phase 2 audit has a remediation state.

Current security posture

ControlStateNotes
Dual portal authenticationLiveFive E2E tests passed
Cross-tenant access controlLiverequireTicketAccess on every action
Privilege escalation boundaryLiveSession purge on role elevation
Rate limiting — auth pathsLivePer-email and per-IP
Rate limiting — public endpointsLiveHTTP 429 verified in smoke test
Session lifecycleLive7 days max, 24h rolling
Email: SPFLiveOutlook + Barracuda + Resend
Email: DKIM (M365)LiveManaged DKIM via Microsoft
Email: DKIM (Resend)LiveSubdomain-based, signed
Email: DMARCObservingp=none, 14-day window
Disaster recoveryLiveEncrypted backup + restore tool

09 · What's Next

The Roadmap From Here

Every item on this list is planned, not speculative. Each one has a defined trigger and a defined outcome.

Two weeks out

  • DMARC to quarantine — after 14 days of clean observation data from dmarcian, move the DMARC policy from p=none to p=quarantine. One-line DNS change, reviewed against the aggregate reports.
  • Sprint 2 Medium findings — viewer role scope audit, IP-layer rate limiting for authenticated actions, magic-link email template refresh.
  • Rate limit store to Vercel KV — migrate from the in-memory serverless store so limits enforce consistently across instances.

Four weeks out

  • DMARC to reject — the end state. Spoofed thinkopen.net mail refused at the receiving server.
  • Add additional staff tenant domains to the allow-list via environment variable once the accounts are ready for MFA enrollment.
  • Mobile keyboard fix for the known iOS landscape input issue.

Productization track

  • Multi-tenant extraction — the product is architected as multi-tenant today but configured as single-tenant. Separating the tenant boundary is a known task for the SaaS productization path.
  • Self-serve onboarding — if we ever ship this as a SaaS for other MSPs, the onboarding flow needs to handle org creation, domain verification, and initial admin provisioning automatically.
  • Pricing model evaluation — per-engineer, per-ticket, or flat infrastructure fee. Market research needed.

Continuous posture

  • Quarterly offense-informed audit — same eight-gap playbook applied every three months against the current codebase.
  • Dependency update discipline — Next.js, Supabase client, NextAuth, Drizzle ORM. Watch the release notes. Patch within 72 hours of any advisory.
  • Client feedback loop — client satisfaction ratings surface in the weekly digest and feed directly into feature prioritization.

10 · The Pitch

This Is What We Can Build For You

If ThinkOpen's internal ticketing platform can ship at this velocity, with this security posture, at this economics — imagine what that capability looks like pointed at your infrastructure problem.

For IT leaders

Custom internal tooling, client portals, audit dashboards, compliance reports. Built at weeks-not-months velocity. Owned by you, not a vendor.

For security-conscious firms

Offense-informed design reviews, penetration test readiness, DMARC/DKIM rollouts, M365 hardening, incident response retainers, quarterly audits.

For regulated industries

Fiduciary-grade data handling, compliance-aware architecture, lender/insurer-ready documentation, end-to-end encryption, disaster recovery runbooks.

Book a 30-Minute Discovery Call

424.437.8173 · info@thinkopen.net