Skip to content

Rui-Cheng PMS Whitepaper ​

An internal project-management system for structural engineering cases

Version 1.0 · June 2026 · 繁體中文版


Executive Summary ​

Rui-Cheng PMS (瑞成工程專案管理系統) is an internal tool built for the structural engineers of 瑞成土木結構技師事務所 to manage 30+ concurrent engineering cases. It is not a public SaaS product and has no signup, no billing, and no public surface — every user is a member of the firm who logs in with a badge number.

The system is designed around three strategic axes that reflect how an engineering practice actually carries legal and professional liability:

  1. Audit-first design for engineer liability (行為留痕、責任可溯) — every create, update, and delete is funnelled through a single rcLog path that records time, badge, role, and a before/after diff. The log is permanent, immutable, and CSV-exportable, because a certifying engineer's liability can be litigated for up to 10 years.
  2. Client-calendar schedule warning lights (依業主工作日的時程燈號預警) — progress is measured against the client's working calendar (a government agency skips Lunar New Year, a developer works Saturdays, a semiconductor client runs 24/7), surfaced as four-level warning lights and pushed to an in-app notification bell.
  3. Badge login + 3-tier accountability boundary (工牌登入 + 三層權限的責任界線) — login is by badge number plus password, and a 10-flag permission matrix draws a hard line: clerical staff may proxy-operate, but only the certifying engineer may move a progress number.

This whitepaper documents the domain model, the accountability and audit design, and the Next.js architecture that implements them.


1. Problem ​

A structural-engineering practice runs dozens of cases at once, each with its own client, its own statutory deadline, and its own certifying engineer whose seal carries personal liability. Before Rui-Cheng PMS, that reality was tracked across spreadsheets, shared folders, and memory:

  • Progress was opaque. Whether a case was on track depended on who you asked, and "on track" was judged against a generic calendar, not the day the client actually works.
  • Accountability was ambiguous. When administrative staff updated a case on an engineer's behalf, there was no durable record of who changed what, or whether they were allowed to.
  • Evidence was fragile. An engineer's certification can be challenged years after a project closes. Reconstructing "what did we know, and when" from scattered files is unreliable.
  • Deadlines were reactive. A slipping case was usually noticed when the client called, not before.

The firm needed a single internal system where the progress number is owned by exactly one role, every change is provable, and a case that is falling behind raises its hand on its own.


2. Domain Model ​

The domain logic lives in components/rc/ and is the heart of the product.

2.1 Six case categories ​

Cases fall into six built-in categories (plus firm-defined custom categories), grouped by how their progress is computed:

CategoryNameProgress model
A1設計監造 (design supervision)Node-based, auto-summed
A2鑑定 (assessment)Node-based, auto-summed
A3巡查 (inspection)Node-based, auto-summed
B1建案 (building case)Self-filled progress
B2計算案 (calculation case)Self-filled progress
B3鑑定案 (assessment case)Flexible hybrid

The A-series are 公共工程 (public works): progress is a deterministic sum of completed nodes, not a number a human types. The B-series let the responsible engineer fill progress directly, with B3 supporting a hybrid of both styles.

2.2 Sub-cases (母子追加案) ​

A B2 calculation case may spawn sub-cases (母子追加案) — follow-on work attached to a parent. Sub-cases are tracked by status, not rolled into the parent's progress percentage, so adding follow-on work never distorts the headline completion figure of the original engagement.

2.3 Schedule warning lights (時程燈號預警) ​

Each case carries a target schedule. An hourly scan compares elapsed-progress against elapsed-time, computed against the client's working calendar:

  • a 政府機關 (government agency) client skips 春節 (Lunar New Year),
  • a 建商 (developer) client works Saturdays,
  • a 半導體 (semiconductor) client runs 24/7.

The result is a four-level warning light:

LightThresholdMeaning
綠 Green< 50Comfortable
黃 Yellow50–74Watch
橙 Orange75–89At risk
紅 Red≥ 90Critical

Warnings are delivered through an in-app notification bell only — there is no email path by design.

Deadlines can raise a light, never lower it (v1.3.0, E390). Two hard dates sit beside the schedule-consumption percentage: the reply due date of an incoming official document that has not been answered yet, and a case-level hard deadline (court date, statutory deadline, or a regulator-imposed deadline). Within 3 / 7 owner working days they lift the light to at least orange; once past they lift it to red. There is a single entry point for this, resolveAlertLevel (lib/rc-schedule-utils.ts), so the dashboard, to-do list, case list, case detail and the notification scan always agree. On-screen day counts ("overdue N days", "N days left") are calendar days; the lights themselves stay on owner working days.

2.4 Client database (業主資料庫) ​

A lightweight CRM stores client attributes, NDA flags, contact windows (including the history of contacts who have since resigned), and the set of cases bound to each client — so the warning calendar and the contact record always travel with the case.

2.5 Audit log (稽核日誌) ​

Every mutation passes through rcLog, recording time, badge, role, and the before/after state. The log is permanent, immutable, and exportable as CSV. Its purpose is concrete: to serve as evidence in civil litigation, where a certifying engineer's liability can persist for up to ten years under the statute of limitations.


3. Accountability and Permissions ​

3.1 Badge login (工牌登入) ​

There is no email login, no OAuth, and no 2FA. A user signs in with a badge number (format R00001) and a password. Auth is handled by Auth.js v5 with the Credentials provider and a JWT session strategy (stateless — no DB session table). RBAC guards re-read the user's role from the database on each gated action rather than trusting a stale token claim.

3.2 Three-tier RBAC ​

Three roles map to real positions in the firm:

RolePositionBoundary
admin管理員 (技師 / certifying engineer)Owns progress numbers
operator行政 (administrative)Clerical proxy-operations; cannot set progress %
staff一般 (general staff)Scoped task access

The core invariant: only the 技師 (admin) may set a progress percentage. An 行政 (operator) can perform clerical proxy-operations across many cases on an engineer's behalf, but the progress number — the figure that carries professional liability — is reserved to the engineer.

3.3 The 10-flag permission matrix ​

Authorization is expressed as a 10-flag matrix evaluated server-side. Every gated Server Action checks the caller's flags as its first line, so the accountability boundary is enforced at the mutation, not merely hidden in the UI.


4. Architecture ​

4.1 Next.js App Router (Next.js 16) ​

The system uses Next.js 16 App Router with:

  • React Server Components (RSC) as the default — "use client" only for browser APIs, event handlers, and state.
  • Server Actions ("use server") for every case mutation — guarded, audited, no separate REST layer for internal state.
  • Route Handlers (app/api/) for the few endpoints that need a non-browser caller. The schedule-light scan does not use one — it runs as an in-process node-cron schedule started from instrumentation.ts at server boot (hourly by default, overridable via NOTIFICATION_SCAN_CRON), with no exposed endpoint and no separate scheduler service.
  • Nested layouts for route groups: (auth)/, (dashboard)/.

4.2 Domain engine ​

The case categories, node-summing progress, sub-case status tracking, calendar-aware light computation, and the rcLog audit path all live under components/rc/. Keeping the domain engine in one place is what makes the accountability boundary auditable.

4.3 Authentication (Auth.js v5) ​

  • Badge-number + password via the Credentials provider.
  • JWT session strategy — sessions are stateless; there is no DB session table. This is a deliberate pairing with Credentials login.
  • Role guards re-read role from the database on each protected action.

4.4 Database (Drizzle + PostgreSQL) ​

  • Drizzle ORM — type-safe schema with zero runtime overhead.
  • PostgreSQL 15 — production-grade, managed on Zeabur.
  • Migrations via pnpm db:generate + pnpm db:migrate.
  • Core tables include users (with badge + role), cases, case nodes, sub-cases, clients, client calendars, schedule lights, external review rounds, site-visit schedules, and the immutable audit log (28 migrations, 0000–0027; ER diagrams in docs/architecture/db-schema-relationships.md).

4.5 UI ​

The interface is built with Tailwind CSS v4 and shadcn/ui on the Rui-Cheng brand blue (#2C5CB8). List and table views use the reusable data-table component; create/edit flows open in modals rather than redirecting, and the full UI ships in 繁體中文.


5. Out of Scope ​

Several capabilities common to commercial SaaS products were deliberately excluded because Rui-Cheng PMS is an internal tool with a single tenant — the firm itself:

  • No payments, subscriptions, or any payment-provider integration. There is nothing to bill.
  • No pluggable feature-install / component-distribution mechanism. The codebase is a single application, not a catalog of distributable parts.
  • No OAuth, no two-factor authentication, no LINE integration.
  • No email notifications. Schedule warnings live in the in-app bell only.
  • No file upload. Documents are referenced by NAS links rather than stored in the app.

These omissions are features: the smaller surface is easier to audit and matches how the firm actually works.


6. How It's Built ​

Rui-Cheng PMS was developed with Claude Code and an Athena agent team running an epic-driven, spec → implement → QA → ship pipeline, with TDD and a coverage gate on every change. This is how the system is built and maintained; it is not a feature of the product.

Quality gates on every change:

  • Typecheck: pnpm typecheck (zero errors enforced)
  • Lint: pnpm lint (eslint-config-next)
  • Unit tests: pnpm test (Vitest, ≥80% coverage gate)
  • E2E tests: pnpm test:e2e (Playwright, smoke gate)

7. Deployment ​

The application deploys to Zeabur as a single service, with migrations run at startup. This documentation site deploys separately to Cloudflare Pages.


8. Conclusion ​

Rui-Cheng PMS turns the way a structural-engineering practice actually carries liability into software: one role owns the progress number, every change is provable for a decade, and a case that slips against its client's real calendar raises its own hand. The deliberately small, single-tenant surface is what keeps it auditable.

Learn more: The 繁中 end-user manual (User Manual · Domain Concepts · Dashboard · Cases · Settings) is published separately on the user-docs site.

Released under the MIT License.