My thoughts and tips from my work life.

Search This Blog

© 2001-2026 Erik Pitti, All Rights Reserved. Powered by Blogger.

Sunday, April 19, 2026

Why I Built My Own Help Desk (And Learned Go Along the Way)


At some point, every small team hits the same wall: someone asks "where do I send support requests?" and the answer is either a shared inbox that everyone ignores or a $200/month SaaS that's overkill for what you actually need.
I hit that wall, and instead of picking the least-bad option, I did what developers do: I built something. And because I wanted to learn Go, I built it in a language I'd never shipped production code in before.

The problem with existing options

The self-hosted help desk space hasn't changed much in a decade. osTicket is functional but feels like it was designed for a different era of the web. Zammad is more modern but heavy — it wants a dedicated server, a full Elasticsearch instance, and an afternoon of your life just to get it running. FreeScout is closer to what I wanted, but it's PHP, and every time I touched the config I felt like I was doing archaeology.
The SaaS options are fine if you're okay with your support data living on someone else's infrastructure and paying per agent per month forever. I wasn't.
What I wanted was simple: a help desk that installs in one command, runs as a single binary, and doesn't make me think about it after the first deploy.

Standing on the shoulders of giants

I didn't start from a blank page. Years of using help desks — good and bad — gave me a pretty clear picture of what I wanted to steal and what I wanted to leave behind.
  • HESK got two things right that most tools overthink: the ticket flow is dead simple, and custom fields let you capture exactly what you need without forcing you into a rigid schema. I kept both.
  • Remedy is the opposite of simple — it's enterprise software in the fullest sense — but its CTI model (Category, Type, Item) is genuinely useful for classifying tickets in a way that makes reporting meaningful. Once you've worked with a well-configured CTI taxonomy, the flat category lists in lighter tools feel like a step backward.
  • Freshservice showed that a help desk doesn't have to look like it was built in 2009. A clean, modern interface isn't a luxury — it's what determines whether your team actually uses the tool.
The goal was to combine all three: HESK's simplicity, Remedy's classification model, and Freshservice's interface sensibility — in something you could self-host and own outright.

Why Go (and why I didn't know it yet)

I'd been wanting to learn Go for a while. It has a reputation for producing fast, reliable, boring software — and boring software is exactly what a help desk should be. The standard library handles HTTP, TLS, and templating without pulling in a dependency tree. The compiler catches an entire class of bugs before they ship. And a Go binary is a Go binary: no runtime, no interpreter, no "which version of Node do you have installed."
So I made a bet: learn Go by building something real. Not a tutorial project, not a toy. A production app I'd actually run.

What it took

Learning a language by building a non-trivial system is humbling. Go's approach to error handling, concurrency, and interfaces is different enough from other languages that I rewrote core pieces two or three times as my understanding improved. The discipline the language imposes — explicit errors, no generics magic, dependencies passed by hand — forced me to think carefully about data structures and ownership in ways I'd previously been able to gloss over.
The surface area of a help desk is also deceptively large. Tickets going in and agents responding sounds simple, but you also need authentication that's actually secure (TOTP MFA, SAML SSO for teams that want it), SLA tracking so nothing falls through the cracks, email notifications that don't end up in spam, and a permission model that doesn't collapse the moment you add a second role.

AI as a collaborator

The piece I'm most proud of is the MCP server layer. Full disclosure: Go Help Desk itself was built with the help of Claude — so it felt right to make Claude a first-class citizen in the finished product.
MCP (Model Context Protocol) is a standard way to expose your application's data and actions to AI tools like Claude. With Go Help Desk's MCP server, you can ask an AI assistant to pull up open tickets, summarize a thread, or update a ticket status — without building a custom integration. That felt like a meaningful step forward over what the existing tools offer, and it's not something I would have thought to build if I hadn't been working alongside an AI the whole time.
Building with AI assistance is still a pretty new experience for most developers. I found it genuinely changed how I worked — less time stuck on unfamiliar syntax, more time thinking about architecture and what I actually wanted to build. For a first Go project, that was a meaningful difference.

What I shipped

Go Help Desk is live. It's open source (AGPL-3.0), self-hosted, and runs as a single Docker container backed by Postgres. Features in v1:
  • Multi-user with roles (admin, agent, end user)
  • TOTP MFA + SAML SSO
  • SLA tracking and breach alerts
  • Full REST API
  • MCP server for AI tool integration
  • WASM plugin support for extensibility
Setup takes about five minutes. There's a /setup route on first run that walks you through creating the first admin account — no manual SQL, no config file archaeology.

Would I do it again?

Yes, and I'd recommend it as a way to learn any language: pick a real problem you actually want to solve, and build the thing. The pressure of shipping something useful keeps you honest. You can't paper over a bad abstraction when you're the one who has to live with it.

Go turned out to be a good choice. And having Claude along for the ride made learning it a lot less lonely.




Monday, November 6, 2023

RTSP Security Camera Viewer


Working on an app to live stream four MJPEG preview streams from security cameras. Going to use WinForms on .Net Core.

Links to save for ideas about the app.

Really real full screen apps:

https://www.codeproject.com/Articles/16618/How-To-Make-a-Windows-Form-App-Truly-Full-Screen-a

RTSPClientSharp

https://github.com/BogdanovKirill/RtspClientSharp/issues/28

https://www.nuget.org/packages/RtspClientSharp

Accord-Net looked really cool, but doesn’t actually decode the video streams

https://github.com/accord-net/framework/blob/development/Samples/Video/Two%20Cameras/MainForm.Designer.cs

Didn’t want a VLC dependency (though it could be worse)

https://stackoverflow.com/questions/10280794/play-rtsp-stream-in-wpf-or-winforms

 

Sunday, March 28, 2021

Tossing an Outlook 2016 for Mac Profile


I'm archiving this here for my own benefit. I didn't come up with this originally. Credit due to @ajkgordon on superuser.com (original link) for the original. To delete the Outlook profile, go to Finder > Applications > right-click / CTRL-click on Outlook > Show Package Contents > Contents > SharedSupport > Outlook Profile Manager > Select profile > Click the minus sign to remove. Then empty trash. After this, the user can launch Outlook and setup their profile as if it was first being setup. In case you're looking for PC instructions, here the are from memory. Open Control Panel (the legacy control panel, not the new Windows 10 settings) Open the Mail control panel Select Show Profiles Remove the profile Restart Outlook and setup the profile again.

Tuesday, July 31, 2018

Fun with Lipsum and Google Translate


Feed the "Lorem Ipsim" text into google translate for interesting results. You can find out more about the history of the latin-like "Lorem Ipsum" or "Lipsum" text and its origins with Cicero at www.lipsum.com.

Original Text:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis egestas mattis massa ut tristique. Nunc euismod malesuada blandit. Praesent lacinia consequat gravida. Praesent rhoncus nunc ut odio pulvinar in suscipit enim vestibulum. Vivamus non justo pellentesque risus elementum interdum. Vestibulum ornare sapien in nisl feugiat pellentesque. Phasellus ut mi urna. Ut sit amet metus augue. In posuere pellentesque mattis. Curabitur ullamcorper placerat lectus sagittis aliquet. Morbi faucibus sem id diam mattis non auctor tortor adipiscing. Proin a massa congue lectus elementum accumsan ac ut sem. Curabitur blandit augue eu turpis tempus eu lobortis eros consequat. Donec sed tempus est.

Nulla interdum, lectus quis posuere ultrices, metus erat fringilla elit, vitae sollicitudin dolor ante vel risus. Donec tempus pulvinar venenatis. Nam ac eleifend erat. Praesent bibendum purus vel neque tempor quis tincidunt elit cursus. Etiam id eros urna, sit amet volutpat elit. Nullam non metus orci, eu adipiscing turpis. Nunc gravida lobortis quam ut adipiscing. Aliquam ultrices, purus sed sollicitudin malesuada, nibh lacus lacinia elit, eu euismod nisi felis at ligula. Integer eu lectus sed nisl tristique cursus. Mauris lectus massa, rhoncus et dignissim a, tempor vel quam. In tortor nisl, dictum id consequat at, cursus sit amet dolor. Vivamus ac massa at odio aliquam venenatis ac vel leo.


Google Translate Automatically "Translated" from Latin in Chrome 67 on Windows 10 with the Google Translate Extension installed. I'm still trying to figure out what exactly is the Latin word for CNN:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mass poverty lot of homework to be sad. Performance now malesuada afternoon. Present skirt photography pregnant. CNN now present in order to receive the hated volleyball court. Live element, not just kids smile sometimes. Sapien eu football players betting on nutrition. Boat as my pot. To carrots fear propaganda. Put kids in real estate. Chat ullamcorper real estate arrows and bananas. Soccer team salad diam real estate is the author of macro customer. Planning graduated from the microwave mass element layer and the salad. Chat sit propaganda football high school football season carton peanut products. But until it is too late.

No protein, graduated one basketball set, fears of ecological cleaning, care of the pain and laughter. Until the time of volleyball blockage. In fact, it was ac Vestibulum. Chili drink or not present at any game and running. It also is reality urn, carrots methods. Does not meet the Nullam orci, eu adipiscing turpis. How to get pregnant now carton customer. The latest basketball, chili and care expected, nibh skirt competition, but football Performance at gas networks. An entire football players graduated, but the sad cycle. Graduated largest mass, grilled and soccer from, or how long. The temperature of Medicine, said that development at the cycle of products. And a poisonous hatred and mass live at or refrigerator.

And now I'm curious if someone out there runs this same test if they get a different result set.

Tuesday, June 2, 2015

I'm Still Around


It's been silent around here for too long.

Here's a few of the things I've been working on for the last two years:

  • SCCM 2012
  • MDT 2013
  • Windows Image Creation and Deployment using MDT and SCCM and without those two using DISM/ImageX/GImageX
  • Mac OS X image creation and deployment using DeployStudio
  • Active Directory and Exchange Administration
  • Exchange 2010 -> 2013 on-premises upgrade
  • Sharepoint 2013 farm installation
  • Database migration to SQL Server 2012
  • XMPP-based IM server installation and maintenance
  • Virtualization with Hyper-V
  • High performance storage design, installation, configuration and operation (Dell|Equallogic, Lenovo, EMC)
  • iPad deployment using Apple's DEP
  • Enterprise Chromebook/Chrome OS Deployment
  • Scripts and Tools to manage Chromebook deployments
  • Network Management (Cisco, Ruckus, Meraki)
And much more.

I plan to get back to blogging on this site with insighes

Sunday, January 27, 2013

Setting up WordPress 3.5.1 on 1and1 Windows/MSSQL Hosting Plan


This article gives a great breakdown on setting up WordPress on IIS with Microsoft's SQL server. I'm not sure if this is specific to 1and1's hosting setup but I did find a quirk when using version WordPress 3.5.1 version 1.1.4 of the WordPress Database Abstraction plugin.

You're likely to run into an error similar to the following.
Call to undefined function mysql_free_result() in E:\kunden\homepages\19\<your user id>\www\mysite\wp-includes\wp-db.php on line 1126
Edit the file wordpress-root-dir\wp-includes\wp-db.php look for the following code block:
if ( is_resource( $this->result ) )
  mysql_free_result( $this->result );
Comment both lines out otherwise mysql_free_result will always return an error:
//if ( is_resource( $this->result ) )
  //mysql_free_result( $this->result );
Leave everything else in the function as is, including the closing curly brace "}" on the line below.

If you encountered this error while running install.php you will need to login to the MSSQL admin panel,  delete the tables that were created by the WordPress install.php script and re-run install.php.

Wednesday, March 14, 2012

Configuring Google NoSSLSearch for Windows DNS Servers


Create a new Primary DNS Zone on your DNS server for www.google.com.
Add a single CNAME record with a blank alias name and “nosslsearch.google.com.” for the FQDN for target host. The trailing dot after “com” is important.
Google NOSSLSEARCH
Clear your DNS server cache by right-clicking on your server in DNS manager and selecting Clear Cache.
When your clients request www.google.com, your DNS server will direct the client to nosslsearch.google.com instead of www.l.google.com.
Sample output from NSLOOKUP after configuring this DNS zone:

C:\Windows\system32>nslookup www.google.com
Server:  dc02.domain.local
Address:  10.254.1.2

Name:    nosslsearch.google.com
Address:  216.239.32.20
Aliases:  www.google.com
Hope this helps.