尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A web-based Internal Quality Control (IQC) dashboard for clinical laboratory instruments. Import QC data from AU5800 and DxI analysers, compute summary statistics (Mean, SD, CV%, n), visualise trends with Levey-Jennings charts, and export audit-ready reports.
Admins see a Try beta switch in the header. Off is the standard app; on adds the features below. The choice is remembered per browser, and non-admin accounts never see the switch or the beta features. Exports (PDF/XLSX/CSV) are unchanged by the switch.
What's new panel — while beta is on, the front screen opens with a "New in the beta" panel listing each beta update and where to find it, plus step-by-step instructions for sigma metrics (where to enter TEa, the formula Sigma = (TEa % − |Bias %|) ÷ CV %, and how to read the result). It can be hidden (remembered per browser) and reopened from Account › What's new in the beta. Switching beta on after data is loaded shows the same list in a dialog.
Design changes in the beta:
The calculations live in public/beta-logic.js (no DOM, unit-tested directly by tests/beta-logic.test.js); the UI is public/beta.js. Both are static files, so the beta adds no Serverless Functions.
| Layer | Technology |
|---|---|
| Frontend | Vanilla JavaScript single-page app |
| Backend | Node.js serverless functions (Vercel) |
| Database | PostgreSQL (Neon serverless) |
| Auth | JWT (jose) + bcrypt password hashing |
| Charts | Chart.js 4.4 + chartjs-plugin-annotation |
| PDF Export | jsPDF + jspdf-autotable |
| Excel Export | xlsx-js-style |
| Hosting | Vercel |
iqc-summary-statistics/
├── public/
│ ├── index.html # Full SPA (HTML + CSS + JS)
│ ├── beta-logic.js # Beta QC calculations (Westgard, bias, sigma, lot comparison)
│ └── beta.js # Beta UI (admin "Try beta" toggle)
├── api/ # Every file here becomes a Serverless Function
│ ├── auth/
│ │ └── [action].js # All /api/auth/* routes (see lib/auth-routes/)
│ ├── admin/
│ │ ├── users.js # GET/PUT /api/admin/users
│ │ ├── reset-password.js # POST /api/admin/reset-password
│ │ └── activity.js # GET /api/admin/activity
│ ├── activity.js # POST /api/activity (client-side logging)
│ ├── csv-store.js # GET/POST /api/csv-store
│ ├── csv-store/
│ │ └── [id].js # GET/DELETE /api/csv-store/:id
│ ├── insights.js # POST /api/insights (AI summary, streamed)
│ ├── reports.js # GET/POST /api/reports
│ ├── reports/
│ │ └── [id].js # GET/DELETE/PATCH /api/reports/:id
│ └── setup.js # GET/POST /api/setup (init DB tables)
├── lib/ # Shared modules — NOT Serverless Functions
│ ├── auth.js # JWT verification middleware
│ ├── activity.js # Activity logging helper
│ └── auth-routes/ # Handlers dispatched by api/auth/[action].js
│ ├── login.js # POST /api/auth/login
│ ├── register.js # POST /api/auth/register
│ ├── logout.js # POST /api/auth/logout
│ ├── me.js # GET /api/auth/me
│ └── change-password.js # POST /api/auth/change-password
├── tests/
│ ├── frontend-logic.js # Extracted frontend functions for testing
│ ├── frontend.test.js # Frontend unit tests (parseCSV, computeStats, etc.)
│ └── api.test.js # API handler tests with mocked DB/auth
├── package.json
├── vercel.json # Vercel routing config
├── jest.config.js
└── babel.config.js
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/register | Register new user. First user auto-becomes admin. |
| POST | /api/auth/login | Authenticate and receive HttpOnly JWT cookie. |
| POST | /api/auth/logout | Clear auth cookie. |
| GET | /api/auth/me | Get current user info (requires auth). |
| Method | Endpoint | Permission | Description |
|---|---|---|---|
| GET | /api/reports | Any authenticated | List all saved reports. |
| POST | /api/reports | full_access | Save a new report. Supports compressed format (gzipped base64) or legacy uncompressed JSON. |
| GET | /api/reports/:id | Any authenticated | Fetch a specific report. Compressed data is sent to client for browser-side decompression. |
| PATCH | /api/reports/:id | full_access | Append data chunks to an existing report (legacy chunked upload support). |
| DELETE | /api/reports/:id | full_access | Delete a report (cascades to report_chunks). |
| Method | Endpoint | Permission | Description |
|---|---|---|---|
| GET | /api/admin/users | admin | List all users. |
| PUT | /api/admin/users | admin | Update user status (approved/denied/pending) or permission (view_only/full_access). |
| GET | /api/admin/activity | admin | Fetch activity log (supports limit and offset query params). |
| Method | Endpoint | Permission | Description |
|---|---|---|---|
| POST | /api/activity | Any authenticated | Log a client-side action (data_process, export_pdf, export_xlsx, export_csv, data_clear, point_remove, point_restore). |
| Method | Endpoint | Description |
|---|---|---|
| GET/POST | /api/setup | Initialise database tables (reports, users, activity_log, report_chunks). Adds compressed_data column if missing. Cleans up empty/broken reports. |
Semicolon-delimited with 13 columns:
Protocol;Instrument;Parameter;Level;Date;Value;Target;SD;Status;Message;Comment;User;SampleId
Example:
TestProto;AU5800 1 L;Glucose;1;01/03/2025 08:00;5.5;5.0;0.3;Accepted;OK;;user1;SAMPLE1
AU5800 1 L -> AU/DxI-1)| Role | Status | Permission | Capabilities |
|---|---|---|---|
| admin | approved | full_access | All features + user management panel |
| user | approved | full_access | Import, export, save/load/delete reports |
| user | approved | view_only | Import, export, view reports (no save/delete) |
| user | pending | - | Cannot access dashboard until approved by admin |
| user | denied | - | Access denied |
The first registered user automatically becomes admin with full_access.
| Variable | Description |
|---|---|
DATABASE_URL | Neon PostgreSQL connection string |
JWT_SECRET | Secret key for signing JWT tokens |
# Install dependencies
npm install
# Set environment variables
export DATABASE_URL="postgresql://..."
export JWT_SECRET="your-secret-key"
# Initialise database tables
# Visit /api/setup or POST to it after deploying
# Deploy to Vercel
vercel
npm test
Tests run in Europe/London time (set in tests/global-setup.js) so date handling is exercised across BST.
Reports use a compressed storage approach to handle large datasets within Vercel's 4.5MB body size limit:
CompressionStream API, then base64-encodedcompressed_data TEXT columnDecompressionStreamfilters.removedPoints and listed in the PDF exportA typical 25MB dataset compresses to ~2-3MB for storage. The serverless function pre-warming strategy eliminates cold start delays (~45s reduced to ~1.5s).
The app is configured for Vercel with:
public/index.html served as the SPA for all non-API routesapi/ directory auto-deployed as serverless functionsmaxDuration: 60 in vercel.json)vercel.jsonThe Hobby plan allows a maximum of 12 Serverless Functions per deployment.
Exceeding it fails the deploy with exceeded_serverless_functions_per_deployment
after the build reports success, so a green build log is not proof of a
successful deploy — check the deployment state.
Every .js file under api/ counts as one function, including files that are
only ever imported by others. Shared code therefore lives in lib/ (outside
api/), and the five /api/auth/* routes are served by the single dispatcher
api/auth/[action].js.
Current count: 11 of 12. Before adding a file under api/, check the count:
find api -name "*.js" -type f | wc -l
To add a route without spending a slot, add a handler in lib/ and dispatch to
it from an existing route.