27```
28โโโ backend/
29โ โโโ database/
30โ โ โโโ migrations.ts # Database schema
31โ โ โโโ queries.ts # Database operations
32โ โโโ routes/
33โ โ โโโ voicenotes.ts # Voice note CRUD operations
51
52- **Backend**: Hono (TypeScript API framework)
53- **Database**: SQLite for voice note metadata
54- **Storage**: Val Town Blob storage for audio files
55- **AI**: OpenAI Whisper for transcription
22 ]
23 );
24 console.log("Voice note successfully inserted into database");
25 } catch (error) {
26 console.error("Error inserting voice note into database:", error);
27 throw error;
28 }
63 };
64 } catch (error) {
65 console.error("Error getting voice note from database:", error);
66 throw error;
67 }
19 )`);
20
21 console.log('Database migrations completed successfully');
22 } catch (error) {
23 console.error('Database migration failed:', error);
24 throw error;
25 }
1import { Hono } from "https://esm.sh/hono@3.11.7";
2import { runMigrations } from "./database/migrations.ts";
3import voiceNotesRoutes from "./routes/voicenotes.ts";
4import staticRoutes from "./routes/static.ts";
11});
12
13// Run database migrations on startup
14try {
15 await runMigrations();
198```
199โโโ backend/
200โ โโโ database/
201โ โ โโโ migrations.ts # Schema definitions
202โ โ โโโ queries.ts # DB query functions
257 ```
258
259### Database Patterns
260- Run migrations on startup or comment out for performance
261- Change table names when modifying schemas rather than altering
12 status: "connected",
13 message: "Successfully connected to Notion API",
14 databases: response.results.map((db) => ({
15 title: db.title?.[0]?.plain_text || "Untitled",
16 id: db.id,
20
21// update the cache
22// this cron updates a blob that stores the JSON that shows the databases that val.town is connected to
23// we present that at root and embed that into Notion
24// to show everyone that the connection is healthy btw Notion and val.town
29 filter: {
30 property: "object",
31 value: "database",
32 },
33 });
12 status: "connected",
13 message: "Successfully connected to Notion API",
14 databases: response.results.map((db) => ({
15 title: db.title?.[0]?.plain_text || "Untitled",
16 id: db.id,
20
21// update the cache
22// this cron updates a blob that stores the JSON that shows the databases that val.town is connected to
23// we present that at root and embed that into Notion
24// to show everyone that the connection is healthy btw Notion and val.town
29 filter: {
30 property: "object",
31 value: "database",
32 },
33 });
12// that blob determines whether or not the cobrowsing button is ON or OFF
13export default async function (interval: Interval) {
14 // every page in the "Glancer demo" database should have it's own blob, so we have a cache for each demo
15 // this cron saves a blob for every page in the Demos DB
16 try {
17 // get notion pages with the databaseId
18 const pages = await notion.databases.query({
19 database_id: Deno.env.get("GLANCE_DEMOS_DB_ID"),
20 });
21 // for each page in the demo database, save a blob
22 for (const page of pages.results) {
23 const blobKey = await blobKeyForDemoCache(import.meta.url, page.id);
21## Further resources
22
23- [React Hono Example](https://www.val.town/x/stevekrouse/reactHonoExample) is a bigger example project, with a SQLite database table, queries, client-side CSS, a favicon, and shared code that runs on both client and server.
41export default async function server(request: Request) {
42 try {
43 // Database schema creation (only runs if tables don't exist)
44 await sqlite.execute(`
45 CREATE TABLE IF NOT EXISTS ${KEY}_employees (
1187 );
1188 }
1189 return new Response(JSON.stringify({ success: false, message: "Database error creating task." }), {
1190 status: 500,
1191 headers: { "Content-Type": "application/json" },
1280 } catch (error) {
1281 console.error("Error fetching single task:", error);
1282 return new Response(JSON.stringify({ success: false, message: "Database error fetching task." }), {
1283 status: 500,
1284 headers: { "Content-Type": "application/json" },
1500 );
1501 }
1502 return new Response(JSON.stringify({ success: false, message: "Database error updating task." }), {
1503 status: 500,
1504 headers: { "Content-Type": "application/json" },
1563 } catch (error) {
1564 console.error("Error deleting task:", error);
1565 return new Response(JSON.stringify({ success: false, message: "Database error deleting task." }), {
1566 status: 500,
1567 headers: { "Content-Type": "application/json" },