OrbelithExplore the product
Full-stack engineering case study

Building Orbelith

Engineering a multi-tenant agency CRM from authenticated interface to tenant-scoped data boundary.

Role
Full-Stack Developer / Product Owner
Period
12 May–8 August 2026
Footprint
52 pages · 62 API routes
Data layer
113 versioned migrations
Building Orbelith full-stack engineering case study cover

01 — Engineering scope

One product across the agency operating system

The codebase connects client acquisition, project execution, communication, finance, people operations, reporting, portals, and integrations without splitting tenant identity across separate products.

01

Client lifecycle

Pipeline, brands, proposals, bookings, portals, approvals, invoices, and communication history.

02

Delivery operations

Projects, task boards, custom statuses, timers, workload, schedules, reporting, and activity history.

03

Finance and people

Expenses, accounting, profitability, payroll, allocations, attendance, leave, and employee records.

Portfolio boundary

This case documents engineering decisions. Product planning, interface design, manual QA, and scheduled automation are presented as separate cases so the implementation evidence is not confused with adjacent roles.

02 — System architecture

Layer trust boundaries instead of trusting the interface

Authenticated pages, public client surfaces, machine consumers, server routes, and Postgres policies each carry a different level of authority.

Orbelith multi-tenant full-stack system architecture

03 — Data authorization

Tenant and capability checks live beside the rows

The application does not treat hidden buttons as access control. Postgres policies resolve the signed-in organization, assigned brands, deletion state, and view/manage permission for every operation.

supabase/migrations/155_enforce_project_task_capabilities.sql

Row-level update policy

create policy "tasks_update" on public.tasks for update
  using (
    organization_id = public.my_org_id()
    and (brand_id is null
      or brand_id in (select public.my_brand_ids()))
    and deleted_at is null
    and public.can_manage('tasks')
  )
  with check (
    organization_id = public.my_org_id()
    and public.can_manage('tasks')
  );
src/app/api/v1/tasks/route.ts

Organization-scoped machine route

const auth = await authApiKey(req)
if (!auth) return unauthorized()
if (!(await apiRateAllowed(auth))) return tooManyRequests()

const { data: brand } = await auth.supabase
  .from('brands')
  .select('id')
  .eq('id', body.brand_id)
  .eq('organization_id', auth.orgId)
  .maybeSingle()

const row = {
  organization_id: auth.orgId,
  title: body.title.trim(),
}

04 — API boundary

Authenticate, throttle, validate, then write scope

An API key identifies one organization. Referenced records are checked inside that organization before a new row is written with an explicit tenant identifier.

05 — Integration architecture

Keep regional providers behind one contract

Invoices use a provider-neutral interface for hosted links and verified webhooks. Stripe, YooKassa, and LiqPay are implemented; Netopia and Paynet remain explicit scaffolds until merchant credentials are available.

src/lib/payments/types.ts

Provider contract

export interface PaymentProvider {
  id: ProviderId
  label: string
  region: string
  currencies: string[] | null
  implemented: boolean
  enabled(): boolean
  createLink(
    invoice: InvoiceForPay,
    options: CreateLinkOpts
  ): Promise<PaymentLink>
  parseWebhook(
    raw: string,
    headers: Headers
  ): Promise<WebhookResult>
}

06 — Engineering decisions

Grow the surface without weakening the foundation

The implementation uses a small set of repeated constraints rather than one-off security and delivery rules per feature.

01

Authorization lives with the data

Row policies combine organization scope, brand membership, deletion state, and view/manage capabilities. Hidden controls are never treated as the security boundary.

02

Server routes repeat tenant checks

API-key routes authenticate, throttle, validate referenced entities inside the same organization, and write organization_id explicitly.

03

Public surfaces carry narrow authority

Booking, proposal, portal, invoice, and tracking endpoints use purpose-specific slugs or tokens instead of opening the wider authenticated data surface.

04

Providers sit behind contracts

Payments and integrations expose stable server-side interfaces so core invoice and CRM flows do not depend on one regional provider.

05

Schema changes are product changes

Tenant isolation, permissions, billing, privacy, reporting, automation, and hardening ship as reviewable, versioned migrations.

06

Localization is infrastructure

The application, public pages, money, dates, email, notifications, reports, and generated output resolve RU/RO/EN through shared language services.

07 — Implemented product

Architecture expressed as a working interface

The product surface consumes the same organization, role, finance, localization, and activity contracts documented above.

Orbelith projects interface from the live owner workspace

52

product/public pages

62

API routes

113

SQL migrations

2,356

localized keys

08 — Outcome

A production foundation for continued product growth

The outcome is documented through implemented routes, policies, provider contracts, migrations, interface surfaces, and production delivery — not unsupported revenue or adoption claims.

  • One organization boundary spans browser, server routes, database rows, RPCs, files, and background workers.
  • Capability-based access distinguishes view and manage rights across product modules.
  • Token-protected public surfaces support client collaboration without exposing the authenticated application.
  • Provider contracts support regional payments without coupling invoice logic to one gateway.
  • A shared dictionary provides 2,356 localized message keys across Russian, Romanian, and English.
  • Versioned migrations preserve an auditable path from single-workspace CRM to multi-tenant SaaS.
  • The application is built, deployed, monitored, and validated as a live production product.
Building Orbelith — Full-Stack Multi-Tenant CRM Engineering