Skip to content
KW
Back to projects

sample 05/in production

SK Agency

A corporate site and a platform where each client follows their own contract, from onboarding to renewal.

  • Next
  • Prisma
  • GSAP
  • Three
  • Turbo

01

Context

SK Agency works in technology and marketing. The project combines the agency site with a platform where each client follows campaigns, reports, proposals, meetings and tickets, while the team runs everything from an admin panel.

In August, the site followed a change in positioning: from an audiovisual and ads agency to a technology and marketing software house.

02

Starting point

The project started with the site, built around a 3D visual narrative, and grew into the agency's operations.

1

corporate site with a 3D narrative

0

tools for clients to follow the work

0

payments or contracts in the system

03

Timeline

178 commits in the project history. These are the milestones.

  1. May 14, 2026

    Site with a 3D narrative

    A scroll-driven particle engine, an editorial system and the first case pages.

  2. May 16, 2026

    Contracts and integrations

    A 95-day contract cycle with pause and renewal, and an OAuth connection to Google Ads.

  3. May 17, 2026

    The client portal

    Proposals with two-way conversation, meeting scheduling, tickets, dashboards with real campaign data and fully private file storage.

  4. May 19, 2026

    Roles and protection

    Four roles with distinct permissions and rate limiting on public and authentication routes.

  5. May 27, 2026

    Guided onboarding

    A step-by-step journey for new clients, from commercial proposal to contract start.

  6. Jun 01, 2026

    Home performance

    In performance testing, the home page's largest element took 21 seconds to appear. WebP images, a dedicated mobile video and on-demand loading tackled it.

  7. Jun 03, 2026

    Payments with Stripe

    Checkout during onboarding, a webhook, upgrades with prorated billing and safety guards for live mode.

  8. Aug 15, 2026

    New positioning

    Home page rewritten for a technology and marketing software house, presenting Atlas as a product.

04

Decision map

Reconstructed from the commit history, the README and the project documentation.

01

The server owns the catalog

Prices, bundles and quotas are defined on the server and adjustable from the admin. The browser never says how much something costs.

02

The contract has a lifecycle

Each contract lasts 95 days, can be paused and renewed, and starts when onboarding ends. Clients see the deadline on their own screen.

03

Permissions in one place

One file says what each role can do, and every admin route checks those rules before acting.

04

Private by default

RLS on public tables and private file storage, accessed through expiring URLs.

05

Real data, not mocks

Dashboards show Google Ads campaigns synced automatically, with 90 days of history for the filters.

06

Heavy only where it fits

The hero's 3D and video run only on desktop. On mobile the page loads light, without giving up its identity.

05

Architecture

The same five layers as this page, applied to the project.

  1. 000 m/interface

    • Site with a 3D narrative
    • Client portal
    • Admin panel
  2. 030 m/route

    • Auth.js with role re-read every session
    • Rate limiting
    • CSRF-protected OAuth
  3. 060 m/service

    • Centralized role permissions
    • Stripe: checkout, webhook and proration
    • Google Ads sync
    • Email with Resend
  4. 090 m/repository

    • Prisma with Postgres
    • Server-side commercial catalog
  5. 120 m/persistence

    • RLS on public tables
    • Private files via expiring URLs

06

Code

An excerpt from the private repository, just to show the layer at work.

What each role can do

The middleware only asks whether the person is on the team. Each admin action checks its specific permission before running.

apps/web/lib/permissions.tsts
export type Role = "CEO" | "ADMIN" | "AGENT" | "CLIENT";

export const ADMIN_TIER: Role[] = ["CEO", "ADMIN", "AGENT"];

/** True iff the role is admin/agent/CEO — i.e. has access to /dashboard/admin. */
export function isAdminTier(role: Role | string | undefined | null): boolean {
  return !!role && (ADMIN_TIER as string[]).includes(role);
}

/** CEO only. */
export function canManageTeam(role: Role | string | undefined | null): boolean {
  return role === "CEO";
}

07

Outcome

4

roles with distinct permissions

95

days per contract cycle, with renewal

3

integrations: Stripe, Google Ads and Resend

Current status

In production at skagency.com.br.