Skip to main content
By the end of this guide you’ll have a working Next.js app with a live Google Calendar dashboard — and you’ll have written almost none of the UI yourself.

Corsair context prompt for your agent

Paste this before your feature prompt so the agent knows how Corsair works:
This app uses Corsair. Every Corsair plugin has two namespaces:

  corsair.<plugin>.db   — reads from the local database (no network, instant)
  corsair.<plugin>.api  — calls the live external API

Both follow the same shape: corsair.<plugin>.[db|api].<group>.<method>(args)

When to use which:
- Rendering UI / reading data → .db (always the default)
- Creating, updating, or deleting → .api
- User-triggered refresh / sync → .api, then re-read from .db
- Every .api response is auto-saved to .db

Entity data is on .data in camelCase. Use .search({}) or .list() on .db to query.

To see what's available, run:
  pnpm corsair list --<plugin>
1

Scaffold the T3 app

npm create t3-app@latest my-cal-dashboard -- --CI --trpc --tailwind --appRouter
cd my-cal-dashboard
2

Install

npm install corsair @corsair-dev/googlecalendar
3

Generate your encryption key

Corsair encrypts stored credentials with a Key Encryption Key. Click Regenerate for a new one, or run the command yourself:
Keep this key safe If you lose it, you lose access to all stored credentials. Treat it like a root password.
4

Migrate the database

Corsair needs five tables. Install the driver, then run the migration:
npm install better-sqlite3
npm install --save-dev @types/better-sqlite3
migration.sql
CREATE TABLE IF NOT EXISTS corsair_integrations (
    id TEXT PRIMARY KEY,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    name TEXT NOT NULL,
    config TEXT NOT NULL DEFAULT '{}',
    dek TEXT NULL
);

CREATE TABLE IF NOT EXISTS corsair_accounts (
    id TEXT PRIMARY KEY,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    tenant_id TEXT NOT NULL,
    integration_id TEXT NOT NULL,
    config TEXT NOT NULL DEFAULT '{}',
    dek TEXT NULL,
    FOREIGN KEY (integration_id) REFERENCES corsair_integrations(id)
);

CREATE TABLE IF NOT EXISTS corsair_entities (
    id TEXT PRIMARY KEY,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    account_id TEXT NOT NULL,
    entity_id TEXT NOT NULL,
    entity_type TEXT NOT NULL,
    version TEXT NOT NULL,
    data TEXT NOT NULL DEFAULT '{}',
    FOREIGN KEY (account_id) REFERENCES corsair_accounts(id)
);

CREATE TABLE IF NOT EXISTS corsair_events (
    id TEXT PRIMARY KEY,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    account_id TEXT NOT NULL,
    event_type TEXT NOT NULL,
    payload TEXT NOT NULL DEFAULT '{}',
    status TEXT,
    FOREIGN KEY (account_id) REFERENCES corsair_accounts(id)
);
sqlite3 corsair.db < migration.sql
5

Create src/server/corsair.ts

src/server/corsair.ts
import 'dotenv/config';
import Database from 'better-sqlite3';
import { createCorsair } from 'corsair';
import { googlecalendar } from "@corsair-dev/googlecalendar";

const db = new Database('corsair.db');

export const corsair = createCorsair({
    plugins: [googlecalendar()],
    database: db,
    kek: process.env.CORSAIR_KEK!,
});
6

Connect Google Calendar

Google Calendar uses OAuth2. You’ll need a GCP OAuth app first:
  1. Go to the Google Cloud Console, create a project, and enable the Google Calendar API.
  2. Under APIs & Services → Credentials, create an OAuth 2.0 Client ID (Application type: Web application). No redirect URI needed — Corsair handles it locally.
  3. Copy your Client ID and Client Secret, then store them:
npm install @corsair-dev/cli
npx corsair setup --googlecalendar client_id=YOUR_CLIENT_ID client_secret=YOUR_CLIENT_SECRET
If pnpm corsair isn’t found, add this to your package.json so pnpm builds the native dependency correctly:
package.json
{
  "pnpm": {
    "onlyBuiltDependencies": [
      "better-sqlite3"
    ]
  }
}
Then re-run pnpm install and retry the setup command.
  1. Start the OAuth flow:
npx corsair auth --plugin=googlecalendar
Open the authUrl printed in the terminal. Once you authorize in the browser, tokens are saved automatically and the command exits.
7

Vibe code the dashboard

Paste this prompt into Claude, Cursor, or any AI coding agent:
I have a Next.js T3 app. The Google Calendar plugin is connected via Corsair.

Build me a Google Calendar dashboard on the home page. I want to see:

- A stats row showing: how many events I have today, how many this week, what my next meeting is, and how many hours are blocked
today
- Today's full agenda — all my events for today in order with times and titles
- An upcoming events panel — my next couple weeks of events grouped by day
- A Create Meeting button that opens a form to schedule a new event
- A notes field on each meeting card where I can save and edit private notes per event (store these in a local table, not on Google
Calendar)
- A Refresh button in the header that fetches the latest events from Google Calendar and updates what's shown on screen, including
removing any events the user has deleted from Google Calendar

The app should use await corsair.googlecalendar.db as a cache — load from there first, and only call Google Calendar when the data isn't
cached yet, when creating an event, or when the user clicks Refresh. The page should not make any live API calls on its own after
the first load.
Run pnpm dev when it’s done.

What’s next

Google Calendar Plugin

Full API reference — create events, check availability, and handle webhook notifications.

Webhooks

React to calendar changes in real time — new events, updates, and deletions pushed to your server.

Workflows

Chain calendar events to other plugins — meeting created → Slack notification → Linear task.

Multi-Tenancy

Building a product? Each user gets their own calendar credentials and isolated data.