FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
lightweight
lightweightglimpse2-runbook-view-glimpse-save-login-react
Remix of lightweight/glimpse2-runbook-view-glimpse-save-login
Public
Like
glimpse2-runbook-view-glimpse-save-login-react
Home
Code
8
_townie
13
backend
7
frontend
5
shared
3
.vtignore
README.md
deno.json
H
main.tsx
Branches
2
Pull requests
Remixes
History
Environment variables
6
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
9/10/2025
Viewing readonly version of main branch: v8
View latest version
README.md

Glance Demos

A Val Town application for managing and viewing demos with authentication.

Features

  • Authentication: Google OAuth via LastLogin
  • Dashboard: User-friendly interface showing system status
  • Health Monitoring: Real-time system health checks
  • Modular Architecture: Clean separation of concerns

Authentication

This application uses LastLogin for authentication:

  • Login: Users sign in with their Google account
  • Protected Routes: All routes require authentication except public endpoints
  • Logout: Users can logout via /auth/logout (handled automatically by LastLogin)
  • Session Management: Automatic session validation and renewal

Public Routes

The following routes are accessible without authentication:

  • /api/health - System health status

Protected Routes

Routes are protected by different authentication mechanisms:

User Authentication (Google OAuth via LastLogin):

  • / - Main dashboard (shows user info and system status)
  • /api/* - API endpoints (except health)
  • /views/* - View routes including /views/glimpse/:id
  • /glimpse/* - Shortcut routes including /glimpse/:id (equivalent to /views/glimpse/:id)

Webhook Authentication (X-API-KEY header):

  • /tasks/* - Webhook endpoints for external integrations (POST requests only)
    • GET requests to /tasks/* are allowed without authentication for debug endpoints

Project Structure

├── backend/
│   ├── controllers/         # Business logic controllers
│   ├── routes/             # Route definitions and HTTP handling
│   │   ├── api/            # API endpoints
│   │   ├── glimpse/        # Glimpse routes (enhanced with React frontend)
│   │   ├── tasks/          # Task-related routes
│   │   ├── views/          # User-facing views
│   │   └── authCheck.ts    # Authentication middleware
│   └── services/           # External service integrations
├── frontend/               # React frontend assets
│   ├── glimpse.html        # HTML template for glimpse views
│   ├── glimpse.tsx         # React entry point
│   ├── components/         # React components
│   │   ├── GlimpseView.tsx # Main glimpse display component
│   │   ├── NotionBlock.tsx # Notion block renderer
│   │   └── NotionProperty.tsx # Property display component
│   └── README.md
├── shared/                 # Shared utilities and types
│   ├── types.ts           # TypeScript interfaces for Notion data
│   ├── utils.ts           # Shared utility functions
│   └── README.md
└── main.tsx               # Application entry point with static file serving

Architecture

The application follows a clean MVC architecture with proper separation of concerns:

Route Layer (HTTP Handling)

  • Handles HTTP request/response formatting
  • Extracts parameters from requests
  • Applies authentication middleware
  • Calls controller functions and formats responses
  • Manages HTTP status codes and error responses

Controller Layer (Business Logic)

  • Contains business logic and orchestrates service calls
  • Returns plain data objects (not HTTP responses)
  • Handles data validation and transformation
  • Filters sensitive data (e.g., button properties)
  • Provides consistent success/error response structure

Service Layer (External Integrations)

  • Handles external API calls (Notion, databases)
  • Manages data persistence
  • Returns structured results with success/error information

Response Format

All controller functions return a consistent structure:

{ success: boolean, data: any | null, error: string | null, details?: string // Additional error context }

Routes then format these into appropriate HTTP responses.

Glimpse Routes

The application provides multiple routes for accessing page data and user authentication:

Authentication Routes

  • GET /glimpse/login - User-specific login redirect

    • Requires user authentication (Google OAuth via LastLogin)
    • Looks up authenticated user's email in GLANCE_DEMOS_DB_ID database
    • If user found: Redirects to user's personal URL
    • If user not found: Creates new user record and redirects to /glimpse/thanks
    • Shows detailed error information for debugging database structure issues
  • GET /glimpse/thanks - New user welcome page

    • Shows confirmation that user account was created
    • Explains next steps (admin review, email with demo link)
    • Provides timeline expectations (1-2 business days)

Data Access Routes

  • GET /views/glimpse/:id - Get complete page data with blocks by Notion page ID (JSON only)
  • GET /glimpse/:id - Enhanced with React Frontend - Content negotiation based on Accept header:
    • Browser requests (Accept: text/html): Returns rich React frontend with interactive Notion content display
    • API requests (Accept: application/json): Returns raw JSON data (same as before)
    • Fallback: If HTML template fails to load, automatically serves JSON

React Frontend Features

The /glimpse/:id endpoint now includes a rich React frontend when accessed via browser:

Content Rendering

  • Rich Notion Blocks: Supports headings, paragraphs, lists, code blocks, callouts, images, videos, tables, and more
  • Property Display: Shows all page properties with type-specific formatting and icons
  • Responsive Design: Mobile-friendly layout using TailwindCSS
  • Server-Side Data Injection: Initial data injected to eliminate loading states

User Experience

  • Error Handling: Graceful error states with retry functionality
  • Loading States: Smooth loading indicators
  • Navigation: Easy return to dashboard
  • Debug Mode: Raw data view in development environments

Technical Implementation

  • Content Negotiation: Single endpoint serves both HTML and JSON
  • Static File Serving: Frontend assets served via /frontend/* route
  • React 18.2.0: Pinned version for consistency
  • TypeScript Support: Shared types for Notion data structures

Note: The glimpse endpoints now provide both programmatic access (JSON) and user-friendly viewing (React frontend) from the same URL, maintaining backward compatibility while adding rich content display capabilities.

Demo API Endpoints

API endpoints for accessing Notion page data with different levels of detail:

  • GET /api/demo/:id/properties - Returns page properties only
  • GET /api/demo/:id - Returns page properties + all blocks recursively

Architecture:

  • Routes: Handle HTTP concerns (parameter extraction, response formatting, status codes)
  • Controllers: Contain business logic (getDemoProperties, getDemoFull)
  • Services: Handle Notion API integration

Authentication Behavior:

  • Browser requests: Require user authentication (Google OAuth via LastLogin)
  • Internal requests: Bypass authentication when called from within the Val (identified by Deno user agent)

Response Format: Routes return the data directly from controllers on success:

{ // Notion page object with properties // For full endpoint: also includes "blocks" array with recursive block data }

On error, routes return:

{ "error": "Error message", "details": "Additional error context" }

Usage Examples:

// Internal call from within Val (no authentication needed) const response = await fetch('/api/demo/page-id/properties'); const data = await response.json(); // External browser request (requires authentication) // User must be logged in via Google OAuth

All glimpse routes:

  • Require user authentication
  • Return complete page data including properties and blocks recursively
  • Filter out button properties from Notion page data
  • Return standardized JSON responses (except authentication routes which redirect or show HTML)
  • Use the same controller functions as the API endpoints for consistency

New User Registration Flow

  1. Authentication: User must be authenticated via Google OAuth (handled by LastLogin)
  2. Database Lookup: System queries GLANCE_DEMOS_DB_ID database for user's email
  3. User Creation: If not found, creates new user record with email address
  4. Welcome Page: Redirects to /glimpse/thanks with next steps information
  5. Admin Process: Admin reviews new users and adds demo URLs manually
  6. User Return: User can return to /glimpse/login once URL is configured

Database Requirements for Login

The GLANCE_DEMOS_DB_ID database must contain:

  • Email property: Contains user's email address (exact match with authenticated email)
  • URL property: Contains user's redirect URL (optional for new users)

Supported URL property names: URL, Link, Redirect URL, Demo URL, url, link Supported URL property types: url, rich_text, title

Error Handling

The login endpoint provides detailed error information for debugging:

  • Missing environment variables
  • Database query failures
  • User creation failures (falls back to access denied page)
  • Invalid or missing URL properties
  • URL format validation errors

The dashboard displays both routes in a comparison table for easy testing.

Development

The application is built with:

  • Hono: Web framework for routing and middleware
  • LastLogin: Authentication service
  • TypeScript: Type-safe development
  • Val Town: Hosting platform

Webhook Authentication

The application supports webhook endpoints for external integrations (like Notion webhooks):

Configuration

Set the webhook secret in your environment:

NOTION_WEBHOOK_SECRET=your-secret-key-here

Webhook Endpoints

  • POST /tasks/notion-webhook - Main webhook endpoint for Notion integrations (requires X-API-KEY header)
  • POST /tasks/url - Updates Notion page URL property with glimpse URL (requires X-API-KEY header)
  • POST /tasks/assign - Assigns agents to tasks based on Person property matching (requires X-API-KEY header)
  • POST /tasks/test - Test endpoint for webhook authentication (requires X-API-KEY header)
  • GET /tasks/debug-webhook - Debug endpoint to check webhook configuration

Task Assignment Webhook (/tasks/assign)

The assignment webhook automatically assigns agents to tasks based on Person property matching:

Workflow:

  1. Receives webhook with page ID from Notion
  2. Retrieves page properties to extract Person and Viewing properties
  3. Checks if Viewing property is true - if not, skips assignment and logs result
  4. Queries GLANCE_AGENTS_DB_ID database for agents with matching Person property
  5. Clears existing "Glimpse demos" relations from each found agent (ensures clean one-to-one relationships)
  6. Updates the original page's "Glimpse agents" property with found agent relations

Requirements:

  • Page must have a Viewing property set to true (assignment only occurs for actively viewed pages)
  • Page must have a Person property with assigned person
  • Agents database must have pages with Person properties matching the assigned person
  • Original page must have a "Glimpse agents" relation property
  • Agent pages must have a "Glimpse demos" relation property

Viewing Property Support:

  • Checkbox: true value
  • Select: "true" option name
  • Rich Text: "true" or "yes" text content (case-insensitive)

Response Format (Assignment Completed):

{ "success": true, "message": "Task assignment completed successfully", "pageId": "page-id", "personId": "person-id", "agentsAssigned": 2, "agentsClearedCount": 2, "timestamp": "2025-09-10T16:51:24.733Z" }

Response Format (Assignment Skipped):

{ "success": true, "message": "Page is not being viewed - assignment skipped", "pageId": "page-id", "viewing": false, "timestamp": "2025-09-10T16:51:24.733Z" }

Relation Management:

  • Ensures agents are only connected to the current demo (clears previous demo relations)
  • Maintains bidirectional relation consistency between demos and agents
  • Non-blocking clearing operations (continues assignment even if some clearing operations fail)
  • Only processes assignments for actively viewed pages (Viewing = true)

Authentication

Webhook endpoints require the X-API-KEY header:

curl -X POST https://your-val.web.val.run/tasks/test \ -H "X-API-KEY: your-secret-key-here"

Testing

Use the webhook testing form in the dashboard:

  1. Navigate to your dashboard at /
  2. Find the "Webhook Endpoint" section
  3. Enter your NOTION_WEBHOOK_SECRET value
  4. Click "Test Webhook" to verify authentication

Environment Variables

Configure these environment variables for full functionality:

  • GLANCE_DEMOS_DB_ID - Notion database ID for demos
  • GLANCE_CONTENT_DB_ID - Notion database ID for content
  • GLANCE_INTERACTIONS_DB_ID - Notion database ID for interactions
  • GLANCE_AGENTS_DB_ID - Notion database ID for agents
  • NOTION_API_KEY - Notion API key for database access
  • NOTION_WEBHOOK_SECRET - Secret key for webhook authentication

Real-time Viewing Analytics

The application includes real-time viewing analytics with immediate Notion synchronization and email-based authorization:

Authorization & Security

  • Email-based Access Control: Viewing analytics are only tracked when the authenticated user's email matches the page's Email property
  • Frontend Authorization: Email comparison happens on the frontend before any API calls are made
  • Zero Unauthorized Calls: Users without matching emails generate no viewing API requests
  • Automatic Detection: System automatically extracts emails from Notion page properties and user authentication

Blob Storage + Notion Sync

  • Fast blob updates: Page viewing status stored in Val Town blob storage for instant response (~100ms)
  • Immediate Notion sync: When users start viewing pages, Notion database is updated immediately
  • Automatic cleanup: Cron job runs every minute to mark stale sessions (>1 minute old) as not viewing

Viewing Data Flow

  1. Authorization Check: Frontend compares user email with page Email property
  2. Authorized Users: Frontend calls /api/viewing → Blob updated → Notion synced immediately
  3. User continues viewing: Frontend updates blob every 4 seconds (no Notion calls)
  4. User leaves/session stale: Cron detects stale session → Blob updated → Notion synced immediately
  5. Unauthorized Users: No API calls made, no viewing analytics tracked

Email Property Requirements

Pages must include an Email property in Notion for viewing analytics to work:

  • Property Name: "Email" or "email"
  • Property Type: Email type or Rich Text type
  • Content: Must exactly match the authenticated user's email address

Notion Database Schema

Pages in your Notion databases should include these properties for viewing analytics:

  • Email (Email or Rich Text) - Required for authorization
  • Viewing (Checkbox) - Real-time viewing status
  • Last Viewed (Date) - Timestamp of last viewing activity
  • Current Viewer (Rich Text) - Email of current viewer
  • Tab Visible (Checkbox) - Whether page tab is currently visible

Frontend Integration

  • Email Authorization: Compares authenticated user email with page Email property before tracking
  • Page Visibility API: Tracks when users switch tabs or minimize windows
  • Periodic updates: Calls viewing API every 4 seconds while page is active (authorized users only)
  • Session management: Automatic cleanup handles crashed browsers and network issues
  • Performance: Non-blocking API calls don't impact user experience, zero calls for unauthorized users
Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.