At Fastcomcorp, we do not build technology for the sake of novelty. We build it because real problems in production environments demand real solutions and because the tools that exist often fall short of what the work actually requires. Casin is the result of one of those moments. It began as a workforce scheduling engagement for a client. It ended with us rebuilding the synchronization layer from the ground up and open sourcing what we built, because we believe infrastructure this foundational belongs to the community.
github.com/fastcomcorp/casin-jmap-server
The Problem with CalDAV at Scale
CalDAV (RFC 4791) is a reasonable protocol for personal calendar management. One user, a handful of events, a predictable sync cadence. For that use case, it works. Workforce scheduling is a fundamentally different problem.
When a supervisor reassigns shifts across forty employees simultaneously, CalDAV requires individual PUT requests per calendar object, per account. There is no native batch operation. What should be a single logical transaction becomes dozens of sequential HTTP calls, with no atomic guarantee. Some employees see the updated schedule immediately. Others see the old one. The supervisor has no reliable way to know which is which.
That inconsistency compounds under real production conditions.
CalDAV’s sync model relies on ctag and sync-token values to tell clients what changed. Under concurrent edits from multiple supervisors touching overlapping employee schedules, those tokens drift. Clients miss updates. Clients receive stale data. Recovery requires a full resync which generates additional server load at exactly the moment load is already elevated.
The result is a feedback loop.
Clients poll more aggressively because data looks stale. Servers slow under the polling pressure. Clients time out and retry. During peak periods, shift bidding windows, end-of-week schedule publishing we observed complete CalDAV freezes. Employees could not see their schedules. Supervisors could not confirm that changes had landed. We patched. We tuned. We added caching. The model was the problem. CalDAV was not designed for what they were asking it to do.
Why JMAP
We evaluated alternatives and kept returning to JMAP RFC 8620, the JSON Meta Application Protocol originally designed by the Fastmail engineering team to replace IMAP for email synchronization. The protocol’s core insight is a stateful delta sync model. Rather than asking a server to return everything and letting the client sort out what changed, JMAP introduces a state token that represents the current version of a dataset. When a client reconnects after a network interruption, a background kill, or any other disruption it presents its last known state token and receives precisely what changed. Nothing more. That model solved every failure mode we had encountered with CalDAV.
| Problem | CalDAV | JMAP |
|---|---|---|
| Bulk operations | Multiple sequential round trips | Single batched methodCall array |
| Sync state integrity | ctag drift under concurrency | Server-issued state token, delta-only |
| Push updates | Client polling | Native server push via EventSource |
| Partial sync | Full object refetch | Delta sync — changed properties only |
A supervisor reassigning forty shifts becomes a single JMAP request containing forty method calls in a batched array. It succeeds as a unit or it does not. There is no intermediate state visible to clients during the operation.
In our benchmarks, JMAP’s delta sync model reduces payload size by up to 80 percent compared to the full-object responses CalDAV required. Across hundreds of employees each synchronizing their schedules, this represents a meaningful infrastructure cost difference at scale.
The Architecture We Built
Once we committed to JMAP as the synchronization layer, the remaining architecture followed from requirements — not preference.
We needed a component to parse and validate JMAP safely under adversarial conditions. We needed a component to hold persistent connections at high concurrency without degradation. We needed a database layer that could enforce scheduling constraints atomically. And we needed a message bus to connect the write path and the fan-out path without coupling them.
That gave us the Split-Brain Architecture: a deliberate separation between the scheduling computation layer and the real-time communication layer, connected by an internal message bus.

Each component has a single, clearly bounded responsibility. The choices were deliberate.
Rust: The Ironclad Gateway
The Rust layer is the sole entry point for external traffic. It handles JMAP request parsing and validation, JWT authentication, compile-time verified SQL queries via SQLx, and event publication to NATS JetStream.
Rust is here because this layer faces the public internet, parses untrusted JSON, and touches the database. Rust’s ownership model eliminates the class of memory safety vulnerabilities that remain among the most exploited weaknesses in critical infrastructure software. A parser bug in the Rust layer produces a logic error. It does not produce a memory corruption vulnerability.
The SQLx compile-time query checking extends this discipline to the database layer. Every query is verified against the live schema at compile time. A column rename that would break a query in production becomes a compiler error during development.
PostgreSQL: The Source of Truth
The foundational scheduling constraint — no employee can be double-booked — is enforced at the database level using PostgreSQL GiST Exclusion Constraints with Range Types.
[sql]
CREATE TABLE shifts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
employee_id UUID NOT NULL REFERENCES employees(id),
duration TSTZRANGE NOT NULL,
EXCLUDE USING GIST (employee_id WITH =, duration WITH &&)
);
[/sql]
The && operator tests for range overlap. The EXCLUDE USING GIST clause instructs PostgreSQL to reject any insert or update that would create an overlapping shift for the same employee — atomically, at the transaction level, regardless of concurrent requests in flight. This is not algorithmic cleverness in application code. It is a physical database constraint. Application-layer conflict checking is vulnerable to race conditions under concurrency. This is not. The database refuses the conflicting write.
NATS JetStream: The Decoupling Layer
After the Rust layer commits a shift change to PostgreSQL, it publishes an event to NATS JetStream. This decouples the synchronous write path from the asynchronous fan-out path entirely. The Rust layer does not need to know or care that the Elixir layer exists.
NATS provides at-least-once delivery with acknowledgment events are not lost if the Elixir consumer is temporarily unavailable. Its operational footprint is significantly lower than Kafka for our message volume. The async-nats Rust client and the Gnat Elixir client are both first-party and actively maintained.
NATS is strictly internal. Port 4222 is never exposed beyond the private VPC subnet. The only publisher is the Rust layer. The only consumer is the Elixir layer.
Elixir: The Realtime Router
The Elixir layer consumes NATS events and fans them out to every affected party. WebSocket connections, WebPush notifications, and external calendar API sync jobs.
The BEAM virtual machine’s process model is the reason Elixir occupies this layer. Each WebSocket connection runs as a lightweight process with its own heap and garbage collector. Three hundred thousand simultaneous connections is not a tuning exercise in Elixir. It is the default operating condition of the runtime.
External calendar synchronization to Google Workspace, Microsoft 365, and Apple iCloud is handled through Oban, a robust job processing queue. A shift bidding event that modifies five thousand schedules simultaneously generates five thousand queued sync jobs, not five thousand simultaneous API calls. Oban respects each provider’s rate limits, retries with backoff on failure, and provides full queue observability. No sync job is lost under load.
ArcRTC: The Offline Problem CalDAV Never Addressed
Legacy scheduling software has no answer for field workers who lose cellular connectivity. The application goes stale. It stays stale until connectivity returns. For workers in hospital basements, rural logistics routes, or underground facilities, this is a real operational failure. We used ArcRTC a proprietary offline sync protocol we built to solve it. When devices lose cellular service, ArcRTC forms an encrypted peer-to-peer mesh network between devices on the same shift:
- Pre-loss signaling — While connected, the Elixir cluster pre-exchanges WebRTC ICE candidates between all workers assigned to the same shift. This happens proactively.
- Mesh formation — When cellular drops, devices discover each other via Wi-Fi Direct or Bluetooth and form an encrypted UDP mesh using DTLS.
- Peer sync — Shift changes, clock-ins, and task completions propagate through the mesh phone-to-phone, using a CRDT-inspired conflict resolution model.
- Reconciliation — When any device in the mesh regains connectivity, it relays the full accumulated mesh state back to the Casin server. PostgreSQL’s GiST constraint handles any write conflicts during reconciliation — atomically and cleanly.
Full protocol specification: docs/arc_rtc_protocol.md
Security
Workforce scheduling data is sensitive. Shift patterns, employee locations, and clock-in records represent operational intelligence that deserves serious protection.
Fuzz Testing — The Rust JSON parsing layer is fuzz tested against malformed payloads, deeply nested structures, and null-byte injections. This hardens the parser against the class of DoS attacks where crafted requests cause resource exhaustion or crashes.
Erlang Atom Exhaustion — Elixir atoms are not garbage collected. The NATS consumer parses all message keys as strings rather than atoms. A crafted message stream cannot exhaust the atom table and crash the virtual machine.
Encryption — TLS 1.3 on all public endpoints. DTLS for WebRTC across the ArcRTC mesh. Strictly rotated OAuth 2.0 tokens for external calendar APIs.
Network Isolation — PostgreSQL (5432), NATS (4222), and the Elixir libcluster port (45892) remain inside the private VPC subnet at all times. Only the Rust API (3000) and Elixir Phoenix (4000) accept external traffic.
Why We Open Sourced It
The scheduling engine, the JMAP layer, the GiST constraint model, the split-brain architecture, and ArcRTC is infrastructure. Infrastructure improves when it is public. Security researchers find vulnerabilities. Performance engineers find bottlenecks. Operators in unusual environments surface edge cases that a single client engagement never would. We chose AGPL v3. If you run a modified version of Casin as a hosted service, you must publish your modifications. The project cannot be taken private by a larger vendor without contributing back.
Commercial licenses are available for organizations that need to integrate Casin without AGPL obligations.
Contact us at [email protected]
An Open Invitation
Fastcomcorp is open to collaboration. The JMAP ecosystem needs more production-grade open source infrastructure. The workforce management space needs scheduling engines that take correctness, concurrency, and offline resilience seriously. Casin is our contribution to both. Whether you are an engineer evaluating it for your stack, an operator deploying it in production, or a developer who wants to contribute. We want to hear from you.
Ensure you have Rust, Elixir (Erlang/OTP 25+), PostgreSQL 15+, and NATS JetStream 2.9+ installed, then:
git clone https://github.com/fastcomcorp/casin-jmap-server.git
cd casin-jmap-server
./start.sh
The script boots the Rust and Elixir backends in the background and connects to your local PostgreSQL and NATS instances. The JMAP API will be available at http://localhost:3000. The WebSocket endpoint at ws://localhost:4000. Documentation starts at the Developer Handbook.
Questions and contributions belong in GitHub Discussions. Security issues follow the responsible disclosure process in SECURITY.md.
Fastcomcorp LLC delivers secure, high-performance infrastructure for enterprise communication and workforce management. Casin is the open-source foundation it runs on. GitHub: fastcomcorp/casin-jmap-server | Licensing: [email protected] | Contact: +1 (251) 645-2261





