More projects · 01 / 05Distributed systems · Java

WORTH — Real‑Time Kanban in Java

How do you let a team on different machines create projects, move tasks across a Kanban board, see who is online and chat in real time, without a single framework? With sockets, threads and the Java standard library, each protocol chosen for the job it does best.

WORTH, live. Click for another project.
open carddoneforbidden move
4communication mechanisms, one per job
8,192project chats in the multicast address pool
20,000PBKDF2 iterations for every password
19Java classes, 3,600+ lines
0frameworks
01 / The idea

Collaboration, built from the sockets up.

WORTH (WORkTogetHer) is a complete client-server system for teams: users register and log in, create projects, add members, put cards on a Kanban board and move them through their life cycle, see who is online and talk in a chat that belongs to each project.

The constraint was the interesting part: no frameworks. Every networking primitive comes from the Java standard library, and each kind of interaction gets the mechanism that suits it, from reliable request-response to server push and group messaging.

02 / Protocols

One mechanism per job.

TCPport 45678

Login, logout and every project and card operation. Each message is a JSON-serialized object preceded by a 4-byte length header, so the receiver allocates exactly the bytes it needs.

Java RMIregistry on port 56789

User registration, and server-to-client callbacks: whenever users log in or out or projects change, the server pushes the new state to every connected client.

UDP multicastport 13731

A group chat for each project, with automatic notices such as a card moving to done. Addresses come from a pool between 239.255.224.0 and 239.255.255.255.

NIO file channelsJSON on disk

Users, projects, members and cards are saved after every state-changing operation and restored when the server starts again.

03 / The server

Many clients, one consistent state.

The main thread restores the saved state, starts the RMI registry and blocks on accept(). Every connection goes to a cached thread pool, where a worker reads the client's requests, runs them against the shared core and sends back the response. Shared users and projects are guarded by synchronized blocks, so concurrent updates stay atomic and consistent.

  • Fault tolerance. An abrupt disconnection is detected through the stream's end of file: the user is logged out, the socket closed and the stale callback stub pruned.
  • Client threads. The client runs its command line and TCP traffic on the main thread, receives callbacks on an RMI thread, and starts one listener thread per project chat that stores messages until the user reads them.
  • Address pool. Each new project takes the smallest free multicast address from a sorted TreeSet, and gives it back when the project is deleted: 8,192 chats in total.
04 / Kanban rules

A board the server enforces.

Every card starts in todo and moves according to fixed rules. Any other move is rejected with MOVE_CARD_FORBIDDEN; every valid one is recorded in the card's history and announced in the project chat, as in the demo at the top.

FromAllowed destinations
todoinprogress
inprogresstoberevised, done
toberevisedinprogress, done
donenone: a project can be canceled only when all its cards are here
WorthCore.java · moveCard()
// source and destination must be different listsif (sourceList.equals(destList)) {    message.setResponse(Response.CARD_EXISTS);    return message;}// the Kanban rules, checked on every moveswitch (destList) {    case "todo" :        message.setResponse(Response.MOVE_CARD_FORBIDDEN);        return message;    case "inprogress" :        if (sourceList.equals("done")) {            message.setResponse(Response.MOVE_CARD_FORBIDDEN);            return message;        }        break;    case "toberevised" :        if (!sourceList.equals("inprogress")) {            message.setResponse(Response.MOVE_CARD_FORBIDDEN);            return message;        }        break;    case "done" :        if (sourceList.equals("todo")){            message.setResponse(Response.MOVE_CARD_FORBIDDEN);            return message;        }        break;    default :}synchronized (createdProjects) {    // the card must really be in the source list    int cardIndex = sList.indexOf(new Card(cardName, null));    if (cardIndex == -1) {        message.setResponse(Response.NONEXISTENT_CARD);        return message;    }    // move the card, update its history, persist the project    Card card = sList.remove(cardIndex);    card.updateHistory(destList);    dList.add(card);    int cardIndex2 = project.getCards().indexOf(card);    project.getCards().set(cardIndex2, card);    server.saveProject(project);}
From the server's core, with the comments translated into English. After the move, the server announces it in the project's multicast chat.
05 / Security

Passwords are never stored.

Credentials are hashed with PBKDF2-HMAC-SHA1, a 32-byte random salt and 20,000 iterations, and only the salted hash reaches the disk. It is the small detail that separates a student exercise from a system you could actually trust with a team's accounts.

32 bytesrandom salt for every password
20,000iterations of PBKDF2-HMAC-SHA1
0passwords stored in clear text

Sockets, threads and nothing else.

The full source, 19 classes with the server, the client and the protocol, is on GitHub with instructions to run a server and as many clients as you like.

Next project · 02 / 05IMDb Data Mining & Predictive Analytics