Syncall addresses a real-time collaboration problem: when logs or output files are generated automatically by programs, especially third-party programs, collecting and distributing them manually is slow and inconvenient.
Multiple clients can connect to the same room and mark a folder as "shared." Any creation, modification, or removal of a file will be synchronized across all connected clients.
This is a term project of WashU CSE5306.
There are several existing approaches to similar problems.
- (vs. cloud file systems) They are not always easy to integrate into automated workflows, and authorization may become complicated in multi-user scenarios.
- (vs. Git) Git focuses on version control rather than low-friction real-time synchronization, so it is useful to reference but is not the primary model for this project.
- (vs. SFTP) SFTP is useful for file transfer, but it usually requires more manual configuration and is less convenient for lightweight room-based collaboration.
In general, the purpose of Syncall is close to SFTP, but extended for easier collaboration. Its main features are:
- It assumes that users in the same room are trusted participants, which keeps file sharing simple.
- It provides lightweight version control to help users recover from mistakes.
- It focuses on transfer speed and storage efficiency to better support real-time usage.
The existing projects with similar goals are: Syncthing, Resilio Sync, SparkleShare.
- Client: Electron + Vue.js for the desktop sync client
- Website: Vue.js for the landing page and signed-in status page
- Server: Node.js + Fastify + Socket.IO for authentication, room management, event broadcasting, and sync coordination
- Database: PostgreSQL for users, rooms, file metadata, and version records
- File storage: shared version blobs stored on the server filesystem in gzip-compressed form
TA checkpoint
- (5 pt) Check on 04/08/2026
Languages/Frameworks used
- (10 pt) Electron
- (5 pt) Vue.js
- (10 pt) Node.js + Fastify + Socket.IO
- (5 pt) PostgreSQL
Functionality
- (10 pt) Users can register, log in, and create or join a room
- (10 pt) File creation, modification, and deletion are synchronized correctly across connected clients
- (10 pt) Version control allows users to review and roll back file history
- (10 pt) The system handles invalid requests and basic security risks safely and robustly
- (10 pt) The project website and admin dashboard are clear, usable, and visually polished
Best Practices
- (3 pt) Code is readable and well formatted
- (2 pt) All website pages pass the HTML validator
Creative Portion
- (10 pt) TBD
Approved by Edgar
- The current release edition is
1.0.2. - Edition digits mean:
major.minor.patchMajor = big features, Minor = small features, Patch = bug fixes. - After each script or code change, increase the appropriate edition number before release.
- Desktop profiles created by editions newer than
0.1.0store their edition number locally. - When a newer edition starts and the saved profile edition does not match, Syncall clears that profile's cached local session, bindings, version heads, room cache, and notification state before continuing.
- The server now enforces a minimum compatible client edition.
The current minimum compatible edition is
1.0.0. Clients at0.1.0or older are rejected at login/register and must be upgraded.
apps/server: Fastify + Socket.IO + Prisma backendapps/desktop: Electron + Vue desktop clientapps/web: Vue landing page and signed-in status pagepackages/shared: shared schemas and TypeScript contracts
- Accept user registration and login
- Manage rooms, members, and username-based invites
- Receive gzip-compressed file uploads from clients
- Store file version metadata in PostgreSQL
- Store compressed file blobs on the server filesystem
- Broadcast sync events to connected clients through Socket.IO
- Provide file history and restore APIs
apps/server/src/app.ts: Fastify app bootstrap and route registrationapps/server/src/routes: REST API routesapps/server/src/services: auth, room, and file/version logicapps/server/prisma/schema.prisma: database schema
- Node.js 24+
- PostgreSQL 16+ or Docker Desktop for local development
- Install dependencies:
npm install
- Start PostgreSQL with Docker if needed:
docker compose up -d
- Copy the server environment template and adjust it:
copy apps\server\.env.example apps\server\.env
- Generate Prisma client and run the initial migration:
npm run prisma:generate npm run prisma:migrate
- Start the backend:
npm run dev:server
- Reset server-side sync state while keeping users, rooms, memberships, and invites:
npm run reset:sync-data --workspace @syncall/server
- This deletes file metadata, file versions, sync activity, client folder bindings, and all stored blobs under
STORAGE_DIR. - The reset command now verifies that
FileEntry,FileVersion,SyncEvent, andClientFolderBindingall end at zero rows after cleanup. - If the server code has been updated and Prisma reports that
clientModifiedAtis unknown, upgrade the existing database column and regenerate Prisma:npm run prisma:upgrade-client-modified-at --workspace @syncall/server npm run prisma:generate --workspace @syncall/server
- If you also want to remove locally cached bindings, version heads, and room status state for one Windows profile, run:
npm run reset:profile --workspace @syncall/desktop -- --profile=alice
- Replace
alicewith the profile name you actually use. This is separate from the server reset and is sometimes needed when you want a truly fresh client state after testing.
- The production server target can stay
Node.js + Fastify + PostgreSQLon Ubuntu without any architecture change. - On Ubuntu, use
cpinstead ofcopywhen preparing the environment file:cp apps/server/.env.example apps/server/.env
- Set
HOST=0.0.0.0inapps/server/.envso the Fastify server listens on the network interface. - Make sure the server has a writable storage directory for compressed blobs, for example:
Then set
mkdir -p /var/lib/syncall/storage
STORAGE_DIR=/var/lib/syncall/storage. - Install PostgreSQL on the Ubuntu host or run it separately with Docker.
- For deployment, put Nginx or another reverse proxy in front of Fastify if you want HTTPS and easier firewall management.
- No code change is required just because the server runs on Ubuntu, but you should use Linux paths and deployment commands in production.
- Let users register, log in, create rooms, and accept invites
- Bind one local folder per room without starting sync immediately
- Show file status per room as
OFFLINE,REMOTE,SYNCED,MODIFIED_LOCAL,MODIFIED_REMOTE, orRUNNING - Start or pause room sync explicitly from the desktop UI
- Watch the local folder for file create/change/delete events only while room sync is running
- Gzip-compress changed files before upload
- Download remote-only files when a room starts syncing
- Keep pre-existing local files offline until the user syncs them individually or with
Sync All Offline - Show history and compression statistics, then trigger restore requests
apps/desktop/src/electron/main.cjs: Electron window and IPC entrypointapps/desktop/src/electron/services/api-client.cjs: desktop-to-server API callsapps/desktop/src/electron/services/sync-manager.cjs: folder watching and sync loopapps/desktop/src/renderer/App.vue: desktop UI
- Windows 10/11
- Node.js 24+ for development
- The desktop client now defaults to:
http://syncall.moeheart.cn - Start one desktop client in dev mode:
npm run dev:desktop
- Start only the shared Vite host for the desktop UI:
npm run dev:desktop:host
- Start an additional desktop client that reuses the existing host:
npm run dev:desktop:client -- --profile=alice
- Start two desktop clients on the same machine for local sync testing:
npm run dev:desktop:dual
- Binding a folder does not upload or download anything by itself.
- When the app restarts, joined rooms and folder bindings are restored, but every room comes back in
PAUSEDmode. Start Syncbegins active watching for that room and downloadsREMOTEfiles.- Pre-existing local-only files stay
OFFLINEuntil the user syncs them explicitly. - File activity, invites, and notices are now collapsed behind drawer buttons with notification bubbles so the main workspace does not grow without bound.
- Build a portable unpacked Windows executable:
npm run package:dir --workspace @syncall/desktop
- Build a Windows executable package:
npm run package:win --workspace @syncall/desktop
- The unpacked executable is available at:
apps/desktop/release/win-unpacked/@syncalldesktop.exe - Packaged client artifacts are written under:
apps/desktop/release/ - On Windows, closing the client window fully terminates that client process and stops syncing immediately.
- On some Windows machines, the NSIS installer step may fail because Electron Builder extracts a signing helper that needs symlink privileges. In that case, use the unpacked executable or the zipped portable build instead.
- The desktop client supports separate local profiles through a command-line flag:
--profile=<name> - Example:
npm run dev:desktop:client -- --profile=alice npm run dev:desktop:client -- --profile=bob
- Or launch both at once:
npm run dev:desktop:dual
- For packaged Windows builds, use explicit profiles when you want more than one local client:
@syncalldesktop.exe @syncalldesktop.exe --profile=alice @syncalldesktop.exe --profile=bob - Each profile uses its own local session and binding file, so you can log in as two different users on the same machine and bind two different folders.
- Starting the same profile twice is intentionally blocked.
- For a local sync test, create two folders such as:
C:\syncall-test\alice C:\syncall-test\bob - Then run two client windows with different profiles, sign in as different users, join the same room, and bind each client to a different folder.
- The
dev:desktopcommand reuses an already running desktop dev server on port5173, but multi-client testing is still expected to use explicit profiles.
- Show the project landing page
- Provide a lightweight signed-in status view for rooms, invites, and recent activity
- Start the website:
npm run dev:web
- Typecheck all workspaces:
npm run typecheck
- Run server tests:
npm run test --workspace @syncall/server