Vasili's Blog

erDiagram
    Bookings {
        BookingId booking_id PK
        EventId event_id FK
        string full_name
        string email
        datetime booking_date
        number duration "Minutes"
        enum status
    }

    Availability {
        AvailabilityId availability_id PK
        string name
        string time_zone
    }

    AvailabilitySlots {
        AvailabilitySlotId availability_slot_id PK
        AvailabilityId availability_id FK
        number weekday "0 for Monday, 6 for Sunday"
        number start_time
        number end_time
    }

    Overrides {
        OverrideId override_id PK
        AvailabilityId availability_id FK
        bool all_day
    }

    OverrideSlots {
        OverrideSlotId override_slot_id
        OverrideId override_id
        number weekday "0 for Monday, 6 for Sunday"
        number start_time
        number end_time
    }

    Events {
        EventId event_id PK
        AvailabilityId availability_id FK
        bool enabled "Is visible in UI"
        string title
        string description "Markdown"
        string slug "Public URL portion"
        number min_duration "Minutes"
        number max_duration "Minutes"
        number increment "Minutes"
        number daily_frequency_limit "Times"
        number weekly_frequency_limit "Times"
        number monthly_frequency_limit "Times"
        number yearly_frequency_limit "Times"
        number daily_duration_limit "Minutes"
        number weekly_duration_limit "Minutes"
        number monthly_duration_limit "Minutes"
        number yearly_duration_limit "Minutes"
        number days_into_future_limit
        number minimum_notice_limit
        enum minimum_notice_limit_unit "days/hours/minutes"
        number before_event_buffer "Minutes"
        number after_event_buffer "Minutes"
        number fixed_fee "Dollars"
        number rate "Dollars per minute"
    }

    IntakeQuestions {
        IntakeQuestionId intake_question_id PK
        EventId event_id FK
        number ordinal
        bool required
        enum kind
        string identifier
        string label
        string description "Markdown"
        string placeholder
        json default_value
        bool locked
    }

    IntakeQuestionOptions {
        IntakeQuestionOptionId intake_question_option_id PK
        IntakeQuestionId intake_question_id FK
        string identifier
        string label
    }

    IntakeQuestionAnswers {
        IntakeQuestionAnswerId intake_question_answer_id PK
        BookingId booking_id FK
        number ordinal
        enum kind
        string identifier
        string label
        string description
        json answer
    }

    Availability ||--|{ AvailabilitySlots : has
    Availability ||--o{ Overrides : has
    Events ||--|| Availability : "scheduled during"
    Bookings }o--|| Events : has
    Bookings ||--o{ IntakeQuestionAnswers : has
    Overrides ||--o{ OverrideSlots : has
    Events ||--|{ IntakeQuestions : has
    IntakeQuestions ||--o{ IntakeQuestionOptions : has

#bookingservice

I've integrated https://mermaid.js.org diagramming support into this blog...

Check it out:

graph LR;
    A--> B & C & D;
    B--> A & E;
    C--> A & E;
    D--> A & E;
    E--> B & C & D;

Should probably back-port it to the mainline repo.

#mermaidjs

After the cal.com fiasco I think I'll try to roll out something simple, without too many dependencies, that can just run quickly...

Some Notes on the architecture, which I'll be updating.

#bookingservice

It's like that Onion article...

Man Who Thought He'd Lost All Hope Loses Last Additional Bit Of Hope He Didn't Even Know He Still Had

Now that I'm running a mentorship #podcast, I'd like to get more people on it as guests, so I thought of deploying some sort of appointment management software. Browsing the Open Source Calend.ly alternatives section only really gives cal.com as something viable. A clean UI that integrates with CalDAV and offers great features (some behind paywall, but still). Self-hostable in theory...

I took a first stab at it, and was immediately blocked by something call turbo which is Vercel's new and shiny tool for building javascript apps.

So, immediately I was prevented from just doing the bare minimum I hope to expect from JS applications:

npm install
npm run

Okay, I get it, it's a Next.js app, so it needs some amount of compilation for all that Typescript and JSX.

My first portent was the fact that yarn was running for minutes, downloading all the dependencies. All 2.5 gigs of them...

After the download completed I proceeded with build. It ran for about five minutes and crashed with OOM exception. I've spent next hour trying to get it to work by passing the NODE_OPTIONS="--max-old-space-size=4096" and it kept failing.

After digging around some more, it looks like turbo specifically whitelists the environment variables passed to the applications being built, and NODE_OPTIONS was not one of them. After adding it to the turbo.json the build started progressing, but still failed soon after, completely saturating the available RAM on the small Vultr VPS I was using for this purpose...

I've cleared up some room on the disk and created a 2 gig swap file... Build process went on for 10 minutes and crashed. Okay, let's bump that up to 4 gigs... now it's running for 12 minutes and crashes... Eventually, after scrounging all remaining space on the box, the build has completed with 8 gigs of swap, after whopping 25 minutes.

The app was finally running...

Now my node_modules folder has a .turbo cache folder, that bring the total to 6 gigs of disk space...

Now I felt like Doc Brown in the famous 1.21 Gigawatts scene

All the bugs and configuration issues notwithstanding I have the software running...

A few weeks later I've fetched the most recent release, and the process had to be done once more. Now that they've upgraded to a newer version of NextJS, it now takes 40 minutes to build, and the site itself is slow beyond reason. I though that SSR and fancy new “Oh, we're just like PHP was 10 years ago, but with React on the server” it is supposed to be fast...

I'll likely be nuking this software from my server... I can't be using products that are only usable if you're paying Vercel for the privilege...

I can probably write a small subset of features that I need that will not require 2.5 gigs worth of NPM packages, and such insane build times.

It should just be

npm install
npm run

Or better yet, write it all in zig with a 10Mb binary with no extra dependencies...

I've been running my own infrastructure for about 20-ish year, as a hobby for fun and profit. In the early days it was a couple of boxes at home running some flavor of RedHat on a domestic ADSL connection. Then one day mail stopped working, and after much scramble we figured out that the ISP has simply blocked inbound port 25. I've upgrade the home connection to a business plan, which was twice as expensive, with same speed, but the ports were not restricted. It lasted for a while until one day a power outage happened and fried the hard drive. I've moved to the cloud using MediaTemple.net, one of the first VPS providers at a considerable $50/mo. qmail was compiled from scratch using some step-by-step guide, apache was chugging along serving PHP-based web sites and we were off. At the time the setup was based on SquirrelMail and Gallery. This server has survived until MediaTemple has completely discontinued the VPS plan they were offering, and suggested moving to another one (much cheaper), but the prospect of having to recompile and reconfigure qmail was a bit too much, and I've decided to go with something that runs out of the box, so I picked postfix, which still powers my mail setup today. Around that time Edward Snowden's revelations showed the depths of surveillance and I thought to move my stuff to a country with better privacy laws, so I switched to 1984 Hosting out of Iceland. I was pretty happy using them for quite a long time, but at some point their storage system has suffered a catastrophic failure and I had to plug the holes by re-routing my mail through Gmail. Hey, I was in a pinch. Eventually they were able to recover the files, but I've since moved on to Digital Ocean, as I wanted something on a cheaper side.

So, let me tell you about my current set-up.

I'm currently running on a Digital Ocean VPS that I've obtained shortly after the 2017 1984Hosting Crash. Originally provisioned with Ubuntu Server 17. It's been upgraded continuously and it's running the latest version now.

Category Purpose Software Stack
Monitoring System Load, etc. Munin Perl
Logging Grafana Go
Data Capture Collectd C
Analytics Matomo PHP
Connectivity Email (SMTP) Postfix C
Email (IMAP) Dovecot C
Email (Filtering) Pigeonhole Sieve C
Email (Antispam) MTPolicyD Perl
Email (Verification) OpenDKIM OpenDMARC C
Email (UI) RoundCube PHP
Video Calling Tlk NodeJS
Calendar + Contacts Baïkal PHP
To-Do Vikunja Go / TypeScript
Security VPN Wireguard C
VPN (Management UI) WG Provision NodeJS
VPN (DNS Tunneling) Iodine C
Password Management VaultWarden Rust / Typescript
Attack Mitigation Crowdsec Go
SSO Zitadel Go
Social Media Status updates Pleroma Elixir
Video Hosting PeerTube TypeScript
Blog WriteFreely Go
Collaboration Knowledge Base Outline TypeScript
VCS Gitea Go

My criteria for the software – preferably compiled, single binary, low memory footprint. This usually precludes things like Ruby and Java, but I do currently run some NodeJS based tools, but for most part they seem to behave.

Costs-wise: $32.5 CAD/mo for the server. $24 for the instance and $5 for additional volume + tax. Not sure what I pay for DNS, because I own a bunch of domains... I use EasyDNS + ZoneEdit, which I can highly recommend.