iBoard - ABOUT

Avatar Andi
#iboard

iBoard is a little practicing project, figuring out how Elixir-development and AI comes together. So, I recently wrote this Blog-server. The content here doesn’t really matter! The project is not public (yet) but will be published at GitHub once it fulfills some basic quality standards ;-)

The iBoard Project This web application is written in Elixir with Phoenix, LiveView, TailwindCSS, DaisyUI, Ecto/Postgres, to name the most important.

ExDocs

Documentation

The full dependency list reads like:

:bcrypt_elixir, "~> 3.0"
:phoenix, "~> 1.8.3"
:phoenix_ecto, "~> 4.5"
:ecto_sql, "~> 3.13"
:postgrex, ">= 0.0.0"
:phoenix_html, "~> 4.1"
:phoenix_live_reload, "~> 1.2", only: :dev
:phoenix_live_view, "~> 1.1.0"
:lazy_html, ">= 0.1.0", only: :test
:phoenix_live_dashboard, "~> 0.8.3"
:esbuild, "~> 0.10", runtime: Mix.env() == :dev
:tailwind, "~> 0.3", runtime: Mix.env() == :dev
:heroicons, github: "tailwindlabs/heroicons", tag: "v2.2.0"
:gen_smtp, "~> 1.2"
:swoosh, "~> 1.5"
:castore, "~> 1.0"
:req, "~> 0.5"
:telemetry_metrics, "~> 1.0"
:telemetry_poller, "~> 1.0"
:gettext, "~> 1.0"
:gettext_sigils, "~> 0.1.0"
:jason, "~> 1.2"
:dns_cluster, "~> 0.2.0"
:bandit, "~> 1.5"
:tzdata, "~> 1.1"
:boundary, "~> 0.10", runtime: false
:ex_doc, "~> 0.31", only: [:dev, :prod], runtime: false
:earmark, "~> 1.4"

With a big hug to this gorgeous community!

Follow the tag #iboard if you’re interested in the faith of this project.

Features so far (Buzzwords)

  • Accounts, Users (phx.gen.auth)
  • Posts, Drafts, Authors, Moderators, Likes, Followers
  • User management, invite by e-mail
  • Supports DaisyUI Themes
  • Supports Locale and Timezone
0
2026-04-02 18:52

Howto Write a Post

Avatar Andi
#howto #iboard #system

Getting started

To create a new post, open the navigation sidebar and click New Post. You will land on a form with two language tabs at the top (EN and DE) and several fields below.

Choosing one or both languages

Each post can be written in English, German, or both. The two tabs at the top of the form each have a checkbox:

  • Tick the box next to a language to include that language in the post.
  • Untick it to exclude the language. (At least one language must remain ticked.)
  • Click the language label itself to switch the editor to that language without touching the checkboxes.

If you publish a post with both languages, readers see the version that matches their selected content language.

Subject and body

The Subject is the headline of your post. The Body is the article itself and is written in Markdown. You can use:

  • # Headings, ## Sub-headings, etc.
  • **bold**, *italics*, `inline code`
  • Bulleted and numbered lists
  • Links: [label](https://example.com)
  • Fenced code blocks with three backticks
  • Block quotes with >

The body textarea grows automatically as you type.

Attaching files and images

Below the body you will find the Attachments uploader. You can drop up to five files of up to 50 MB each into that area, or click to pick them from your computer.

For every attachment you can fill in:

  • Title — used as the link label when the file is not an image.
  • Description — optional caption.

To embed an image inline in your text, insert a placeholder anywhere in the body using curly braces around the file name:

Here is the diagram:

{architecture.png}

And here is a downloadable PDF: {whitepaper.pdf}

When the post is rendered:

  • Files whose content type starts with image/ are inlined as <img> tags.
  • All other files become Markdown links to the uploaded file.

Tip: click the file name of any attachment in the form to copy its {placeholder} to your clipboard. A short flash confirms the copy.

Tags

The Tags field accepts space-separated words, for example:

howto elixir phoenix

When you focus the field, a dropdown opens with all tags that already exist in the system. Click a suggestion to add it, or just type a new tag — new tags are created on save.

Visibility

The Who can see this? select controls the audience:

  • Public — anyone on the internet can read the post.
  • Registered Users — only signed-in users.
  • Friends Only — only your mutual followers.
  • Direct Message — only the specific recipients you pick.

When you choose Direct Message a recipient picker appears. Type a name to search and click a result to add it.

Comments

The Who can comment? select is independent from visibility:

  • Nobody (Turned Off) — comments are disabled.
  • Friends / Followers / Registered Users / Public — progressively wider audiences.

Saving as a draft

Clicking Save Post does not publish the post — it is stored as a draft. Drafts are only visible to you (and to admins), so no follower will see anything yet. This gives you a chance to preview the rendered article and fix anything before the audience sees it.

Finding your drafts

Drafts are hidden from the default /posts view. To see them:

  1. Open My Postings (/posts).
  2. In the toolbar at the top, find the three-button switch (the three document icons sitting next to each other):
    • No Drafts (single document) — hides drafts, the default.
    • With Drafts (document with overlay) — shows published posts and drafts together. Drafts are marked with a small “Draft” indicator in the listing.
    • Drafts Only (empty document) — shows only your drafts.
  3. Pick With Drafts or Drafts Only and your unpublished post appears in the list.

Click the draft to open the preview. This is exactly how the article will look once published — images, attachments, formatting and all.

Publishing the draft

When you are happy with the preview, publish it in one of two ways:

  • From the listing: in the row of action icons next to your draft, click the green eye icon (Publish).
  • From the post itself: the toolbar above an unpublished post shows a Publish button.

Either path opens a small dialog asking whether you want to notify followers:

  • Yes, send e-mail — the post is published and a notification email is sent to your followers (and friends, deduplicated). The email is bilingual when the post is bilingual, includes inline images, and attaches all non-image files.
  • No, just publish — the post is published without sending any email. Use this for minor posts or when you don’t want to bother subscribers.

After publishing, the eye icon turns into an eye-with-slash icon (Unpublish) so you can move the post back to draft state any time.

About the “e-Mail followers” checkbox on the form

The checkbox e-Mail followers that sits next to the Save button is not used to publish a fresh draft — at that point the post has no published_at date yet, so no email is sent regardless of the checkbox.

This checkbox only matters when you edit an already-published post: tick it before saving to send a fresh notification email about the update; leave it unticked to save the edit silently. New drafts always use the publish dialog described above to decide on email.

0
2026-05-30 18:50

Latest Changes and Improvements

Avatar Andi
#iboard

What’s new on the blog

A short tour of the changes that landed over the last few days. Most of it is quality-of-life work on the read and admin experience.

Resizable table columns

Every table in the application — the user admin, the posts table, attachments, authors, registration requests — now has draggable column widths.

  • Hover any column header and you’ll see a thin separator line on the right with a small diagonal grip in the corner.
  • Grab the grip and drag horizontally to resize the column.
  • Your widths are saved per table and per column to your browser’s local storage, so they survive reloads, navigation, and re-renders.

Since each user keeps their own preferences in their own browser, you can shape the tables to fit your screen without bothering anyone else.

Like count column on the posts table

The /posts table view has a new heart column between Comments and Attachments. It shows the like count as a small red badge when a post has any likes. The old unlabeled icon column is gone — the pinned (★) and system (📍) indicators now sit inline right next to the post subject, so the table is one column shorter overall.

Smaller screens, much better

If you read the blog on a phone (iPhone mini and similar), you’ll notice things fit a lot better now.

  • Top bar. The direct-message icon (with the unread badge) and your avatar are now visible at every viewport size, not just on wide screens. Settings, language, timezone, and the theme picker move to a “Preferences” section at the bottom of the sidebar when they don’t fit in the top bar.
  • Sidebar. Tapping any link in the sidebar — including the preferences — automatically closes the drawer, so you don’t have to dismiss it manually before you can read.
  • Post detail page. The toolbar above each article (back, reader/standard, edit, print) no longer overflows. On phones, the buttons collapse to icons, so you can find the print button without scrolling sideways.
  • Tags page, home stats, admin headers, flash messages. All re-flowed for narrow viewports — no more horizontal scrolling on a 375px screen.
  • Markdown content. Long URLs wrap, large images shrink to the viewport, and wide tables get their own internal horizontal scroller instead of forcing the whole page to scroll.

Tag selection scrolls to the article

When you pick a tag on /tags, the page now smoothly scrolls to the first matching article. The header stays just above the fold so you can see what you’ve selected.

Image preview: fullscreen finally works

Clicking the fullscreen button in the image preview was, until now, invisible: the dialog rendering covered the fullscreen layer, and the enlarged view only flashed for a second as the modal closed. Fullscreen now applies to the inner content of the preview, so the enlarged image is visible right away. Press Esc to exit fullscreen; the preview stays open.

No more duplicate emails for mutual followers

If you and another author follow each other (so you’re “friends”), you used to receive two notification emails every time the other person published a new post: one as a friend, one as a follower. Each user now lands in exactly one notification bucket, so you get one email per post — never two.

0
2026-05-30 15:48

My Server Migration from AWS to Infomaniak in Switzerland

Avatar Andi
#bigtech #getoutofit
AI Thumbnail
AI Thumbnail — EN: David vs. Goliath: Why I turned my back on the complexity of US Big Tech and moved my servers to the Swiss Alps. DE: David gegen Goliath: Warum ich der Komplexität von US Big-Tech den Rücken gekehrt habe und mit meinen Servern in die Schweizer Alpen gezogen bin.

It is done. After much deliberation and some preparation time, I pulled the plug and migrated my entire server infrastructure from Amazon Web Services (AWS) to Infomaniak in Switzerland. For me, this step was not just a technical decision, but primarily a matter of principle.

In this report, I want to share my reasons for making this switch.

1. From Complexity to Simplicity

AWS is undoubtedly a powerful tool. It offers a technical solution for almost every conceivable problem. But for me – and probably for many other small to medium-sized projects – that is exactly the issue: the sheer volume of services, the cluttered dashboard, and the often incomprehensible pricing models are simply overwhelming. It feels like you spend more time setting up the right permissions (IAM) and trying to figure out why a service suddenly costs more than you do actually working on your projects.

Infomaniak, on the other hand, feels like a breath of fresh air. The interface is clean, logically structured, and above all, simple. You get exactly what you need without having to fight your way through a jungle of cryptic acronyms. The services do what they are supposed to do, the pricing is transparent and fair, and the learning curve is refreshingly gentle.

2. Digital Sovereignty: Goodbye, US Big Tech!

The second, equally important reason was my strong desire to reduce my dependence on major US technology corporations. In an era where data is the most valuable commodity, I no longer wanted to leave my infrastructure to the whims and privacy policies of American hyperscalers.

In Infomaniak, I found a partner that is not only based in Europe (Switzerland) but also strongly focuses on data privacy, sustainability (100% renewable energy), and independence. It is incredibly reassuring to know that my data falls under strict Swiss data protection laws rather than sitting on the servers of a company ultimately subject to the US Cloud Act.

Conclusion

The move naturally cost time and effort – a migration is never a walk in the park. But looking back, it was the best decision for my setup. I now have a system that I can fully oversee again, that doesn’t crush me with unnecessary complexity, and that gives me back a large chunk of my digital sovereignty. A clear win!

0
2026-05-27 16:52

Offline Cafè Oida

Avatar Andi
#social

Erstes Offline-Cafe in Wien eröffnet

Offline-Cafe
Offline-Cafe — Ein Handy, versperrt, in einer Glasbox.

Am Samstag hat in Wien das nach eigenen Angaben erste „Digital-Detox-Cafe“ eröffnet. Das „Offline Oida“ befindet sich im Innenhof einer ehemaligen Molkerei auf der Wieden. Alle elektronischen Geräte wie Handys und Laptops sollen dort ausgeschaltet bleiben.

Unter der Woche ist das Cafe das normale „Lokal im Hof“, doch am Wochenende verwandelt es sich nun in eine Zone ohne Klingeln und Scrollen. Geöffnet hat es ab sofort samstags und sonntags von 10.00 bis 18.00 Uhr.

Quelle: Der ganze Artikel auf ORF W…

0
2026-04-27 03:10

Fix: duplicated e-mails for followers

Avatar Andi
#iboard
Too much!
Too much! — A comic drawing, showing a user who is annoyed by receiving too much e-mails.

Until this version, when an author created a post, e-mails to followers was sent. When the author then published a post, another e-mail was sent. If the author fixed a typo and saved the post, another e-mail was sent.

Of course, this is annoying!

This fix now asks the author either e-mails should be sent.

I hope this makes the system more fun to use 😉

2
2026-04-15 12:53

iBoard - README

Avatar DevOp
#devop #iboard

WAppCore - The iBoard Project

A Phoenix 1.8 web application with LiveView, real-time PubSub, markdown posts, comments, user authentication, and multi-locale support.

Quick start (development)

cp .env.example .env          # copy and adjust settings
mix setup                     # install deps, create and migrate DB, build assets
mix run priv/repo/seed-posts.exs # (optional) seed markdown posts from data/posts/
mix phx.server                # start the dev server

Visit http://localhost:4000.

Emails sent in development are captured locally and visible at http://localhost:4000/dev/mailbox.

Environment variables

Copy .env.example to .env and adjust the values. The application loads the .env file automatically on startup.

Development

Variable Description Default
ENDPOINT_IP IP address Bandit binds to 127.0.0.1
ENDPOINT_PORT TCP port the server listens on 4000
ENDPOINT_HOST Hostname used in generated URLs (email links) localhost
ENDPOINT_SCHEME URL scheme: http or https http
DBUSER Database username postgres
DBPASSWORD Database password postgres
DBHOST Database hostname localhost
DBPORT Database port 5432
DBNAME Development database name w_app_core_dev
DBNAME_TEST Test database name w_app_core_test
POOL_SIZE_DEV Database connection pool size 10
LOG_LEVEL Logger level (debug, info, warning, …) debug
SECRET_KEY_BASE_DEV Secret key base for dev (preset in .env.example)
AVAILABLE_LOCALES Comma-separated list of supported locales en_US,en_GB,de_DE,de_AT,de_CH
FALLBACK_LOCALE Default locale when none is detected en_US
MAILER_ADAPTER local (mailbox UI) or sendgrid local
SENDGRID_API_KEY Required when MAILER_ADAPTER=sendgrid

Production

See DEPLOY.md for a full list of production environment variables and Docker deployment instructions.

Running tests

mix test

Documentation

Generate API docs with ExDoc:

mix docs

The generated docs are written to doc/. In development the docs are also accessible in the sidebar at /dev/docs.

Deployment

See DEPLOY.

0
2026-03-31 04:05

iBoard - Deploy

Avatar DevOp
#devop #iboard #deploy #docker

Deployment Guide

Overview

The application is packaged as an Elixir release and shipped as a Docker image (iboard/blog:latest). On container start the entrypoint automatically:

  1. Loads /app/.env if present
  2. Creates the PostgreSQL database if it does not yet exist
  3. Runs all pending Elixir migrations
  4. Starts the Phoenix server

No manual migration step is required after deploying a new image.


Quick-start package

A ready-to-edit deployment package is included in the repository:

tar -xzf deploy.tgz -C /your/deploy/dir

Contents:

.env                      # production environment variables — fill in the blanks
docker-compose.yml        # nginx + web + db stack (no extra editing needed)
nginx/conf.d/app.conf     # nginx server blocks — replace "example.com" with your domain
nginx/certs/.gitkeep      # place fullchain.pem and privkey.pem here
data/postgres/            # postgres data volume (created on first start)
data/uploads/             # user-upload volume (created on first start)
README.txt                # five-step quick-start checklist

Minimum steps after extracting:

  1. Edit .env — set ENDPOINT_HOST, SECRET_KEY_BASE, PGPASSWORD, and SENDGRID_API_KEY (or switch to MAILER_ADAPTER=local)
  2. Copy TLS certificates into nginx/certs/
  3. Replace example.com in nginx/conf.d/app.conf with your domain
  4. docker compose pull && docker compose up -d

Environment variables

All configuration is read at runtime from environment variables. There are no compiled-in secrets.

Endpoint

Variable Description Default
ENDPOINT_HOST Required. Public hostname used in generated URLs and email links (e.g. example.com)
ENDPOINT_SCHEME URL scheme: http or https https
ENDPOINT_PORT TCP port Bandit binds to inside the container 4000
ENDPOINT_IP IP Bandit binds to. 0.0.0.0 = all IPv4, :: = all IPv4+IPv6 0.0.0.0
PHX_SERVER Set to true to start the HTTP server (always set by docker-compose.yml)

Note: ENDPOINT_HOST and ENDPOINT_SCHEME are used for URL generation only (email links, redirects). The application always binds on ENDPOINT_PORT regardless of the scheme. In a typical setup nginx terminates TLS on port 443 and reverse-proxies to ENDPOINT_PORT.

Database

Variable Description Example
DATABASE_URL Required. Ecto database URL ecto://user:pass@host/dbname
POOL_SIZE Database connection pool size 10
ECTO_IPV6 Set to true to connect over IPv6 false

Security

Variable Description
SECRET_KEY_BASE Required. 64-byte secret used for cookies and tokens. Generate with mix phx.gen.secret.

Mailer

Variable Description Default
MAILER_ADAPTER local — in-memory, /dev/mailbox UI available; sendgrid — sends real email local
SENDGRID_API_KEY Required when MAILER_ADAPTER=sendgrid

Other

Variable Description Default
DNS_CLUSTER_QUERY DNS query for clustering multiple nodes
LOG_LEVEL Logger level: debug, info, warning, error info

Docker

Prerequisites

  • Docker and Docker Compose installed on the host
  • An .env file in the same directory as docker-compose.yml

Minimal .env for Docker

# Phoenix
SECRET_KEY_BASE=<output of: mix phx.gen.secret>
ENDPOINT_HOST=example.com
ENDPOINT_SCHEME=https
ENDPOINT_PORT=4000

# Port exposed to the host (nginx reverse-proxies to this)
EXPOSE_PORT=4000

# PostgreSQL
PGUSER=blog
PGPASSWORD=<strong password>
PGDATABASE=blog_prod

# Mailer
MAILER_ADAPTER=sendgrid
SENDGRID_API_KEY=SG.<your key>

Start

docker compose up -d

This starts:

  • db — PostgreSQL 16, data stored in ./data/postgres/
  • web — Phoenix application, uploads stored in ./data/uploads/

The database is only reachable inside the Docker network. The web service is exposed on EXPOSE_PORT (default 4000).

Stop / restart

docker compose down        # stop and remove containers (data volumes are preserved)
docker compose restart web # restart only the web service

View logs

docker compose logs -f web
docker compose logs -f db

Building the Docker image

A build.sh script is provided:

./build.sh          # builds iboard/blog:latest
./build.sh --push   # builds and pushes to Docker Hub

The build uses a multi-stage Dockerfile:

  1. Builderhexpm/elixir image; installs npm, compiles assets, builds the Elixir release
  2. Runnerdebian:bookworm-slim; copies only the release artifact

Nginx reverse proxy (example)

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass         http://127.0.0.1:4000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

Backups

Two directories on the host contain all persistent data:

Path Contents
./data/postgres/ PostgreSQL data directory
./data/uploads/ User-uploaded files (avatars, post attachments)

Back up both directories to preserve the full application state.


Releases (without Docker)

To build a release tarball directly:

MIX_ENV=prod mix assets.deploy
MIX_ENV=prod mix release

The tarball is written to _build/prod/rel/w_app_core/. Extract it on the target host and run:

# Set all required environment variables, then:
bin/entrypoint.sh start

The entrypoint handles .env loading, upload directory setup, DB creation, and migrations before starting the server.

Also, see README

0
2026-03-31 04:05

Framework 13" AMD Ryzen Meets Omarchy

Avatar Andi
#omarchy #getoutofit #hardware
Framework Laptop 13
Framework Laptop 13" — The original package, half opened.

There is a unique kind of magic in putting together your own computer. But building a laptop? That takes the experience to a whole new level. I recently got my hands on the DIY Edition of the Framework Laptop 13” powered by an AMD Ryzen processor, and let me tell you: the build process was an absolute blast.

From snapping the modular expansion cards into place to tightening the last captive screw on the chassis, every step felt like a victory. No glue, no proprietary roadblocks—just a beautifully engineered machine that felt truly like my laptop by the time I was done. But hardware is only half the battle. To make this AMD Ryzen beast really sing, I needed the right operating system.

Enter Omarchy.

Why Omarchy?

Omarchy Desktop
Omarchy Desktop — A screenshot of a dark theme on Omarchy

If you haven’t heard of Omarchy yet, you’re missing out. Created by David Heinemeier Hansson (DHH), it’s a brilliant, opinionated Linux distribution based on Arch Linux and the Hyprland tiling window manager. Instead of spending an entire weekend writing config files to make Arch usable, Omarchy gives you a gorgeous, keyboard-driven developer setup right out of the box. Zero bloat, beautiful aesthetics, and lightning-fast performance.

But as with any great Linux adventure, getting it installed required a little bit of a hack.

The “Aha!” Moment: Conquering Secure Boot

BIOS
BIOS — A screenshot of the laptop's BIOS

Omarchy, like many independent Linux distributions, requires you to disable Secure Boot in the BIOS before installation. Simple enough, right? I mashed the F2 key on boot, navigated to the Security tab in the Framework’s BIOS, and found the “Force Secure Boot” toggle.

Except… it was grayed out. Untouchable. Un-toggleable.

I spent a good twenty minutes scratching my head, wondering if I had missed a firmware update or if my glorious new laptop was locking me out. After some deep-dive research, I finally discovered the secret handshake.

If you are going down this same road and find yourself locked out of the Secure Boot settings, here is exactly how you bypass it:

  1. Enter the BIOS: Reboot your Framework and tap F2 to enter the BIOS setup.
  2. Navigate to the Security Tab: Use your arrow keys to slide over to the Security section.
  3. Set a Master/Supervisor Password: This is the magic key! Find the option to set a Supervisor or Master Password. You can make it something simple for now (like 1234), but do not forget it.
  4. Unlock the Toggle: As soon as you set that password and hit enter, the BIOS elevates your privileges. Suddenly, that stubborn “Secure Boot” option is no longer grayed out.
  5. Disable Secure Boot: Toggle it off.
  6. Clear the Password (Optional but recommended): If you don’t want a BIOS password slowing you down every time you tweak your settings, you can now go back and remove it (usually by choosing to change the password, entering your current one, and leaving the “new password” fields blank). Secure Boot will remain disabled!
  7. Save and Exit: Hit F10 to save your changes and reboot.

Booting Into the Future

With Secure Boot out of the way, the Omarchy ISO booted up flawlessly. The installation was incredibly smooth, and within minutes, I was staring at a stunning Hyprland desktop.

The marriage of the Framework 13’s crisp 3:2 display, the raw multi-core power of the AMD Ryzen chip, and the streamlined, keyboard-centric workflow of Omarchy is nothing short of incredible. Super + Space to launch apps, a blazingly fast terminal ready to go, and a system that feels completely tailored to productivity.

If you’re on the fence about picking up a Framework or diving into the world of Arch-based tiling window managers, consider this your sign. Yes, you might have to wrestle with a BIOS password for a hot second, but the reward on the other side? A modular, lightning-fast machine that is 100% yours.

Happy hacking!

1
2026-03-30 19:04

Dockerfile

Avatar Andi
#deploy #docker #phoenix #elixir

How we build our image

# Builder Stage
FROM hexpm/elixir:1.19.5-erlang-28.4-debian-bookworm-20260223-slim AS builder

ENV MIX_ENV=prod

WORKDIR /build

# Install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
    && apt-get clean && rm -f /var/lib/apt/lists/*_*

# Install hex and rebar
RUN mix local.hex --force && mix local.rebar --force

# Install mix dependencies
COPY mix.exs mix.lock ./
COPY config config
COPY README.md README.md
COPY CHANGELOG.md CHANGELOG.md
COPY TODO.md TODO.md
RUN mix deps.get --only $MIX_ENV
RUN mix deps.compile
#RUN mix docs

# Copy application code
COPY priv priv
COPY lib lib
COPY assets assets
COPY doc priv/static/docs

# Deploy assets
# Provide dummy environment variables for config/runtime.exs evaluation during build
ENV DATABASE_URL=ecto://postgres:postgres@localhost/w_app_core_prod
#ENV SECRET_KEY_BASE=dummy_secret_key_base_for_build_only_must_be_at_least_64_bytes_long_so_we_add_some_more_chars_here

# Compile the release
RUN mix compile
RUN mix assets.deploy
RUN mix release

# Runner Stage
FROM debian:bookworm-slim AS runner

ENV MIX_ENV=prod

# Install runtime dependencies including wkhtmltopdf
# wkhtmltopdf fontconfig libjpeg62-turbo libxrender1 xfonts-75dpi xfonts-base \
# pdftk \
RUN apt-get update -y && \
    apt-get install -y libstdc++6 openssl libncurses5 locales \
    && apt-get clean && rm -f /var/lib/apt/lists/*_*

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen

ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

WORKDIR /app

# Copy the built release from the builder stage
COPY --from=builder /build/_build/prod/rel/w_app_core ./
COPY doc priv/static/docs

# Expose default port
EXPOSE 4000

CMD ["sh", "-c", "/app/bin/w_app_core eval WAppCore.Release.migrate && /app/bin/w_app_core start"]
````
0
2026-03-30 13:34

docker-compose example

Avatar Andi
#deploy #docker #elixir #phoenix

docker-compose.yml

That is an example of one of our docker-compose.yml files.

version: '3.3'
services:

  # ── nginx ── TLS termination + reverse proxy ────────────────────────────────
  # See /etc/nginx/sites-available/blog.iboard.cc

  # ── Phoenix application ─────────────────────────────────────────────────────
  web:
    image: iboard/blog:latest
    env_file:
      - .env
    volumes:
      - ./data/uploads:/app/uploads
      - ./data/docs:/app/lib/w_app_core-0.1.0/priv/static/docs
      - ./data/images:/app/lib/w_app_core-0.1.0/priv/static/images
    ports:
      - ${EXPOSE_PORT}:${PORT}
    networks:
      - instance_network
    depends_on:
      - db
    restart: unless-stopped

  # ── PostgreSQL ──────────────────────────────────────────────────────────────
  db:
    image: postgres:16-alpine
    env_file:
      - .env
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    expose:
      - "5432"
    networks:
      - instance_network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${PGUSER}"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

networks:
  instance_network:
    driver: bridge
    ipam:
      config:
        # A /29 subnet provides 8 IP addresses, which is perfectly small for two containers
        - subnet: ${NETWORK_SUBNET}
0
2026-03-30 13:32

e-Matrix Innovations GmbH

Avatar Andi
#ematrix
e-Matrix Innovations GmbH, Wels
e-Matrix Innovations GmbH, Wels — our logo

We deliver complete solutions

Corporate E-Learning

– from Idea to Go-Live

As a full-service e-learning provider, we support you from concept to rollout — with a system, content and expertise.

e-Matrix Innovations GmbH, 4600 Wels, Austria

Instruction System

Manage, organize and document all instructions centrally – with our digital instruction system.

Our digital instruction system allows you to manage all training and instructions in one central location. Automatic reminders, certificates, and comprehensive documentation ensure seamless record-keeping.

Visitor Instruction

Digital solutions for instructing visitors, contractors and suppliers – simple, efficient and legally compliant.

Instruct visitors, contractors and suppliers digitally – before entering your premises or directly on site. Legally compliant documentation of all instructions.

Standardized E-Trainings

Ready-made digital training for workplace safety, IT awareness, compliance and corporate training – ready to use and legally compliant.

Our standardized e-trainings cover a wide range of topics and are ready to use immediately. All modules meet legal requirements and are available in multiple languages.

Topics

  • Workplace Safety
  • Compliance
  • Cyber Security Awareness Trainings (Fit4)
1
2026-03-30 11:31

Elixir Conf 2018, Belveue, Seattle

Avatar Andi
#conference #elixir #usa
Josè Valim and Andreas Altendorfer
Josè Valim and Andreas Altendorfer — At the Elixir Conf US 2018

A great conference where I met a lot of old friends.

0
2026-03-30 11:07

Framework Laptop 13¨

Avatar Andi
#bigtech #getoutofit #hardware
Framework 13
Framework 13" Laptop — Closed lid of a new Laptop

My new Framework Laptop. It comes in parts and is fun to assemble it all on myself. It works great with Omarchy once the pieces are stuck together.

Delivered in Parts

Framework 13
Framework 13" Laptop — Some electronics

But mine

Framework 13
Framework 13" Laptop — Some electronics

Not theirs

Framework 13
Framework 13" Laptop — Comes in parts

😄

Framework 13
Framework 13" Laptop — Works great with Omarchy Linux
2
2026-03-30 11:07

Review of the Remarkable Paper Pro

Avatar Andi
#review #hardware
ReMarkable Paper Pro
ReMarkable Paper Pro — A picture of the ReMarkable Paper Pro e-Ink device with a kind of UML-drawing on it.

I’ve been using the Remarkable since 2021, and it has become an indispensable part of my daily routine. As someone who loves the feel of writing on paper but needs the convenience of digital notes, the Remarkable has been a game-changer. Now I received the Paper Pro.

The Writing Experience

The first thing that struck me about the Remarkable is how natural it feels to write on. The textured surface of the screen and the pressure-sensitive stylus create an experience that is remarkably close to writing on paper. There’s no lag, and the “ink” flows smoothly from the stylus. It’s a joy to use for everything from jotting down quick notes to long-form writing.

My Daily Organizer

I use my Remarkable with the “My Daily Organizer” template, and it has completely transformed my productivity. The template provides a structured way to plan my day, set goals, and track my progress. Having all my notes, to-do lists, and calendar in one place, with the ability to search and organize them, is incredibly powerful.

There is a YouTube channel, named My Deep Guide, where the author, Vojislav Dimitrijevic, talks about all kind of e-ink devices and analyzes them. It was his channel, leading me to the ReMarkable.

A Distraction-Free Zone

In a world full of notifications and distractions, the Remarkable is a breath of fresh air. It’s a dedicated device for writing and reading, with no browser, no email, and no social media. This focus on a single task has had a significant impact on my ability to concentrate and get things done.

Final Thoughts

After more than four years of daily use, I can confidently say that the Remarkable Paper Pro is one of the best investments I’ve made in my productivity. It’s a beautifully designed device that delivers on its promise of a paper-like digital writing experience. If you’re looking for a way to bridge the gap between the analog and digital worlds, I highly recommend giving the Remarkable a try.

0
2026-03-30 11:07

Omarchy on a MacBook Pro from 2017

Avatar Andi
#review #getoutofit #omarchy #archlinux #os

My Omarchy Experience on a 2017 MacBook Pro

MacBookPro 2017
MacBookPro 2017 — A MacBookPro cover with a lot of stickers.

It’s not every day that a new operating system truly impresses me, especially when running on older hardware. However, my recent experience with Omarchy on my trusty 2017 MacBook Pro has been overwhelmingly positive. This setup has, hands down, provided the best development environment I’ve encountered to date.

For years, this particular MacBook Pro has been a workhorse. While it’s still a capable machine, newer macOS versions have sometimes felt a bit sluggish, and the overall experience wasn’t as snappy as it once was. Enter Omarchy. From the moment I installed it, the system felt revitalized. The interface is clean, intuitive, and remarkably responsive, breathing new life into the hardware.

The Good: A Superior Development Setup

What truly sets Omarchy apart for me is its out-of-the-box readiness for software development, particularly for my Elixir and Phoenix projects. The underlying architecture seems incredibly well-optimized, and I’ve found that all my development tools and dependencies integrated seamlessly. Compiling Elixir code, running Phoenix servers, and managing dependencies feel incredibly fast and efficient. The responsiveness of the terminal, the smooth operation of my IDE, and the overall lack of friction in my daily workflow are truly remarkable. It genuinely feels like Omarchy was designed with developers in mind, offering a stable and powerful foundation for crafting applications.

The Not-So-Good: Camera and Audio Workarounds

No system is perfect, and my experience with Omarchy did hit one minor snag: the built-in camera and audio on my 2017 MacBook Pro are not recognized or functional. While this is a slight inconvenience, it’s easily remedied. I’ve opted to use external USB devices for both my camera and microphone, which actually provide better quality anyway. It’s a small workaround for an otherwise exceptional operating system.

The Future: Dedicated Elixir and Phoenix Development

Moving forward, this 2017 MacBook Pro, powered by Omarchy, will be my dedicated machine for all Elixir and Phoenix development. The performance gains and the sheer joy of working in such a streamlined environment have convinced me that this is the optimal setup. For anyone looking to breathe new life into older Apple hardware and create a top-tier development workstation, especially for Elixir and Phoenix, I wholeheartedly recommend giving Omarchy a try. It truly is the best setup for developing I’ve had so far.

1
2026-03-30 11:07

The Big Move

Avatar Andi
#bigtech #getoutofit

About my move from Google to kSuite

The kSuite Desktop
The kSuite Desktop — A bad screen capture of the kSuite web app.

Moving away from the dominant Big Tech ecosystem often feels like a daunting task—one that usually involves a complex weekend of “digital surgery.” However, I recently made the switch to kSuite the Swiss-based collaborative solution from Infomaniak, and the experience was surprisingly smooth.

If you’re looking for a digital home that values privacy, independence, and cost-effectiveness without the “Silicon Valley” strings attached, here is why kSuite should be on your radar.


🚀 The “Sunday Afternoon” Migration

One of the biggest hurdles to leaving Google or Microsoft is the sheer volume of data: domains, years of emails, and gigabytes of documents.

I set aside a Sunday afternoon for the move, and to my surprise, that was all it took. Infomaniak provides intuitive import tools that handle the heavy lifting. I was able to:

  • Transfer my domain with minimal downtime.
  • Sync my entire email history via their IMAP migration tool.
  • Move my documents over to kDrive (their cloud storage) seamlessly.

By the time the sun went down, my old accounts were empty, and my new Swiss-hosted digital workspace was ready to go.

🛠️ Performance “In Production”

I’ve now been using kSuite for a few days in my daily workflow, and the “honeymoon phase” isn’t wearing off. Here’s the breakdown:

  • Reliability: Everything works exactly as expected. Mail delivery is instant, and sync is snappy.
  • The “Better” Factor: Some features actually outperform the giants. The kDrive interface is remarkably clean, and the integration of OnlyOffice means I can edit Word, Excel, and PowerPoint files directly in the browser without the bloat of Microsoft 365.
  • Privacy by Design: Knowing my data is hosted in Switzerland—under some of the world’s strictest privacy laws—provides a peace of mind that’s hard to quantify until you actually make the move.

💰 The Bottom Line: Costs & Philosophy

What truly sets kSuite apart isn’t just the tech, but the business model.

Infomaniak is independent and employee-owned. They aren’t beholden to shareholders demanding data-mining for ad revenue. Their pricing is refreshing:

  • Transparent: No hidden “introductory” rates that double after a year.
  • Competitive: For many users, the Standard tier is essentially free (including your own domain mail), and the paid tiers offer massive storage (up to 6 TB) for a fraction of what “Big Tech” charges for similar enterprise features.

Final Thoughts

Switching to a sovereign, ethical cloud doesn’t have to be a sacrifice. After 48 hours in production, I haven’t missed a single feature from my old providers. In fact, the speed and simplicity of the Swiss approach have made my workflow feel lighter.

0
2026-03-30 11:07

Docker Deployment

Avatar DevOp
#devop #deploy

The Story of “Example Server”: A Humble DevOps Journey

We’ve all been there. You spin up a quick virtual machine to test a simple proof-of-concept. You name it something incredibly generic, like example-server. You manually install a few packages, tweak a config file, and your app is live.

It was only supposed to be an experiment. It was only supposed to live for an afternoon.

But as things usually go in software, the temporary became permanent. Fast forward a bit, and suddenly this little example-server had grown into something I actually had to maintain, update, and care for. It evolved from a quick sandbox into a real learning experience that forced me to grapple with the realities of deployment and infrastructure.


Why Am I Writing This?

I’m not here to write a definitive “How-To” guide or preach about the absolutely perfect, undisputed way to build a deployment pipeline. There are plenty of textbooks and official docs for that.

Instead, I’m starting this series simply to report on my own journey with this server. Over the next few posts, I want to document what I actually did, the mistakes I made, the weird edge cases I ran into, and the incremental improvements I figured out along the way.

Here is a taste of what I’ll be sharing from my notes:

  • The “Gotchas”: The manual configurations I forgot about that inevitably broke things later.
  • The Upgrades: How I slowly transitioned from “SSH and pray” to slightly more sane deployment practices.
  • The Lightbulb Moments: The specific tools and concepts that finally made sense once I applied them to a real, messy environment.

Hoping It Helps

My main goal is just to get these experiences out of my head and onto the page. But my sincere hope is that by sharing my completely unpolished journey, there might be something useful in here for you. Maybe you’ll find a solution to a problem you’re currently stuck on, avoid a pothole I tripped over, or at the very least, feel a little less alone in the wild world of server management.

Stay tuned for the first real chapter of the example-server saga!

0
2026-03-31 06:59