Latest Posts

System
Thursday, April 2, 2026, 18:52
public users

iBoard - ABOUT

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
Avatar
Andi
Wednesday, July 8, 2026, 16:52
public users

Introducing Groups: Share with exactly the people you choose

Until now, a post here could be public, private, or sent as a direct message. That covered the extremes — everyone, or just one person — but not the middle ground most of us actually live in: this handful of people, and no one else.

Groups fill that gap.

Create a group in seconds

Head to My Groups in the sidebar (or /groups) and hit New group. Give it a name, and start adding people:

  • Friends are added instantly — they’re active right away.
  • Anyone else gets an email invitation. Once they confirm, they join the group and become a mutual friend, so the connection works both ways.

Posts for members only

When you write a post, visibility now has a Specific Groups option. Pick which groups may read it — and, separately, which of those may comment. Only active members of a listed group can see or reply.

Every group-restricted post carries a “Who can read this” section, so it’s always clear exactly who’s in the room. No guessing, no accidental oversharing.

It lands in the inbox

Published group posts show up in each member’s inbox (/dm) right alongside direct messages, complete with a Group badge and per-person read/unread tracking — the same unread counter you already know from the navbar. Nobody misses what’s meant for them.

A home for every group

Each group has its own page (/groups/:id) listing its members and how many posts each has published. Any active member can invite new people; you can remove anyone you added and leave whenever you like; and the owner can manage everyone.

Groups are yours to shape — start one today and share with just the right circle.

Avatar
Andi
Tuesday, July 7, 2026, 15:57
public users

An Observation on AI-Generated Documentation

With the rise of modern AI tools, the concept of generating complete, gapless documentation for an entire codebase seems tempting at first glance. It appears to be the ultimate solution: every function, variable, and logic branch automatically explained. However, upon closer inspection, this approach reveals significant downsides.

No seasoned developer would voluntarily document every single detail—and for good reason. If every line of code were commented, the famous mantra “Read the fucking code” (RTFC) would lose its validity. Yet, RTFC remains entirely justified, especially when dealing with low-level details. Often, the code itself is the most precise description of what is happening at the machine level.

Documentation intended for users—whether other developers or DevOps engineers—should not attempt to include everything. Such “completeness” dilutes the critical information. Readers are forced to wade through a mountain of trivial details to find the actual architectural decisions or usage patterns. This is frustrating, time-consuming, and ultimately leads to the documentation being ignored because the signal gets lost in the noise. Good documentation curates knowledge; it does not merely duplicate it.

Avatar
Andi
Monday, June 29, 2026, 19:28
public users

The End of Small Open Source Projects?

1782761135607.jpg
1782761135607.jpg

Small open-source projects, often sustained by only a handful of contributors, are facing a critical turning point. Historically, these initiatives thrived on the necessity of collaboration and code sharing. However, Artificial Intelligence is fundamentally altering this dynamic. Developers can now generate complex features, bug fixes, and even entire modules using AI assistants alone, removing the dependency on external help or peer reviews.

Yet, this surge in efficiency carries a paradoxical risk: the motivation to share work publicly is diminishing. If every developer can complete their “private closed work” autonomously without relying on the community, the ecosystem risks fragmentation. Instead of refining a shared open solution together, we may see the rise of isolated, AI-generated silos. The thesis is not that open source will vanish, but that the foundation of small, purely community-driven projects is eroding because the barrier to autonomous development is lowering while the incentive for openness fades.

Avatar
DevOp
Saturday, June 27, 2026, 08:57
public users

Deployment Files

The Docker-Compose File (run)

The following file docker-compose.yml is used to run a docker-container with an image created in Dockerfile.

The dockerfile builds the phoenix-release of iBoard blog.

The docker-compose file packs a stack with two services.

  • web (The Phoenix application)
  • db (A Postgres database)

docker-compose.yml

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: ${PGUSER:-blog}
      POSTGRES_PASSWORD: ${PGPASSWORD:?Set PGPASSWORD in .env}
      POSTGRES_DB: ${PGDATABASE:-blog_prod}
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    expose:
      - "5432"
    networks:
      - backend
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${PGUSER:-blog}"]
      interval: 10s
      timeout: 5s
      retries: 5

  web:
    image: iboard/blog:latest
    env_file:
      - path: ./.env
        required: false
    environment:
      PHX_SERVER: "true"
      # Endpoint
      ENDPOINT_HOST: ${ENDPOINT_HOST:?Set ENDPOINT_HOST in .env}
      ENDPOINT_SCHEME: ${ENDPOINT_SCHEME:-https}
      ENDPOINT_PORT: ${ENDPOINT_PORT:-4000}
      ENDPOINT_IP: ${ENDPOINT_IP:-0.0.0.0}
      # Database — connects to the db service on the internal network
      DATABASE_URL: "ecto://${PGUSER:-blog}:${PGPASSWORD}@db/${PGDATABASE:-blog_prod}"
      POOL_SIZE: ${POOL_SIZE:-10}
      # Security
      SECRET_KEY_BASE: ${SECRET_KEY_BASE:?Set SECRET_KEY_BASE in .env}
      # Mailer
      MAILER_ADAPTER: ${MAILER_ADAPTER:-sendgrid}
      SENDGRID_API_KEY: ${SENDGRID_API_KEY:-}
      # Logging
      LOG_LEVEL: ${LOG_LEVEL:-info}
      # Clustering (optional)
      DNS_CLUSTER_QUERY: ${DNS_CLUSTER_QUERY:-}
    ports:
      # Host port EXPOSE_PORT → container port ENDPOINT_PORT.
      # Put an nginx reverse proxy in front to terminate TLS on 443.
      - "${EXPOSE_PORT:-4000}:${ENDPOINT_PORT:-4000}"
    volumes:
      - ./data/uploads:/app/uploads
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend
    restart: unless-stopped

networks:
  backend:
    driver: bridge

Dockerfile

The following dockerfile builds an image from a slim Debian, packed with Erlang and Elixir.

It uses mix to build a release and a docker 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

# Copy application code
COPY priv priv
COPY lib lib
COPY assets assets
# run mix doesn't compile - FIXME: find another way to deploy docs
# RUN mix docs
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"]