Unlisted
Like
scaffold
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.
A Val Town application for receiving Notion webhooks, processing data, and integrating with external services.
├── backend/
│ ├── controllers/ # Business logic
│ ├── routes/ # HTTP handlers
│ │ ├── api/ # API endpoints
│ │ ├── tasks/ # Webhook handlers
│ │ ├── views/ # User-facing views
│ │ └── authCheck.ts # Auth middleware
│ └── services/ # External API integrations
├── frontend/ # React frontend
│ ├── components/ # React components
│ ├── index.html # HTML shell
│ └── index.tsx # React entry point
├── shared/ # Shared types and utilities
│ ├── types.ts # TypeScript interfaces
│ └── utils.ts # Shared utility functions
├── main.http.tsx # Application entry point (Hono)
├── CLAUDE.md # Development guidelines
├── AGENTS.md # Val Town platform guidelines
└── deno.json # Deno configuration
This application follows a strict 3-layer MVC architecture:
Request → Route → Controller → Service → External API
- Routes: Handle HTTP only (extract params, format responses)
- Controllers: Business logic and orchestration
- Services: External API calls (Notion, Firecrawler, etc.)
Never skip layers! See CLAUDE.md for detailed guidelines.
Required environment variables (set in Val Town):
NOTION_API_KEY- Notion integration token (required)WEBHOOK_SECRET- Shared secret for API and webhook authentication (required for production, optional for development)RECENT_PAGES_LOOKBACK_HOURS- Hours to look back for recent pages (optional, defaults to 24)- Additional service API keys as needed (e.g.,
FIRECRAWLER_API_KEY)
-
Set environment variables in Val Town settings
-
Add routes in
backend/routes/:- API endpoints →
api/ - Webhook handlers →
tasks/ - Views →
views/
- API endpoints →
-
Create controllers in
backend/controllers/:- Use
pageController.tsfor generic Notion page operations - Return standardized
{success, data, error, details?}format
- Use
-
Integrate services in
backend/services/:- Use
notionService.tsfor Notion API calls - Create new service files for other integrations
- Use
-
Mount routes in
main.http.tsx:import { apiRoutes } from './backend/routes/api/index.ts'; app.route('/api', apiRoutes);
SCAFFOLD.md- One-time setup guide for creating a new val from scratchCLAUDE.md- Ongoing development guidelines and architectural patternsAGENTS.md- Val Town platform patterns (triggers, redirects, standard library, React config)/backend/README.md- Complete backend architecture documentation/frontend/README.md- Frontend structure and React patterns/shared/README.md- Shared code guidelines
Quick Links:
- New to this val? Start with
SCAFFOLD.md - Developing features? Reference
CLAUDE.md - Val Town questions? Check
AGENTS.md
All controllers return:
{
success: boolean,
data: any | null,
error: string | null,
details?: string
}
- Work with
pageId, not task/project-specific IDs - Routes can be domain-specific (e.g.,
/api/tasks/:id) - But they should call generic page controllers
- Services: Return errors, don't throw
- Controllers: Add context to errors
- Routes: Map to HTTP status codes (400, 401, 500)
- Runtime: Deno on Val Town
- Framework: Hono
- Frontend: React 18.2.0 with Pico CSS (classless CSS framework)
- APIs: Notion API (@notionhq/client)
- Storage: Val Town blob storage (optional)
MIT