Contact EN 中文

Tzu Chi Portal Migration

The Tzu Chi Foundation's main website, moved from Joomla to static Lit pages

At a glance

Problem
The Tzu Chi Foundation's main website ran on Joomla 3.10.
What I built
A static multi-page site.
Outcome
Live at www.tzuchi.org.tw; an editor's save goes live in about a minute, and 222 redirect rules keep old links working.
My role
Solo
Period
2026-01 → 2026-10

Abilities shown

Each links to the ability and its level on the Skills page.

The problem

The Tzu Chi Foundation’s main website ran on Joomla 3.10. The pages were crowded, the stack needed PHP and a database, and editors depended on the old CMS to change the homepage. The site serves donors, volunteers and press, and many visitors are older readers on phones. It had to move without breaking old links or published financial reports.

What I built

A static multi-page site. Shared UI (header, nav, footer, breadcrumbs, alerts) is a set of tc-* Lit Web Components. The legacy content pages were crawled, converted to static HTML and kept on the original Joomla CSS, so nothing had to be rewritten at once. Homepage content, bank account panels, charity reports and shared ads are edited in a schema-driven /dashboard backed by drust, my own BaaS. It is a transitional v1.5; a full redesign is planned as v2.0.

How it works

  1. An editor saves a change in the dashboard; drust stores it with an audit trail.
  2. A drust webhook triggers a GitLab pipeline, which runs the full build.
  3. The build bakes the homepage, report pages and slide galleries into plain HTML through anonymous read-only RPCs, so those pages need no data calls to render their main content.
  4. Header, nav and footer are rendered on the server with @lit-labs/ssr as Declarative Shadow DOM and hydrated in the browser.
  5. Wrangler deploys to Cloudflare Pages, about 1 minute after the save. A check every 30 minutes rebuilds if Joomla articles drift, and a full rebuild runs every 6 hours.

Decisions

  • Server-render the shared components. They used to render only in the browser, at zero height before the JS loaded, which caused layout shift on every page.
  • Strict baking. If drust cannot be reached, the build stops and the previous deploy stays live. An empty hero is worse than slightly old content.
  • Redirects at the edge, from one source. All rules are generated from data/redirects.json into _redirects. An earlier version put them in a Pages Function, which sent every static request through the Functions runtime.
  • Whitelist public fields. The partner logo wall reads a form database that also holds contact data; the build projects only 6 public fields, and a test locks that key set.

Outcome

The migrated site is live at www.tzuchi.org.tw. I built it solo from January to October 2026, with Claude Code and a spec → plan → implement → review loop. The 15 design specs in the repo record each larger change.