PXCharts 4.0 Ships a Self-Hosted Multidimensional Table with 25 Field Types, 8 Views, and a Hand-Rolled Formula Engine
25 Field Types × 8 Views: We Built a Mini Feishu-Style Multidimensional Table
Today, I'm happy to share our AI startup project with you again.
Over two years, we did something that sounds a little crazy: built a complete multidimensional table collaboration platform.
Tables, kanban boards, Gantt charts, calendars, dashboards, forms, documents, mind maps — all revolving around the same data. Modify in one place, sync everywhere.
Tech stack: Next.js 14 + React 18 + TypeScript 5 + PostgreSQL + WebSocket, ready to use out of the box.
Open-source repo: https://github.com/MrXujiang/pxcharts
Demo: https://pxcharts.turntip.cn
1. The Background Behind Pxcharts SaaS 4.0
The story starts with a real project management experience. Our team of a dozen or so people stored all requirements, schedules, and bugs in individual Excel sheets. The daily morning routine was: "Who messed up the sheet?" "Which one is the latest version?" "Can someone send me this file?"
Later, everyone gradually adopted commercial multidimensional table products. The experience was indeed good — but new problems emerged: data was stored on someone else's servers, private deployment was prohibitively expensive, and adding a custom field type was simply impossible. For many small and medium-sized businesses and indie developers, this is an unavoidable hurdle.
So we decided to build it ourselves: a multidimensional table platform with features comparable to mainstream commercial products, but fully capable of private deployment. It's not just a "webpage where you can edit cells," but a complete data collaboration system — with a field type system, multiple views, formulas, automation, real-time collaboration, and ideally, AI.
After a long period of tinkering, it finally took shape. We call it PxCharts.
2. What It Is: One Set of Data, Eight Ways to View It
Positioned in one sentence: PXCharts is an AI-native driven multidimensional table collaboration platform that allows the same data to switch freely between eight views — table, kanban, Gantt chart, calendar, gallery, form, hierarchy, and chart — and supports real-time collaboration, automation, and AI capabilities.
Below, a showcase of its various "forms":
1. Table View
2. Gallery View
3. Task Kanban
4. Form View
5. Gantt Chart
6. Calendar View
7. Visual Dashboard
3. Deep Dive into Feature Highlights
3.1 25 Field Types: From Text to AI, One Table Holds All Business
Fields are the "atoms" of a multidimensional table. We defined 25 field types in one go within lib/types.ts: text, multi-line text, number, single select, multi-select, checkbox, date, image, attachment, link, rich text, progress, and advanced types like relation, lookup, rollup, formula, AI field, person, rating, currency, phone, email, auto-number, button, barcode, and location.
Business value: Clicking a "button field" triggers an automation rule — for example, changing the status to "Completed" and simultaneously pushing a notification to a WeCom bot. A single cell becomes an entry point for a business action.
3.2 Eight Views: Same Data, Different Perspective, Another Tool
There is only one set of data, but eight ways to view it: Table, Kanban, Gantt Chart, Calendar, Gallery, Form, Hierarchy, and Chart. Project managers look at Gantt charts, operations staff use kanban boards, finance checks charts, and external data collection uses the form view to generate a fill-in page with one click — no one needs to maintain a second copy of the data.
Business value: The table view uses react-window virtual scrolling at its core. Even with tens of thousands of rows, only the few dozen visible on the screen are rendered, keeping scrolling smooth.
3.3 Formula Engine: 32 Built-in Functions, Seamless for Excel Users
We hand-wrote a complete formula parsing engine (lexical analysis → syntax parsing → evaluation), with 32 built-in functions: SUM, AVERAGE, IF, CONCATENATE, DATEDIF... Function names are fully aligned with Excel, so existing users don't need to learn a second syntax.
Business value: Formula recalculation uses row-by-row incremental computation — editing one cell only recalculates formulas in that row, not the entire table. After optimization, for a table with 20,000 rows, the formula calculation time for a single edit dropped from 86ms to 0.006ms.
3.4 Automation Engine: 3 Triggers × 7 Actions, The Table Does the Work Itself
"When a record is created/updated/button clicked, if conditions are met, execute an action" — we fully implemented this classic model. There are up to 7 actions: update field, internal notification, Webhook, AI generation, email, WeCom bot, DingTalk bot.
Business value: A specific line of logic was written in the engine to prevent infinite loops — "If the field value to be updated by the automation hasn't changed, skip it." Otherwise, the "update field" action would trigger the "record updated" event, igniting itself.
3.5 Real-time Collaboration: WebSocket Broadcast, Colleagues See Your Edited Cell in Seconds
Collaborative editing is the soul of the pxcharts multidimensional table platform. We implemented an independent collaboration service based on the ws library, sharing the same server.js process with Next.js, deployed from the same origin with zero extra operational overhead. Cell edits and whole row additions/deletions are broadcast as patch messages to all members in the same room, along with presence online status messages, so you can see "who is currently viewing this table."
Business value: Writing to the database is not a simple UPDATE, but an atomic write using "SELECT ... FOR UPDATE row lock + transaction" — if two people modify the same table simultaneously, neither will overwrite the other's changes.
3.6 AI Suite: AI Field, AI Table Creation, Natural Language Query
AI is not a superficial decoration, but grows within the field system: add an "AI field," write a prompt template (using {{field name}} to reference other columns), and the entire column of data can be intelligently generated in batch — for example, automatically producing a "Sentiment Analysis" column based on a "Customer Feedback" column.
Business value: There are also two hidden skills — generating an entire table with one sentence (AI table creation, automatically inferring field structure) and natural language query (input "Help me filter out uncompleted orders from last week," and the AI translates it into filter conditions and executes them directly).
3.7 32 Industry Templates: 9 Major Industries, Ready to Use
An empty table is the most discouraging starting point. We built in 32 project templates, covering 9 major industries: e-commerce, manufacturing, catering, retail, logistics, education, HR, internet, and general. E-commerce order management, production work orders, equipment inspection, student records, logistics waybills, recruitment management, financial reimbursement... Each template comes with its own field structure and sample data, ready to start working with a single click.
Business value: Templates are not "example screenshots"; they are complete, runnable projects — fields, views, and records are all real and editable.
4. Overall Architecture: One Process Handles Both REST and WebSocket
Architecturally, we made a very pragmatic choice: Next.js's REST API and the collaborative WebSocket service run in the same server.js process. The benefit is that deployment only requires one port and one process, easily started with PM2, so small teams don't need to touch additional message middleware; simultaneously, the client is naturally same-origin, eliminating the hassle of cross-origin issues and ws/wss protocol adaptation under HTTPS.
Key selections and reasons: Next.js 14 — integrated frontend and backend, all 116 API routes are route-file-as-endpoint; Zustand — for high-frequency partial updates like tables, a lightweight store is much more convenient than a full-featured framework; PostgreSQL + JSONB — field structures are flexible and variable, one SELECT fetches the entire table, zero JOINs for small to medium-scale tables; ws — a native, lightweight WebSocket library, collaboration broadcasting doesn't need a heavier framework.
5. The 6 Steps Behind a Single Cell Edit
Design-wise, we have a small refinement: "Local first, then broadcast, then persist" optimistic update. When the user presses Enter, the cell on their own screen changes immediately (step ②), without waiting for the network; meanwhile, the patch has already flown to the server to broadcast to colleagues (③④⑤), and the REST persistence (⑥) completes the atomic write in the background and triggers automation rules along the way. The experience is fast, and data is not lost.
6. Core Implementation Breakdown: Four Code Snippets to See the Craft
6.1 Collaboration Broadcast: Room Model, One Function Does It
lib/collab-server.ts (simplified)
// Broadcast message to other clients in the room (excluding sender)
function broadcastToRoom(roomId, message, excludeClientId) {
const clientIds = rooms.get(roomId)
if (!clientIds) return // Room doesn't exist, ignore
const messageStr = JSON.stringify(message)
clientIds.forEach((cid) => {
if (cid === excludeClientId) return // Skip the sender
const client = clients.get(cid)
if (client && client.ws.readyState === WebSocket.OPEN) {
client.ws.send(messageStr)
}
})
}
Plain English explanation: Each table is a "room," and whoever opens the table enters the room. When someone modifies data, the server sends the message to everyone else in the room one by one, specifically skipping the sender — because their screen was already updated in step ②. A proud detail: The message is JSON.stringify'd once and then sent in a loop, saving a dozen serializations for a room of a dozen people. In high-frequency collaboration scenarios, this is a tangible CPU saving.
6.2 Atomic Write: FOR UPDATE Row Lock, Concurrent Table Modifications Don't Clash
lib/db.ts (simplified)
export async function atomicMutateTableRecords(tableId, mutate) {
return transaction(async (client) => {
// FOR UPDATE row lock: concurrent writes to the same table must queue
const res = await client.query(
'SELECT data::text FROM tables WHERE id = $1 FOR UPDATE',
[tableId]
)
const records = JSON.parse(res.rows[0].data || '[]')
const { records: nextRecords, result } = mutate(records)
await client.query(
'UPDATE tables SET data = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2',
[JSON.stringify(nextRecords), tableId]
)
return result
})
}
Plain English explanation: The entire table's records are stored in a single JSONB field, making reads and writes very simple, but what about "two people writing at the same time"? The answer is a row lock: before modifying data, lock this row first, release it after modification, and latecomers automatically queue. A proud detail: The "read-modify-write" three steps are all wrapped in a single transaction. If any step fails midway, the whole thing rolls back, preventing half-modified dirty data. After a successful write, a backup snapshot is also asynchronously saved, adding another layer of data reliability.
6.3 Formula Engine: 32 Functions Are Just a Dictionary
lib/formula-engine.ts (simplified)
const BUILTIN_FUNCTIONS = {
SUM: (...args) => args.reduce((s, v) => s + Number(v || 0), 0),
IF: (cond, trueValue, falseValue) => cond ? trueValue : falseValue,
DATEDIF: (start, end, unit = 'D') => { /* Date difference: D days/M months/Y years */ },
// …32 in total, naming aligned with Excel
}
// Dispatch by name during evaluation (case-insensitive)
const func = BUILTIN_FUNCTIONS[funcName.toUpperCase()]
Plain English explanation: Formulas are first broken down into lexical and syntax trees. When a function call is encountered, this "function dictionary" is looked up. Adding a new function is just adding a line to the dictionary, with almost zero expansion cost. A proud detail: All function names are uniformly converted to uppercase before lookup, so whether the user writes sum(...) or SUM(...), it works, maintaining consistency with Excel's tolerance.
6.4 Automation Engine: One Line of continue Prevents Infinite Loops
lib/automation-engine.ts (simplified)
for (const action of rule.actions) {
if (action.type === 'update_field' && action.fieldId) {
// Prevent self-triggering infinite loop: skip if target field's current value is already the same
if (event.recordData?.[action.fieldId] === action.value) continue
fieldUpdates[action.fieldId] = action.value
}
// send_notification / send_webhook / ai_generate /
// send_email / send_wecom / send_dingtalk ……
}
Plain English explanation: After a rule is matched, actions are executed one by one. The most dangerous is "update field" — it itself causes a record update, triggering the automation again. So before execution, a comparison is made: if the value hasn't changed, skip it directly. The spark of recursion is extinguished by this single line of continue. A proud detail: Hidden in the action list is also ai_generate — one action of the automation can be "let the large model write something and fill it into a field." Rules and AI are connected in this way.
7. Application Scenario Sharing
Below, based on our market research, let's share some application scenarios where pxcharts super table can be used:
🛒 E-commerce Teams: Order management table + Kanban view to monitor shipping status, automation pushes overdue unshipped orders to WeCom groups.
🏭 Manufacturing Factories: Production work orders + equipment inspection records, Gantt view for scheduling, automatic email notification for maintenance upon inspection anomalies.
🚚 Logistics Companies: Waybill tracking table, form view for drivers to report anomalies, hierarchy view to see region-route-waybill number.
🧑💼 HR Departments: Recruitment management pipeline, kanban drag-and-drop for candidate stages, AI field automatically summarizes resume highlights.
🏫 Educational Institutions: Student records + course scheduling calendar view, class hour consumption automatically calculated using formula fields.
💻 R&D Teams: Requirement pool + Bug tracking, chart view to see iteration burndown, natural language query "unfinished requirements under my name from last week."
📊 Data-Sensitive Enterprises: The entire system is privately deployed on their own servers, data never leaves the intranet — something commercial SaaS cannot provide.
8. Final Words
PXCharts is still iterating rapidly. The field system, views, and automation will continue to grow. If you also have similar needs and pain points, or want a multidimensional table where data is completely in your own hands, feel free to refer to our solution:
Open-source repo: https://github.com/MrXujiang/pxcharts
If you find it useful, give us a Star, that's the greatest encouragement!
Let data collaboration return to what it should be — simple, real-time, controllable.
See you next time!
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
1. What is a multidimensional table?