Skip to content

keton-id/vod

Repository files navigation


  ##   ##  #####  ####
  ##   ## ##   ## ##  ##
  ##   ## ##   ## ##  ##
   ## ##  ##   ## ##  ##
    ###    #####  ####

Virtual Office Dashboard — a self-hosted Google Workspace lobby

See who's in which Google Meet room, join or create rooms, and track presence — all from one dashboard.

VOD Dashboard


Features

  • Google OAuth login — workspace members and external guests use separate flows
  • Room management — workspace members create Meet-linked rooms via Google Calendar API
  • Presence tracking — heartbeat-based with sendBeacon fallback on tab close
  • Meet sync — on-demand sync pulls live participants from Google Meet REST API
  • Guest support — any Google account can join rooms; unresolved participants shown as "Guest XXXX"
  • Self-hosted — Postgres + Redis via Podman Compose, no managed cloud required

Stack

Layer Choice
Frontend Next.js 14 (App Router)
Auth NextAuth.js (Google Provider)
Database PostgreSQL 16 + Prisma ORM
Cache Redis 7 (ioredis)
Styling Tailwind CSS + shadcn/ui
Infra Podman Compose + Caddy
Monorepo pnpm workspaces + Turborepo

Quick Start

git clone <repo-url> && cd vod
make setup
# fill in .env and apps/web/.env.local with your credentials (see below)
make dev

That's it. make dev starts Postgres + Redis, runs migrations, and launches the web app.


Prerequisites

  • Node.js 20+
  • pnpm 9+
  • Podman + podman-compose
  • A Google Cloud project with OAuth 2.0 credentials

Google Cloud Setup

1. Create OAuth credentials

  1. Go to console.cloud.google.comAPIs & ServicesCredentials
  2. Create OAuth 2.0 Client ID → Application type: Web application
  3. Add authorized redirect URI: http://localhost:3000/api/auth/callback/google
  4. Copy the Client ID and Client Secret

2. Set OAuth consent screen to External

Go to APIs & ServicesOAuth consent screen → set User type to External.

If your app is unverified by Google, add Gmail test users manually under "Test users" so they can log in during development.

3. Enable required APIs

Enable these APIs in your Google Cloud project:

  • Google Calendar API
  • Google Meet REST API
  • People API

Environment Setup

Copy the example env file:

cp .env.example .env
cp apps/web/.env.example apps/web/.env.local  # create this if it doesn't exist

Fill in apps/web/.env.local:

# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-random-secret-here   # generate with: openssl rand -base64 32

# Google OAuth
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret

# Workspace domain — users with this email domain are "Members" (can create rooms)
# All other Google accounts are "Guests" (can only join rooms)
ALLOWED_WORKSPACE_DOMAIN=yourcompany.com
NEXT_PUBLIC_ALLOWED_WORKSPACE_DOMAIN=yourcompany.com

# Database & Redis (matches podman-compose defaults)
DATABASE_URL=postgresql://appuser:localdev123@localhost:5432/virtualoffice
REDIS_URL=redis://localhost:6379

Fill in .env (root, used by Podman Compose):

POSTGRES_DB=virtualoffice
POSTGRES_USER=appuser
POSTGRES_PASSWORD=localdev123
NODE_ENV=development

Running Locally

make setup          # copy env files + install deps (run once)
# edit .env and apps/web/.env.local
make dev            # start infra + migrate + launch web
make worker         # (separate terminal) start background worker

Open http://localhost:3000.

The worker handles presence cleanup (every 2 min) and Meet reconciliation (every 5 min) — optional for local dev but needed in production.

All available commands

make setup      Copy env files, install deps
make dev        Start infra + run migrations + start web (hot reload)
make worker     Start background worker
make up         Build and start full stack via Podman
make down       Stop all Podman services
make logs       Tail all service logs
make migrate    Run pending DB migrations
make generate   Regenerate Prisma client
make help       Show all commands

Running with Podman (Full Stack)

make up     # build + start all services (web, worker, postgres, redis, caddy)
make logs   # tail logs
make down   # stop everything

The app will be available at https://office.localhost via Caddy (self-signed cert — trust it once in your browser).


User Roles

Role Who Permissions
Member @yourcompany.com accounts Create rooms, close rooms, trigger Meet sync
Guest Any Google account Join existing rooms only

On the sign-in page, members and guests use separate buttons. Both use the same OAuth callback URL — no extra redirect URI needed in Google Cloud Console.


Meet Sync

The Sync button on the dashboard pulls live participants from Google Meet REST API using the room creator's stored OAuth token. Participants who haven't logged into VOD are shown as Guest XXXX and automatically registered when they eventually sign in.

Sync also runs automatically every 5 minutes via the background worker.


Project Structure

/
├── apps/
│   ├── web/                  # Next.js 14 app (frontend + API routes)
│   │   ├── prisma/           # Schema + migrations
│   │   └── src/
│   │       ├── app/          # App Router pages + API routes
│   │       ├── components/   # UI components
│   │       ├── hooks/        # SWR hooks (rooms, heartbeat, beacon)
│   │       └── lib/          # Auth, DB, Redis, Google API, sync
│   └── worker/               # Background job runner
│       └── src/jobs/         # presence-cleanup, reconciler
├── packages/
│   ├── types/                # Shared TypeScript interfaces
│   ├── ui/                   # Shared shadcn/ui components
│   └── config/               # Shared ESLint, Tailwind, TS configs
└── infra/
    ├── podman-compose.yml
    ├── podman-compose.dev.yml
    ├── caddy/Caddyfile
    ├── postgres/init.sql
    └── redis/redis.conf

License

MIT

About

Virtual Office Dashboard to Preview Multiple Google Meet

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors