// 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 gifStructured 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#n5G4C3gsjF4fAdd 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