Command: cat projects/project-office.md
A product and project management office, with concurrent editing and no lost work
An internal system to manage product, projects and people: Scrum and Kanban with sprints, a prioritized backlog, burndown and velocity, workload per person, a dossier for each project, a mind map and an executive view. Several people edit the same project at the same time without anyone wiping out someone else's work, and each project only reaches those allowed to see it, checked on the server on every request.
open the demoa simulation of the system with fictional data · 6 screens
- Role
- Sole engineer, from product to operations
- Period
- Jul 2026 – Sep 2026
- What I did
Me: Product, architecture, an edge backend without Node, data model, syncing and merging edits, login security, every screen and the tests.
Private project, described without identifying the client, product or company.
Diagram
In the browser, the React SPA saves each project with the version it knows and, periodically, polls only the current version. The Worker, built on Web APIs only and with no Node, checks the project access list on every request and guards the login with PBKDF2 and a bot check that fails closed; it writes to D1 with prepared statements and keeps files in KV, out of the database. If someone saved first, the Worker answers with a conflict, and the browser runs a three-way merge and resends after a random wait.
Context
The group needed one place to manage product, projects and people: sprints, backlog, deadlines, each person’s workload and the reasons behind decisions, with several people working on the same board at the same time.
What I built
- Execution. A Kanban board with drag and drop, plus moving by selection for keyboard users; sprints with a goal and dates; a MoSCoW backlog with Fibonacci points; and a dashboard with burndown, velocity, task distribution and upcoming deadlines.
- People & Performance. Load against capacity, cycle time, 14-day throughput and delay risk, computed from each person’s tasks.
- Knowledge. Each project’s dossier (vision, business model, OKRs, risks and decisions), a mind map on an infinite canvas with automatic layout, documents viewed inside the app and a directory of tools by department.
- Executive view. A roll-up by period, by project and by person, counting the same person across projects once, by e-mail.
- Collaboration without loss. Automatic saving with versions, an item-by-item merge on conflict, and the team’s changes showing up on screen on their own.
What I would do differently
I would ship the multi-editor load test together with the first version of the merge. The livelock only showed up when eight editors saved at the same time, and the random wait that came later could have been born together with the conflict handling.
Constraints
- Several people editing the same project at the same time, without losing work.
- Each person sees only the projects shared with them, and the server is what enforces it.
- A backend on the edge runtime, with no Node and no ORM.
- A single technical person to build and run it.
Decisions
Optimistic concurrency with a three-way merge
- Context
- Each project is saved as one document. With two people editing, whoever saved last would silently erase the other's change.
- Choice
- Every save carries the version the browser knows. If someone saved first, the server answers with a conflict, and the browser merges base, local and server versions item by item (task, sprint, map block) and sends it again after a random wait.
- Gains
- A conflict becomes a merge, not an overwrite.
- The random wait came from a livelock measured in a load test with eight editors.
- Costs
- The merge has to know every kind of item in the document; a new kind needs a new rule.
Syncing through a lightweight version check
- Context
- Persistent connections would add infrastructure for a small team with few people editing at the same time.
- Choice
- Every 4 seconds, with random jitter, the browser asks only for the project's version, and it pauses while the tab is hidden. The database indexes were built for that path.
- Gains
- Simple and cheap, with no open connection.
- Costs
- Someone else's change can take a few seconds to show up.
- Constant, if light, traffic while the tab is open.
Per-project permission on the server, on every request
- Context
- Hiding a project on screen does not stop a member from asking the API for it.
- Choice
- A user × project access list checked on every request; admins see everything, with safeguards so an admin cannot lock themselves out.
- Gains
- Anyone not on a project's list does not get the project from the server.
- Costs
- Every new route has to apply the check, which takes discipline and a test per route.
A login that fails closed
- Context
- Brute force and bots are the most obvious risk for a system on the internet, and a forgotten setting must not open the door.
- Choice
- PBKDF2 with 100,000 iterations, constant-time comparison and the same cost for unknown e-mails, an atomic lockout per account, a per-IP limit in its own table, and a bot check that blocks the login when its secret is not configured.
- Gains
- A missing setting blocks instead of silently letting people in.
- Costs
- A misconfigured deployment locks everyone out until it is fixed.
Stack and why
- React 18 and Vite
- A single-page app served by the Worker itself.
- Cloudflare Workers, D1 and KV
- A backend on the runtime's Web APIs, SQL with prepared statements and files kept out of the database.
- Recharts and React Flow
- Burndown, velocity and distribution; a mind map on an infinite canvas.
- WebCrypto and Turnstile
- PBKDF2 without dependencies and a bot check that fails closed.
- Vitest
- Worker routes, security, merging and state tested in CI.
Results
23 test files with about 220 cases, covering Worker routes, security, edit merging and state, running in CI.
audited private repositoryThe repository's tests and CI workflow(Audit of the private repository, Sep 2026)A single route table, with a test that fails if any handler is left out.
audited private repositoryThe Worker's code and tests(Audit of the private repository, Sep 2026)A fix round of 19 security and data integrity items, all closed with tests.
self-reportedThe project's fix log
Security angle
Attack surface
- Password login with a bot check.
- The API for projects, documents and users.
- Document upload and in-app viewing.
- Several people editing the same project.
Controls in place
- PBKDF2 with 100,000 iterations, constant-time comparison and the same cost for unknown e-mails.
- An atomic lockout per account and a per-IP attempt limit.
- A bot check and an origin check that fail closed.
- A per-project access list checked on every request.
- Uploads restricted to an allowlist, with no executables, and files served under a restrictive policy.
- Links accepted only over http and https.
What I would test today
- A member asking the API for a project that was not shared with them.
- Two editors saving the same item at the same instant.
- A mutation sent from another origin.
Evidence
- audited private repositoryAudited private repository(Audit of the private repository, Sep 2026)