ToolUp.Scheduling.Core
0.34.1
Prefix Reserved
dotnet add package ToolUp.Scheduling.Core --version 0.34.1
NuGet\Install-Package ToolUp.Scheduling.Core -Version 0.34.1
<PackageReference Include="ToolUp.Scheduling.Core" Version="0.34.1" />
<PackageVersion Include="ToolUp.Scheduling.Core" Version="0.34.1" />
<PackageReference Include="ToolUp.Scheduling.Core" />
paket add ToolUp.Scheduling.Core --version 0.34.1
#r "nuget: ToolUp.Scheduling.Core, 0.34.1"
#:package ToolUp.Scheduling.Core@0.34.1
#addin nuget:?package=ToolUp.Scheduling.Core&version=0.34.1
#tool nuget:?package=ToolUp.Scheduling.Core&version=0.34.1
ToolUp.Scheduling
Domain-neutral booking-and-availability subsystem for ToolUp.Platform. Companion package — apps that don't import ToolUp.Scheduling.Server.props / ToolUp.Scheduling.Client.props pay zero runtime cost.
What this is
A small, opinionated booking primitive: bookable resources with default availability and availability exceptions, bookings that can recur via RFC 5545 RRULE, and conflict detection that surfaces every reason at once. Plus an iCalendar (.ics) parser + emitter for export / import.
Shipped surface (commit-stable across Phase 20):
| Concern | File | Module |
|---|---|---|
| Domain types | Shared/SchedulingTypes.fs |
BookableResource, Booking, AvailabilityException, RecurrenceRule, BookingConflict, BookingError |
| Recurrence expansion | Shared/RecurrenceExpander.fs |
expand, occurrenceStarts — pure, Fable-safe |
| Wire contract | Shared/SchedulingApi.fs |
ISchedulingApi (ToolUp.Remoting) |
| iCalendar I/O | Shared/iCalendar.fs |
parse, emit, VCalendar, VEvent |
| Audit payloads | Shared/SchedulingEvents.fs |
BookingCreatedPayload etc., SourceModule = "_scheduling" |
| Server interface | Server/IBookingScheduler.fs |
IBookingScheduler — six-rule portable |
| Pure conflict detection | Server/BookingConflictDetector.fs |
detect, DetectorInputs |
| Default impl | Server/BookingScheduler.fs |
BookingScheduler over IEntityStore + IEventStore |
| API handler | Server/SchedulingApiHandler.fs |
schedulingApi ToolUp.Remoting handler |
| Compose pipeline | Server/SchedulingCompose.fs |
SchedulingServerApp record + run |
Why a companion, not core SDK
Booking is a domain capability, not platform substrate. Nothing else in the SDK depends on IBookingScheduler. Analytics-only deployments never need scheduling — charging them the binary weight is wrong-by-default. This is the same rationale for ToolUp.AI / ToolUp.RAG / ToolUp.KnowledgeBase not living in ToolUp.Platform.
The companion is a consumer of substrate (IEntityStore Phase 19, IEventStore Phase 6, optionally IJobScheduler Phase 9b for reminders), not substrate itself.
How to enable
In your server .fsproj:
<Import Project="..\ToolUp.Scheduling\ToolUp.Scheduling.Server.props" />
In your client .fsproj (only if you'll use the planned Feliz components):
<Import Project="..\ToolUp.Scheduling\ToolUp.Scheduling.Client.props" />
In your server's composition root:
open ToolUp.Scheduling.SchedulingCompose
let config = {
ServerConfig.defaults with
Port = 5000
Surfaces = Surfaces.team
EntityStore = EnabledEntityStore // REQUIRED — scheduling rides on Phase 19
}
[<EntryPoint>]
let main _ =
SchedulingServerApp.create ()
|> SchedulingServerApp.withConfig config
|> SchedulingServerApp.withAuth (StaticJwtAuthProvider(...))
|> SchedulingServerApp.withStorage (LocalFileStorage("data"))
|> SchedulingServerApp.addModules myModules
|> SchedulingServerApp.run
SchedulingServerApp.run:
- Registers three entity types with
IEntityStoreviaServerApp.withEntity:BookableResource(index onResourceType)Booking(indexes onResourceId,Status, compound(ResourceId, StartUtc))AvailabilityException(index onResourceId)
- Registers
IBookingSchedulerin DI as a singleton (default impl:BookingScheduler). - Mounts the
ISchedulingApiToolUp.Remoting handler. - Delegates the rest to
ServerApp.run.
Apps without ServerConfig.EntityStore = EnabledEntityStore get a runtime null reference at first dispatch — explicit enforcement is a follow-up.
How to register a resource type
BookableResource.ResourceType is a free-form string ("Person", "Room", "Equipment", or your domain's term). The SDK never names a resource type — that's the deployment's choice. The same IBookingScheduler instance handles every resource type the deployment uses.
let alice : BookableResource = {
Id = "alice@team"
Type = "BookableResource"
Version = 1
ResourceType = "Person"
DisplayName = "Alice"
Timezone = "Europe/London"
DefaultAvailability = [
{
DayOfWeek = None // every day
StartTime = TimeOnly(9, 0)
EndTime = TimeOnly(17, 0)
EffectiveFrom = None
EffectiveTo = None
}
]
Metadata = Map.empty
}
scheduler.RegisterResource("team-acme", alice)
How to configure reminders
Reminder fusion is opt-in and currently a no-op flag (SchedulingServerApp.withReminders). When the feature lands, the consumer enables it via:
SchedulingServerApp.create ()
|> SchedulingServerApp.withReminders // future: lead-time + transport config
|> SchedulingServerApp.run
Until then, deployments that want booking reminders dispatch them themselves via IJobScheduler against _scheduling events — same plumbing the future fusion will use.
RRULE subset
RecurrenceExpander and the iCalendar layer cover:
FREQ=DAILY|WEEKLY|MONTHLY|YEARLYINTERVAL=NBYDAY=MO,TU,...,SU(Weekly only — token weekdays, no positional offsets)UNTIL=YYYYMMDDTHHMMSSZCOUNT=N
Plus a hard cap of 10,000 occurrences to defend against pathological rules. Caller detects the cap by comparing the returned list length to the hard cap.
Not supported: positional BYDAY (1MO, -1FR), BYMONTHDAY, BYSETPOS, sub-day frequencies. Deferred to Phase 20 follow-ups if customer demand emerges.
iCalendar coverage
Parser + emitter cover the VEVENT subset: UID / SUMMARY / DTSTART / DTEND / DTSTAMP / RRULE / DESCRIPTION. Datetime forms: UTC (YYYYMMDDTHHMMSSZ), floating + TZID (lifted to UTC via TimeZoneInfo.FindSystemTimeZoneById), date-only (midnight UTC). Line discipline: parser unfolds CRLF or LF + leading-whitespace; emitter folds at 75 octets. Round-trip-tested against synthetic Apple Calendar / Outlook / Google Calendar fixture excerpts (see Tests/InProcess/iCalendarTests.fs).
Not supported: VTODO / VJOURNAL / VFREEBUSY / VTIMEZONE definitions, X-properties (silently dropped on parse, never emitted), positional BYDAY / BYMONTHDAY / BYSETPOS, ATTENDEE / ORGANIZER. No paid dependencies (RFC 5545 is open; pure F# implementation, no Ical.Net).
See also
TECHNICAL_GUIDE.md— internals, six-rule portability audit verdict, conflict-detection algorithm, simplifications + deferrals.../ToolUp.Platform/Server/IEntityStore.fs— entity-store substrate.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- ToolUp.Platform.Core (>= 0.34.1)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on ToolUp.Scheduling.Core:
| Package | Downloads |
|---|---|
|
ToolUp.Scheduling.Server
ToolUp.Scheduling Server — booking scheduler with per-resource concurrency lock, conflict detector, scheduling API handler, SchedulingCompose. Depends on ToolUp.Platform.Server + ToolUp.Scheduling.Core. |
|
|
ToolUp.Calendar.CalDAV
Generic CalDAV ICalendarBridge for ToolUp.Scheduling — RFC 4791 PROPFIND / REPORT / PUT / DELETE over BCL HttpClient, credentials from ISecretStore. No vendor SDK, no OAuth registration. |
|
|
ToolUp.Calendar.Microsoft
Microsoft Graph ICalendarBridge for ToolUp.Scheduling — Outlook / Microsoft 365 calendars over the Graph REST surface with BCL HttpClient: delegated OAuth through the platform substrate, calendarView delta pulls, change-notification subscriptions with their own notification route. No Graph SDK. |
|
|
ToolUp.Calendar.Google
Google Calendar ICalendarBridge for ToolUp.Scheduling — the Calendar v3 REST surface over BCL HttpClient: push with deterministic event ids, incremental pull on sync tokens, watch-channel notifications with scheduled renewal and a polling fallback. OAuth through the platform's Authorization Code and token-refresh substrates. No Google client library. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.34.1 | 0 | 10/27/2026 |
| 0.34.0 | 37 | 10/26/2026 |
| 0.33.0 | 59 | 10/25/2026 |
| 0.32.0 | 59 | 10/24/2026 |
| 0.31.0 | 81 | 10/22/2026 |
| 0.30.0 | 106 | 10/20/2026 |
| 0.29.0 | 110 | 10/19/2026 |
| 0.28.0 | 120 | 10/19/2026 |
| 0.27.0 | 120 | 10/16/2026 |
| 0.26.0 | 119 | 10/12/2026 |
| 0.25.1 | 119 | 10/9/2026 |
| 0.24.1 | 130 | 10/6/2026 |
| 0.23.0 | 128 | 9/23/2026 |
| 0.22.0 | 119 | 8/27/2026 |
| 0.21.0 | 127 | 8/26/2026 |
| 0.20.1 | 139 | 8/20/2026 |
| 0.20.0 | 120 | 8/19/2026 |