blog.iankulin.com

Posts

Getting Your Vite React App to Work on Github Pages

I walk through deploying a Vite/React app on GitHub Pages using the branch-based setup. I cover pointing Pages at a /docs directory, setting Vite’s base path to the repo name, building and copying the output to /docs, and an optional vite.config change to build directly into it...

React Expense Tracker App

This is a write-up of an exercise from Mosh’s React 18 course: building a small expense-tracking app in React and TypeScript, with Zod used for form validation. I cover component breakdown decisions, persisting expenses to local storage, tradeoffs in TypeScript type definitions, and refactoring repeated table markup into reusable components...

What's unfinished in your Udemy?

A rundown of the tech courses and tutorials I started but never finished, including Udemy purchases, 100 Days of SwiftUI, MIT’s Missing Semester lectures, and Stanford’s CS193p, with brief notes on why each was abandoned. I argue that quitting a course in favor of building real projects is usually a good trade, since courses are mainly valuable for discovering tools and concepts you didn’t know you needed...

Copying Objects in JS

I take a look at copying objects in JavaScript for React state updates, covering why simple assignment fails, how the spread operator creates copies, and how to selectively replace properties during a copy. I also show why shallow copies fall short with nested data, demonstrating how to manually spread nested arrays for add and remove operations, and end by noting how the approach gets messy at deeper nesting levels...

CSS for React Components

I compare approaches to styling React components, including global stylesheets, inline style objects, CSS and component libraries, per-component CSS files, CSS modules, and styled-components. I demonstrate each on a simple card component, noting trade-offs such as name clashes, hover effects, and unused CSS accumulating over time. I find styled-components the most elegant but lean toward per-component CSS files to avoid extra dependencies...

React - a To Do Example

My To Do app gets rebuilt in React, continuing a series that has already covered vanilla JavaScript and htmx versions backed by the same REST API. I cover React’s core ideas—components, declarative UI, and the virtual DOM—along with Vite build tooling, and walk through the app’s components, useState-based state management, and passing data via props. React’s tooling complexity and 150K of shipped JavaScript make it overkill at this scale, but I plan further React work, possibly with TypeScript...

htmx - A To Do Example

An introduction to htmx and the hypermedia and HATEOAS concepts behind it, followed by a conversion of a simple todo app from a Node/Express setup that serves JSON and renders client-side in JavaScript to an htmx version where the server returns HTML fragments instead. I compare the two implementations and discuss when htmx makes sense, particularly for server-side developers who want to avoid writing frontend JavaScript...

Testing Node.js apps - Mocha, Chai, and Supertest

I walk through testing a Node/Express API with mocha, chai, and supertest, using a simple maths-endpoint app as the example. I cover installing the tools as dev dependencies, exporting the app so tests can control it, writing test suites and cases, running tests via an npm script, and the role each tool plays. I had been using Bruno for lightweight endpoint checks and found the full setup trivial to configure...

Simple SQLite in Express

In this walkthrough, I build a minimal Node/Express REST API backed by SQLite as a learning exercise for migrating an app away from Mongoose. I cover query strings versus request bodies, CRUD endpoints for a users table, and rewriting string-interpolated SQL as parameterized queries to prevent injection. I close with a table of REST conventions for HTTP methods and a link to the finished project on GitHub...

Using LXC templates in Proxmox

A guide to automating the setup of new self-hosted services on Proxmox by converting a fully configured LXC container into a reusable template. I cover preparing the base container with standard software such as Docker and Tailscale, addressing clone-specific issues like host names, machine IDs, and SSH host keys, then cloning the template to spin up new containers quickly...

Practice your restore strategy

My routine quarterly disaster-recovery test in my Proxmox homelab—shutting down the production node and restoring its backups onto a second machine—turned up a few minor issues: the backup node ran out of disk space, was still on an old Proxmox version, and was missing a config fix for backing up LXCs to NFS. The exercise also prompted me to reflect on sticking with Proxmox, Synology’s reliability, and the Uptime Kuma and ntfy monitoring that confirmed services came back up...

Gogs, Gitea, Forgejo

A security vulnerability announced for Forgejo, which also affects Gitea and Gogs, prompted me to look into the fork history behind my self-hosted Gogs setup: Gitea split from Gogs in 2016 over project management disagreements, and Forgejo forked from Gitea in 2022 after its trademarks moved to a company. Impressed by Forgejo’s handling of the issue and only lightly invested in Gogs, I’m considering a switch. The takeaway is that project governance matters alongside features, and security announcements for the tools you rely on are worth following...

Git - pushing to two remotes

A guide to pushing a single git repository to two remotes, prompted by my running a private Gogs instance alongside GitHub. I cover naming remotes meaningfully rather than relying on the convention of origin, pushing to each remote explicitly, and using the -u flag to set a default remote, which becomes the source of truth for both pushing and pulling. My typical setup treats Gogs as the source of truth, with manual pushes to GitHub when code needs to be shared...

Concurrency and channels in Go

I offer a beginner-oriented walkthrough of Go’s concurrency basics, built around a small demo program with a worker function that sleeps and reports. I introduce goroutines, then channels for passing values between the worker and the main program, explain why plain channel reads block, and show how a select statement with a default case enables non-blocking checks, finishing with closing the channel to release resources. The sample code is available on GitHub...

Date formatting in Go is quirky

I ask ChatGPT for a Go date-formatting example and assume its answer of Format(“02012006”) is a hallucination, until discovering it was actually correct: Go bases its date format strings on the reference time 1/2 3:04:05 2006, with each number mapping to month, day, hour, minute, second, and year...

Gogs - your own tiny GitHub

I wanted a private git server for version-controlling my plain-text financial accounts (kept with beancount), rather than pushing them to GitHub. I walk through installing Gogs — chosen over Gitea for being simpler — in Docker on an LXC container, including a storage driver fix needed to get it running, and finish with the first-run setup and pushing a repo...

New Self-Hosted Service Workflow

A walkthrough of my workflow for adding a new self-hosted service to my Proxmox homelab, using audiobookshelf—set up after abandoning Audible—as the worked example. It covers running the service as a Docker container inside an unprivileged Debian LXC, mounting NAS storage via fstab, Tailscale access, Ansible automation, monitoring with Uptime Kuma, and Proxmox backups...

Ansible - Importing a Playbook

I look at structuring Ansible playbooks, starting with the distinction between plays and tasks, then covering how to import one playbook into another with import_playbook. I include a note on where imports can be placed — at the top level of the YAML, not inside a play...

ViewTube

ViewTube is a self-hosted YouTube front end that strips out ads and tracking, with local accounts for subscribing to channels and keeping video progress. I got it running in a VM with Docker Compose in about five minutes, along with a workaround of using MongoDB 4.4 because newer versions require AVX CPU support my VM didn’t expose...

Adding Front Matter To mdserver

The mdserver project needed page titles defined as YAML front matter inside markdown files, in the style of Jekyll and Hugo, instead of being generated from the file name. Rather than writing custom extraction code, I use Showdown’s built-in metadata support, enabled with a converter flag, and confirm the front matter leaves the HTML output unchanged...