Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

OpenTodo website

The public website of OpenTodo, the open-source task manager you host yourself. Live at https://open-todo.app; the demo runs at https://demo.open-todo.app.

The site is built with Astro to static files and served by nginx. Everything it says about the app (version, docs, screenshots, colours, icons, changelog, import formats) comes from the app's site bundle of a pinned release, never from files copied by hand. How the site is built and what it must do is specified in openspec/ (see AGENTS.md).

Run locally

Needs Node 22.

npm ci
npm run dev        # fetches the pinned bundle into .bundle/, then http://localhost:4321
npm run build      # fetches the bundle, checks the content, builds dist/
npm run serve      # serves dist/ like nginx on http://127.0.0.1:4321

The site bundle

bundle.json pins where app facts come from. Exactly one of:

Pin Meaning
{ "version": "v0.5.0" } Today. The release asset opentodo-site-bundle-v0.5.0.tar.gz from the app's GitHub releases, checked against the release's SHA256SUMS.
{ "preview": "<run id>" } The bundle artefact of an app CI run on main (needs GITHUB_TOKEN). Every page shows a "Preview" banner, and production builds refuse it.

BUNDLE_DIR=/path/to/bundle npm run build uses a local bundle folder instead; that is always a preview.

Updating the site to a new release is a one-line change to bundle.json: pin the new tag, rebuild, and fix any content the new docs or manifest no longer back.

A bundle holds the docs site (generated by the app's make docs), the screenshots, tokens/tokens.css and the icon sprite (icons/icons.svg, with names.json and the Lucide licence), a changelog.json parsed from the app's CHANGELOG.md, and a manifest.json with the version, release date, import formats and the facts the pages may show. Its README.md describes the layout.

Checks

Command What it fails on
npm run build Also writes sitemap-index.xml and one social preview card per page (dist/og/, from scripts/og.mjs, with the Inter files in scripts/og/fonts/). Fails on: a page that does not render; content front matter that breaks its schema (a comparison without checkedOn or older than 180 days, an OpenTodo claim without a docs link, a guide or template not reviewed in a year); a paragraph that claims a feature without a docs link (scripts/check-content.mjs).
npm run check TypeScript and Astro errors.
npm test Unit tests of the bundle scripts, template generator, content rules and checks.
npm run check:dist Broken internal or docs links and anchors; emoji or symbols used as icons; scripts from origins other than the site and the self-hosted analytics.
npm run test:browser Serious or critical axe violations in light and dark at 360 and 1280 px; horizontal scroll; pages that do not read and navigate without JavaScript; broken islands. Visits one page of every template in src/pages/ and every home page; npm run test:browser:full visits every page (BROWSER_PAGES=all, or list with BROWSER_PAGES_FILE). Needs Playwright's Chromium (npx playwright install chromium).
npm run templates:check A template that does not import cleanly into a server of the pinned release (OPENTODO_URL); also captures each template's screenshots into src/assets/template-shots/.

GitHub Actions runs them on every pull request and on main (.github/workflows/). The browser checks visit every page on main, nightly (a red night opens a ci-nightly issue) and on a manual run; a pull request visits the template set, or, when it only changes Markdown and images under src/content/, the pages whose HTML differs from the last build of main. The Docker image builds on a pull request only when what goes into it changes (ci-fast-checks).

Content

Folder Pages
src/content/templates/ /templates/<slug>: a template tree, turned into a downloadable opentodo-export file at build time
src/content/guides/, toolkit/ Guides and setup toolkits
src/content/blog/<slug>/index.md /blog/<slug>/: news, releases, development and ownership posts (/essays/ redirects here)
bundle changelog.json /whats-new/<version> and /feed.xml

Content is drafted following content/VOICE.md, picked from content/BACKLOG.md, and arrives through a pull request with a preview; posts stay drafts until the maintainer publishes them.

Writing a blog post

  1. Create a folder src/content/blog/<slug>/ with an index.md. The folder name is the URL (/blog/<slug>/); page, category and feed.xml are reserved. Put the post's images in the same folder.

  2. Start it with front matter:

    ---
    title: "OpenTodo 0.3.0: bring your own AI"
    summary: One or two sentences for the cards, the feeds and search results (at most 300 characters).
    publishedAt: 2026-10-14        # the post is hidden until this date
    updatedAt: 2026-11-02          # optional, shown next to the publish date
    author: raffaele               # a key in src/content/authors.json
    category: releases             # news | releases | development | ownership
    release: 0.3.0                 # releases only, and required there: a version in the pinned bundle's changelog
    cover: ./cover.jpg             # optional; also the social preview image
    coverAlt: What the cover shows # required with a cover
    inDevelopment: false           # true for work that is not in a release yet
    shippedIn: 0.4.0               # optional, once an in-development post's work is released
    draft: true                    # drafts never render; remove it once the maintainer approves
    ---
  3. Write in Markdown following the "Blog posts" section of content/VOICE.md. Every claim about what OpenTodo does links to its docs page (/docs/...); a paragraph that only looks like a claim gets <!-- no-claim --> on the line above. Posts with inDevelopment: true skip the claim rule and show an "In development" notice instead, but their docs links must still resolve.

  4. Run node scripts/check-content.mjs (it also runs before every npm run build) and open a draft pull request. The post appears on the blog index, its category page, the home page, /feed.xml and /blog/feed.xml once it is published and the site is built.

Deploy on Coolify

  1. + New Resource → Public Repository, https://github.com/OpenTodoApp/OpenTodoWebsite, branch main.
  2. Build pack: Dockerfile. Base directory: /. Port: 80. No environment variables.
  3. Assign the domain open-todo.app and deploy.

The Dockerfile builds the site (fetching the pinned bundle) and copies dist/ into nginx:1.27-alpine. Any static host works too: publish dist/, serving index.html for directory URLs and 404.html for unknown paths.

Licence

Code: MIT (LICENSE). Written content and images: CC BY 4.0 (LICENSE-CONTENT.md). The documentation and screenshots in the bundle follow the app's AGPL-3.0 licence. Inter is under the SIL Open Font License (public/fonts/OFL-Inter.txt), the icons under the ISC licence (icons/LICENSE-lucide.txt in the bundle).

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages