跳到正文
DEV Community· Taskbead·· 3 小時前AI 評分47

Taskbead 如何以同一套程式碼支援網頁、PWA 和 Telegram mini app

One codebase, three front doors: shipping a task app to the web, a PWA and a Telegram mini app

AI 導讀

Taskbead 團隊以單一 HTML 檔案和純 JavaScript,讓同一款待辦事項應用程式支援網頁、PWA 和 Telegram mini app。應用程式採用離線優先設計,並共用日期解析器;Telegram 版以簽署的 initData 驗證用戶,亦可透過機械人把訊息轉成任務。團隊另設 MCP 伺服器,讓 AI 助手在權限限制及活動記錄等防護下操作任務清單。

正文

Disclosure: we're the team behind Taskbead, the app this post is about. It's a build story, not a sales pitch, and the plug is one line at the end.

We wanted a task list that's simply there, whichever screen you have in front of you: a laptop in the library, a phone on the bus, or Telegram, where a lot of students and freelancers already spend their day. Here's how we got one app to run in all three places without three codebases, and what we'd do the same way again.

1. The app is one HTML file

There's no front-end framework. The client is a set of plain JavaScript files, numbered so they load in order (0-parse.js, 1-core.js, 2-view.js, ...). A small build script concatenates them and inlines the CSS and JS into a single index.html.

Why bother?

  • One request to first paint. The shell is one HTML response, so a cold start on a slow mobile connection is quick.
  • Nothing to keep in sync. The same file is served at /app/ on the web, installed as a PWA, and opened inside Telegram.
  • Easy cache-busting. The build hashes the final HTML and stamps the hash into the service worker, so a new deploy means a new cache, every time.

The trade-off is discipline: without components, you need clear naming and small files. We'd still choose it for an app this size.

2. Offline first, sync second

A service worker caches the app shell, and IndexedDB keeps your tasks and their details on the device. You can add and tick off tasks without a connection, and changes sync when you're back. That matters more than we expected: a lot of task capture happens on the move.

3. The Telegram mini app is the same web app

A Telegram mini app is a web page Telegram opens inside the chat. Ours is the same single HTML file. The difference is sign-in: Telegram passes signed initData, and the server checks its HMAC (keyed from the bot token, as Telegram documents) before trusting the user. Web users sign in with email or Google instead, and they can link both in Settings so it's one account and one list.

The bot itself is the other half: forward any message to it and it becomes a task. That needed the next piece.

4. One parser for "essay due fri 3pm #uni"

The app's input box and the Telegram bot share one small parser module. The build copies it into the client bundle, and the worker imports the same file, so "fri 3pm" means the same thing everywhere.

The rules we settled on:

  • Day-first and timezone-aware. 5/11 is 5 November. Dates are computed on the user's wall clock using Intl.DateTimeFormat, so "tomorrow 9am" is 9 am where you are.
  • Conservative. If it isn't clearly a date, leave it alone. page 3/4 done stays a title.
  • Show before saving. The app previews the date and tag before you save, so a wrong guess is visible and easy to fix.

We wrote unit tests with a fixed "now" so every case (next mon, in 3 days, 2pm-3pm, tonight) is checked against an exact timestamp.

5. The backend is one Cloudflare Worker

  • Workers serve the landing page, the app, the API and the bot webhook.
  • D1 (SQLite) holds the data.
  • R2 holds attachments in a private bucket. Files are only ever served through the worker, after it checks you're allowed to see them.
  • A cron trigger runs every few minutes for scheduled work like reminders and recaps.
  • A Durable Object gives each API key its own small rate limiter.

For a small team, "no servers to patch" is the real feature.

6. Letting AI agents in, safely

We added an MCP server at /mcp (Streamable HTTP) so assistants like Claude, ChatGPT or Cursor can work with your list. Sign-in is OAuth 2.1 with PKCE and dynamic client registration, so there's no key to copy. Other tools can use named API keys, read-only or full access.

The guardrails were the interesting part:

  • You choose whether an agent sees only the tasks you hand it or all of them.
  • Every change is written to the task's activity log as "you via Claude", with undo.
  • There is no delete tool, and agents can't share, invite or change settings.
  • Every tool is annotated with readOnlyHint / destructiveHint, so clients can ask before acting.

7. 20 languages from day one

UI strings live in one dictionary per language, and the build step compiles them. Translations were machine-drafted and reviewed, with rules like "never translate #tags, times or names" and "example inputs should be what a native speaker would type". The parser also knows the weekday and "today/tomorrow" words in the app's languages.

What we'd tell ourselves at the start

  • A single HTML file and plain JS are enough for a real app, if you keep the files small.
  • Share the parser. Two parsers in two places will drift.
  • Design the agent permissions first. Undo and an activity log make people comfortable letting an assistant touch their data.

If you want to see the result: Taskbead is free (no ads) at taskbead.com, and in Telegram as @TaskBeadBot. Questions about any of the above, ask in the comments.

來源:DEV Community · dev.to