Skip to content

Instantly share code, notes, and snippets.

View janit's full-sized avatar

Jani Tarvainen janit

View GitHub Profile

The Birth of Afroute.com: Rebuilding a 19-Year-Old Platform in One Week with AI-Native Development

A Technical Case Study by Jani Tarvainen February 2026


Executive Summary

In February 2026, I rebuilt a multi-tenant driving directions platform that has been operating since 2007 from scratch. The project went from first commit to 17 production tenants serving real visitors across Europe and Africa in a week. The entire codebase was produced by a team of two: me as product owner, architect, and technical director, and Claude Code (Anthropic's AI coding agent) as the implementation engine. I did not write a single line of code by hand.

Keybase proof

I hereby claim:

  • I am janit on github.
  • I am janit (https://keybase.io/janit) on keybase.
  • I have a public key ASAVpmR_PpgT0putmX8REETDu2wYOegUUqL5Mq_pWcmb4wo

To claim this, I am signing this object:

@janit
janit / gist:08db57c88017a8937ba3bfc107f55aa5
Created January 15, 2021 14:02
Powercycle UniFi PoE Port via adi using node.js
// https://www.npmjs.com/package/node-unifi
var unifi = require('node-unifi');
var controller = new unifi.Controller("CONTROLLER_IP_HERE", 8443);
// LOGIN
controller.login("YOUR_USER_HERE", "YOUR_PASSWORD_HERE", function(err) {
if(err) {
console.log('ERROR: ' + err);
@janit
janit / 1_readme.md
Last active November 19, 2020 09:21
Benchmark of eZ Platform EE 2.5.15 install on Composer 1.10 and 2.0

Recently I did a round of benchmark on the performance and memory implications for an install of Ibexa Experience. You can find this article with some analysis of results here: Benchmarks of Composer 2.0 vs 1.10 with Ibexa DXP

Björn Köster was interested in if I had did any tests for eZ Platform EE 2.5. I had not, but have now. Similar to with Ibexa DXP, the improvements are significant on 2.0. Scripts used for this (single) benchmark are in other files. See raw results below.

------8<------------------8<------------------8<------------------8<------------------8<------------

Composer 1.10:

@janit
janit / 1_main.sh
Last active November 19, 2020 08:09
Benchmarking Composer 2.0 and 1.10
composer selfupdate --2
sleep 10
./benchmark.sh
cp results.txt 2_0-1.txt
sleep 60
./benchmark.sh
cp results.txt 2_0-2.txt
// YAML config for sending emails on eZ Platform Cloud / Platform.sh on eZ Platform v3.0 and higher
swiftmailer:
url: 'smtp://%env(PLATFORM_SMTP_HOST)%'
spool: { type: 'memory' }
eZ Platform v3.0.0 used ezplatform-kernel 1.0.0 package which had an issue with
storing images in the wrong directory: https://jira.ez.no/browse/EZP-31546
The issue was fixed in ezplatform-kernel 1.0.1 (shipped in eZ Platform v3.0.1),
but misplaced files and corrupt database entries for image binaries remain in
the wrong location. This will make your installation not work consistently.
This is a set of commands that can be used to remedy the issue and bring your
file structure and database up-to-date if you have been running version 3.0.0
@janit
janit / preparerichtext.php
Last active February 6, 2024 11:52
Convert HTML to eZ Platform Rich Text DocBook XML format
<?php
// This is the namespace you want to use
use EzSystems\EzPlatformRichText\eZ\FieldType\RichText\Type as RichTextFieldType;
// this would be a method in your class (you'll need to inject RichTextFieldType)
// It has some extra wrangling of input not required, but makes it moarrr robust
private function prepareRichText($inputText){
if($inputText === ''){
@janit
janit / init.txt
Last active June 15, 2018 15:42
Using Zyxel SBG3300 with CDC ethernet on Huawei E5377 (eth3G)
# You can run the Huawei E5377 LTE modem as an ethernet device on the Zyxel SBG3300 router
# More here: https://kb.zyxel.com/KB/searchArticle!gwsViewDetail.action?articleOid=013274&lang=EN
Short info:
$ telnet 192.168.1.1
$ sh
$ usb_modeswitch -v 12d1 -p 1f02 -V 4817 -P 5340 -M 55534243123456780000000000000a11062000000000000100000000000000
$ lsusb
@janit
janit / sw.js
Last active October 31, 2019 11:26
Service Worker example for controlling what is cached - See https://malloc.fi/fix-duplicate-redirects-service-worker-caching
self.addEventListener('install', function (event) {
event.waitUntil(preLoad());
});
var preLoad = function () {
// console.log('[PWA Builder] Install Event processing');
return caches.open('pwabuilder-offline').then(function (cache) {
// console.log('[PWA Builder] Cached index and offline page during Install');
return cache.addAll(['/offline.html', '/']);
});