// EXAMPLES

Examples of projects and proof-of-concepts.

Visit my Codeberg page for publicly available repositories.

All of these small projects/POCs are hosted on an old Lenovo box at my home together with many private whitelisted things. In front of it is an Ubuntu VPS that only acts as a fixed IP address and reverse proxy via Caddy to the Lenovo box through a secure WireGuard protocol.

Description

RAGGo is a self-hosted application that indexes your documents and images, allowing you to chat with them using natural language. Everything runs on a Linux server within your own IT infrastructure. Your data never leaves your server, never passes through a third-party cloud provider, and remains completely under your control. There are no unexpected monthly API bills or hidden licensing fees. Once RAGGo is installed, the system runs without additional costs.

RAGGo supports the following document formats:
pdf, docx, odt, xlsx, pptx, html, htm, epub, txt and md

RAGGo supports the following image formats:
png, jpg, jpeg, webp and gif

Structured documents (such as PDF, DOCX, ODT, XLSX, PPTX, HTML, HTM and EPUB) are analyzed semantically while preserving page numbers, headings, tables, and lists as metadata that maintains context. Plain text and Markdown files are split into semantically meaningful chunks rather than being broken in the middle of a sentence. Images are processed using AI captioning that describes their contents and are then indexed together with the other documents, making visual data searchable through natural language.

Built on open technologies such as Go, PostgreSQL with pgvector, and Ollama, the deployment is straightforward and easy to reproduce and audit. A web interface provides chat and document management. For companies and organizations managing large document collections, this creates a searchable knowledge base that remains easy to maintain with predictable costs and without depending on external AI providers.

Guide

Log in – To use RAGGo, log in using the link below.
Username: raggo
Password: oKfE!DHecTgJM9zPjjgfqL#mt59#n5G4C3gsjF4f

Add documents – Click the + button below the input field. Select a supported file (PDF, DOCX, ODT, XLSX, PPTX, HTML, EPUB, TXT or Markdown). The file is automatically parsed and indexed and becomes searchable within seconds. You'll receive a confirmation showing the filename and the number of chunks created.

Add images – Click the image button next to the + button. Select an image file (PNG, JPG, JPEG, WEBP or GIF) and write a short description of the image. The description makes the image searchable. If a vision model has been configured, you can click Auto-caption to generate the description automatically.

Ask questions – Type your question into the input field and press Enter (use Shift+Enter for a line break). RAGGo retrieves the most relevant passages from the indexed documents and images and generates an answer based on that material. Every response cites the source file and, when applicable, the page number for structured documents.

View indexed files – Click Documents in the navigation menu to see an up-to-date table containing everything in your collection: filenames, file types, chunk counts, ingestion timestamps, and detected structural features such as tables and lists. The list updates automatically.

Switch theme – Click the circular button in the lower-right corner to switch between the Light and Dark (Tokyo Night) themes.

Tech Stack
Go – with third-party libraries tsawler/tabula, openai/openai-go, and fsnotify/fsnotify
Postgres 18 + pgvector – PostgreSQL backend with pgvector as the vector store
Taskfile – used for build, deployment, and orchestration commands
Ollama – inference server
▸ AI components – conversational model as the primary chat interface; embedding model that converts text chunks into vectors for similarity search; multimodal model that accepts images as input and produces text output; query rewriter that rewrites previous user prompts into an optimized search query
▸ AI models – gemma4, nomic-embed-text
▸ CSS
▸ HTML
▸ JavaScript

Source code
Private
Username
raggo
Password
oKfE!DHecTgJM9zPjjgfqL#mt59#n5G4C3gsjF4f
Link
RAGGo
Description

Web app for time registration and invoice generation to PDF. I use this app myself in my daily work as a consultant. I built it because there is no app that does exactly this on the Faroese market. Besides, I am also too stingy to pay some company a monthly fee for this. This prototype runs only in the browser without any backend, so all data is deleted every 10 minutes.

Otherwise, in the version I use, a backend API is connected to a VPS that reverse proxies calls through Caddy to my home server, where a SQLite database receives all CRUD operations. This version is of course IP-whitelisted, so you cannot use it ;-)

Guide

1. Enter information about your company on the [SETTINGS] page (there are default values if you cannot be bothered with this)

2. On the [TIMER] page, create Company, which is the company you will work for. Enter name, address, email, phone number and standard hourly rate. All of this is used to calculate the final price and as information for invoice generation.

3. Then create an Assignment, which is a larger chunk of work. It could, for example, be Develop backend for the new website at example.com. A Company can have several Assignments. Here you can also give a longer description of the task and a special price for exactly this Assignment. If no price is given, it is the standard price for the company that was just created.

4. Then create a Task. This is a sub-chunk of work under an Assignment. An Assignment can own many Tasks. So we create a Task called Develop GET customer endpoint or something.

5. From here you can then choose to attach time to a Task, either by starting Timer or by entering a Manual entry.

6. Now the assignment is finished, and you need to send an invoice to Company. Press Generate invoice (PDF). On this page you see hours, amount and price. Write a short description of this Assignment in Comment. Here you can also attach invoice lines that are not hours but some unit. So you can, for example, add a router for 500 kr. each or something. Well, when you are ready, press Generate PDF, and tada, a beautiful invoice, ready to send to Company. Phew, that was a lot, but try it?

Tech stack
Go - the web server, backend code, templating language etc.
HTMX - used to do CRUD operations
GNU Make - used to automate building the binary and deployment to a remote server via ssh with one command.
▸ CSS
▸ HTML
▸ JavaScript
▸ SQLite
Source code
Private
Link
zeitkort
Description

I have wanted to build a project for a long time that streams events from a database to an event consumer. In other words, using what is called CDC (Change Data Capture), where changes are read from the database’s transaction log or replication mechanism and forwarded to a consumer.

CDC/log-based replication is based on the fact that the database already records changes in order to support recovery and replication. In PostgreSQL, this is for example WAL and logical replication/logical decoding; in MariaDB/MySQL, it is the binlog; and in SQL Server, CDC exists as a built-in feature. These mechanisms can capture INSERT, UPDATE, and DELETE operations in tables, which makes this an efficient way to stream changes from a database without requiring the application itself to emit extra events.

I think Debezium is one of the strongest solutions when it comes to streaming data between a database and a consumer, such as Apache Kafka or NATS. Debezium can read changes from the database and forward them as events with metadata. It is written in Java and is easy to deploy as a container on a Linux server.

I have often wrestled with Apache Kafka, and just as often I end up with no result and a headache after a long day of trial and error. That is why I chose to use NATS this time instead. NATS is written in Go and is a binary, unlike that Kafka Java monster with a thousand moving parts.

Anyway, long story short: this is an inventory management system. On the page, you can perform CUD operations, which result in SQL DML against the PostgreSQL database. CDC captures the changes from the log, Debezium sends the change together with metadata to NATS, and from there multiple systems could subscribe to real-time data from the database.

The advantage of this is that the operational system is decoupled from downstream usage of the live data. The inventory system only has to do its normal work against the database, while other systems can consume the changes without being directly tied to the application itself. This could, for example, be a BI dashboard showing live inventory data, or other systems and employees that need to make decisions based on live operational data.

Guide

In the demo, the inventory system is shown on the left and the CDC trace on the right. Select a product and make a change, such as sell, restock, rename/move, or delete. Once the change is made, the right side shows how it moves through the flow: PostgreSQL -> Debezium -> NATS JetStream -> browser. At the bottom, the event is shown as raw JSON and an audit trail, so you can see both the before and after state of the change.

Tech stack
Go - web server, API endpoints, NATS consumer, and SSE event stream.
PostgreSQL - inventory database with logical replication enabled.
Debezium Server - captures database changes from PostgreSQL and publishes them as events.
NATS JetStream - event streaming layer between Debezium and the Go backend.
Taskfile - used for build, deployment, and orchestration commands.
Podman - runs the development and production infrastructure containers (NATS, PostgreSQL, Debezium).
▸ Server-Sent Events - streams CDC events live from the Go backend to the browser.
▸ HTML
▸ CSS
▸ JavaScript
Source code
Codeberg
Link
inventory-fló
Description

Web API for retrieving data from backend, written in Go. This is an imagined example of registering domestic violence to an API endpoint, both as a registration tool and for later analysis.

Deployed as just one binary without any dependencies or runtime environment. The entire frontend is embedded in the binary. The project uses only the Go standard library, no external dependency.

Guide

See the technical guide on the link below.

Tech stack
Go - 100% Golang std lib: html/template, net/http, flag, crypto
Taskfile - process automation, builds and deployment
Reflex - fast rebuild and start of the binary when files in the repo change
Rsync - for syncing to production
▸ CSS
▸ HTML
▸ JavaScript
Source code
Codeberg repos
Link
go-api
Description

Web app developed for Landsverk. Used for job matching and similar things.

Free hosting and deployment to GitHub Pages with Hugo/Go as a static site generator that is integrated with a CI/CD pipeline. One PR into main updates the whole page.

Guide
Find out which profile you are by clicking your way through Starvskumpass.
Tech stack
Go - Hugo uses Go html/template as templating language
Hugo - Static Site Generator written in Go
▸ JavaScript - quiz logic
▸ CSS
▸ HTML
Source code
Github repos
Link
Starvskumpass link
Description

A simple POC of a chat function written in Rust. Rust fascinates me, so I wanted to try to build and deploy a Rust project.

We have a back office where some supporter waits for messages while he eats chips.

Then two users write into the chat, and the supporter can chat with both users at once.

Going forward, I plan to connect the back office to a backend, where a supporter can attach metadata to chats, so that in the future one can make quantitative analyses. Also, if one stores the conversations, one can make sentiment analyses or qualitative analyses.

But I have children and a house and a job I have to take care of, so...

Guide

This POC deletes all data/chats every 3 minutes and has rate limiting on req/resp, so my home server will not be smashed.

Go to the link below. First choose the supporter, go back to the front page in a new tab, and then choose user.

Give the user some name and the chat starts. Write something and the supporter sees that a conversation starts. Now you can chat with yourself.

But what if you want to chat even more with yourself? Create a new user and now the supporter has two chats open.

Tech stack
    Axum - web framework in Rust. Takes care of routing and middleware and all that there. About the same as Gin in Golang and FastAPI in Python
    Tokio - the thing one always uses when one needs async await in Rust
    Serde - serialization/deserialization from JSON to Rust structs
    GNU Make - used to automate building the binary and deployment to a remote server via ssh with one command.
    ▸ CSS
    ▸ HTML
    ▸ JavaScript
Source code
Private
Link
rs-chat
Description

This website is hosted on a Lenovo box at my home.

Guide
N/A
Tech stack
Go - 100% Golang std lib, except for a fairly standard dot-env reader, joho/godotenv
Taskfile - process automation, builds and deployment
Reflex - fast rebuild and start of the binary when files in the repo change
Rsync - for syncing to production
▸ CSS
▸ HTML
▸ JavaScript
Source code
Private
Link
fló.fo