Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - Behnooddev/PWA-SyncRoot: Self-hostable collaborative workspace for managing projects, tasks, files and team activity. · GitHub
Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Behnooddev/PWA-SyncRoot: Self-hostable collaborative workspace for managing projects, tasks, files and team activity. · GitHub
Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Behnooddev/PWA-SyncRoot: Self-hostable collaborative workspace for managing projects, tasks, files and team activity. · GitHub
Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - Behnooddev/PWA-SyncRoot: Self-hostable collaborative workspace for managing projects, tasks, files and team activity. · GitHub
Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Behnooddev/PWA-SyncRoot: Self-hostable collaborative workspace for managing projects, tasks, files and team activity. · GitHub
Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - Behnooddev/PWA-SyncRoot: Self-hostable collaborative workspace for managing projects, tasks, files and team activity. · GitHub
Skip to content

Repository files navigation

SyncRoot

A Modern Collaborative Workspace — projects, tasks, todos, comments, files, and activity tracking for small teams.

Status: Phases 0–8 complete (Dashboard + Project Workspace + Task Board + Todo List). Comment/File/Activity feature logic lands in Phases 9–11 — see Roadmap below.


Tech Stack

LayerChoice
FrontendReact 19, TypeScript, Vite 6, Tailwind CSS v4, React Router 7, Framer Motion, TanStack Query, Axios
BackendNode.js, Express, TypeScript
DatabasePostgreSQL + Prisma ORM
Toolingnpm workspaces monorepo, ESLint 9 (flat config), Prettier, Vitest

Prerequisites

  • Node.js ≥ 20 (see .nvmrc)
  • Docker (for local Postgres) — or your own Postgres instance

Getting Started

# 1. Install dependencies for all workspaces
npm install
# 2. Start Postgres locally
docker compose up -d
# 3. Copy env files
cp apps/server/.env.example apps/server/.env
cp apps/client/.env.example apps/client/.env
# 4. Once Phase 2 lands (Prisma models), run:
npm run db:migrate
npm run db:seed
# 5. Run client + server together
npm run dev

Project Structure

syncroot/
├── apps/
│ ├── client/ # React app (Vite)
│ └── server/ # Express API
├── packages/
│ └── shared-types/ # Types shared between client & server
├── handoffs/ # One file per phase — read the highest-numbered one first
├── docker-compose.yml # Local Postgres
└── PHASE_0_PLANNING.md # Full architecture record

See PHASE_0_PLANNING.md for the complete architecture write-up (why layered Controller/Service/Repository, why the StorageProvider abstraction, database relation strategy, etc.) — this README covers how to run it, that document covers why it's built this way.

Architecture at a Glance

  • Layered backend:Controller → Service → Repository. Controllers only validate input (Zod) and shape HTTP responses. Services hold business rules. Repositories are the only layer touching Prisma directly.
  • Centralized error handling: every thrown error is an AppError subclass, caught by one middleware (middleware/errorHandler.ts) — no controller calls res.status().json() for an error case.
  • No authentication in V1: every request carries an X-User-Name header, resolved client-side from a name captured on first launch and stored in localStorage. This is an explicit, documented MVP trade-off, not an oversight — see PHASE_0_PLANNING.md §1.
  • No real-time sync in V1: by decision, not by omission. Data freshness comes from React Query's background refetch/polling, configured per feature. A WebSocket layer is a candidate for a post-V1 phase.
  • File storage: local disk in V1, behind a StorageProvider interface (lib/storage/) so a future move to S3/MinIO is a new implementation class, not a rewrite of every service that touches files.

Known Gaps (honest, not hidden)

  • PWA manifest currently ships one SVG icon. Browser-standard 192×192 / 512×512 PNG (and maskable variant) icons are Phase 14 work, per the original roadmap.
  • The Project Workspace page (/projects/:id) has a real header/tab shell (Phase 6), a real Task Board (Phase 7), and a real Todo list (Phase 8). Comments/Files/Activity tabs still show a labeled placeholder — Phases 9–11 replace each one with real, data-backed content.
  • Task Board's "move status" is a dropdown on each card, not drag-and-drop — a deliberate scope call for Phase 7 (no drag-and-drop library was in package.json at the time). Todo reordering (Phase 8) made the same call for consistency, using up/down buttons instead. See handoffs/PHASE_7_HANDOFF.md and handoffs/PHASE_8_HANDOFF.md for the reasoning; revisit if/when drag interactions matter enough to justify the dependency — the sandbox now has npm registry access (see below), so adding one is actually possible starting from Phase 9.
  • Task Board fetches up to 100 tasks per project in one page (no real pagination yet) — fine at V1 scale, would need revisiting for a project with a very large backlog. Todos made the identical call (100/page).
  • Todos are project-level only in the UI. The backend (schema, repository, service, API) already supports task-scoped todos end-to-end — taskId on create/list — but no UI surfaces it yet. See handoffs/PHASE_8_HANDOFF.md.
  • No auth, no real-time sync — both explicit V1 decisions, not gaps. See Architecture section above.
  • Sandbox network access, updated as of Phase 8: unlike Phases 1–7, this session has real network access to the npm registry — npm install, npm run build, lint, test, and format:check have now actually been run (and two real bugs from Phase 7 were caught and fixed as a result — see handoffs/PHASE_8_HANDOFF.md §1). binaries.prisma.sh is still blocked, so prisma generate/migrate dev still can't run and no live-database integration testing is possible — that part of the original limitation is unchanged. If a future session has network access too, don't skip re-running the root verification commands just because this note says they've been run before — always verify fresh.

Roadmap

PhaseScopeStatus
0Planning & architecture✅ Done
1Project initialization & tooling✅ Done
2Database schema, migrations, seed✅ Done
3Backend foundation (modules, middleware, Project module)✅ Done
4Frontend foundation (layout, routing, theme, reusable components)✅ Done
5Dashboard (project cards, search, stats, recent activity, CRUD)✅ Done
6Project Workspace (header, tab shell — tab content deferred, see Known Gaps)✅ Done
7Task System (board, priority, due date, status)✅ Done
8Todo System (project-level checklist, completion tracking, reordering)✅ Done
9–13Comment System, File Manager, Activity System, Search, Settings⏳ Next
14PWA (offline, install prompt, full icon set)Not started
15Optimization, security review, deployment prepNot started

Scripts (root)

CommandDoes
npm run devRuns client + server concurrently
npm run buildBuilds shared-types → server → client, in order
npm run lintLints every workspace
npm run formatFormats the whole repo with Prettier
npm run testRuns tests in every workspace
npm run db:migrate / db:seed / db:studioPrisma commands, proxied to apps/server

About

Self-hostable collaborative workspace for managing projects, tasks, files and team activity.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages