iBoard.cc
The Programming Kitchen (a dev only blog)
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
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
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.
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.
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.
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"]
Introducing the Next Generation of Our Blog: Public Reading, Real-Time Analytics, and Administrative Mastery
We’ve been busy over the last few weeks! Today, we are thrilled to share a massive set of updates that drastically improve how you read, moderate, manage, and monitor the blog. Whether you are a casual visitor, an active author, or a site administrator, there is something major in this release for you.
Here is a deep dive into the highlights of the latest changes.
1. Public Reading Mode: No Login Required! 📖
The biggest architectural shift in this release is that the blog is now public-facing.
Previously, visitors had to log in just to browse posts. We have opened our doors: anyone can now read posts, explore the news feed, learn about authors, and filter by tags at /posts, /news, /authors, and /tags without needing an account.
To keep our community safe and high-quality:
- Writing and Editing: Creating new posts, editing, liking, and pinning still strictly require being logged in.
- Anonymous Safety: The comment form is hidden for anonymous viewers, and likes are displayed as a sleek, read-only heart badge.
- User & Author Contexts: Public pages hide draft posts and restricted visibility posts (e.g., “friends-only” or “users-only”) dynamically, depending on whether the visitor is logged in and authorized.
2. Real-Time Session Analytics & Interactive SVG Charts 📊
For administrators, we’ve built a powerhouse of an analytics suite at /admin/session-log/stats powered by Phoenix PubSub and live telemetry.
- Live Summary Metrics: Track Total, User, Guest, and Active Country counts in real time as traffic hits the server.
- Interactive SVG Donut/Pie Chart: Hover over the “Top Countries” card to interact with custom SVG segments showing percentage shares and country legends.
- Interactive SVG Bar Charts: Watch active session distributions by day and hourly peak activity update live before your eyes without a page reload.
- Flags Box Modal: Click any item in the trimmed country flags box to pop open a scrollable, detailed modal listing all active country session counts.
- Auto-Archiving: A background worker now automatically archives session logs older than a configurable threshold (defaulting to 24 hours) to keep the database lean and performant.
3. Advanced Runtime Configuration UI ⚙️
No more editing files on the server or manually redeploying just to tweak a setting!
We introduced WAppCore.RuntimeConfiguration, a smart memory cache that sits in front of your environment variables and .env file. We then built a control center at /admin/settings where administrators can:
- Group and Filter Settings: Quickly search through settings. Compile-time constants and sensitive credentials (which are safely masked) are grouped by their root domains (DB, MAIL, etc.).
-
On-the-Fly Editing: Tweak keys like
WELCOME_MESSAGEorBROWSER_TITLEand hit Save to atomically rewrite the.envfile with clean formatting. -
Zero-Downtime Reloads & Restarts: Reload the on-disk
.envfile into memory instantly, or trigger an application restart (:init.restart/0) right from the web page. Sessions survive perfectly since they are backed by cookie-based signing!
4. Approval-Based Registration & Anti-Spam Blacklists 🛡️
To support a private or curated community, we have redesigned the onboarding experience from the ground up:
- Moderated Application Queue: Self-registration can now be disabled or set to require moderator approval. Visitors must supply their email and write a mandatory multiline reason (which must be at least 3 words long to block single-word “test” or spam submissions).
- Silent Rejections and Deletions: Reviewers can accept applications (which automatically triggers an invitation link), reject them with a custom explanatory message, or reject silently to prevent notifying spammers. Complete deletion of spam entries is also just a click away.
- Domain Blacklist: Administrators can manage regular expressions to block specific domains (like temporary email services) from even submitting an account request.
-
Toggle Gated Flows: Turn self-registration or account requests on or off with native daisyUI toggles in
/admin/settings.
5. Modern Mobile & Desktop Layout Overhaul 📱
The user interface has received a top-tier polish focusing on responsiveness and smooth micro-interactions.
- Top Bar & Sidebar Improvements: On phones, settings, timezone selectors, and theme options elegantly fold into a “Preferences” section at the bottom of the sidebar drawer. Tapping any navigation link automatically slides the drawer shut so you can read immediately.
- Active Sidebar Link Auto-Centering: A live JS hook automatically scrolls your active navigation link into vertical center alignment when the page loads.
- Sticky Table Headers: When scrolling through massive lists of users or posts, the column headers stick to the top of the viewport just below the sticky navigation bar, adjusting their heights dynamically on small viewports.
-
Draggable & Resizable Table Columns: Drag column headers horizontally to resize columns. Your choices are saved in browser
localStorageand persist across page loads and LiveView patches. - Image Preview Fullscreen: Clicking the enlarge icon in the image preview lightbox now correctly triggers true browser fullscreen mode inside the active modal.
6. Bilingual Post Emails & Custom Assets 📧
Notification emails for new posts, comments, and direct messages have been rewritten for a world-class reading experience:
- Dual-Language Formatting: Post emails are sent in both English and German. If a post has no translation, it elegantly prints the content once without duplicate headers.
- Inline Embedded Images: Images attached to posts are embedded inline directly in your HTML mail body—no download link clicks required.
- Password Show/Hide: Input elements on forms now feature a native password show/hide eye-icon.
- Datalist Dropdowns: Replaced standard browser autocomplete fields with custom, high-fidelity select menus that handle multi-selection (for tags) and arrow-key navigation.
7. Major Engine Upgrades 🚀
Under the hood, we upgraded the core environment to run on Erlang/OTP 29, Elixir 1.20, Phoenix 1.8.8, and Phoenix LiveView 1.2.3.
-
Enjoy blazing-fast performance, improved compilation times, robust type safety, and optimized Docker build layers (thanks to our streamlined
.dockerignorefilters). -
Fully localized support is now active for 6 distinct locales, including formal German (Sie) (
de_DE), informal German (Du) (de_AT), Standard English (en), British English (en_GB), and a complete dialect translation in Züritüütsch (Swiss German) (de_CH).
What’s next?
These quality-of-life and performance upgrades set a rock-solid foundation for future features. Explore the public pages, customize your preferences in the sidebar, and let us know what you think of the new real-time admin charts!
Happy reading!
In seinem Werk „Der Fürst und seine Erben“ wagt Peter Sloterdijk einen intellektuellen Spagat zwischen historischer Analyse und zeitgenössischer Diagnose. Der Titel evoziert bewusst Niccolò Machiavellis klassischen „Fürsten“, doch Sloterdijk erweitert den Blickwinkel: Es geht nicht nur um die Kunst der Herrschaft, sondern um das Schicksal der Macht in einer Epoche, die traditionelle Autoritäten hinterfragt.
Sloterdijk untersucht, wie sich die Figuren der Führung und die Mechanismen der Einflussnahme gewandelt haben. Wer sind die „Erben“ in einer modernen, oft führungslos wirkenden Gesellschaft? Sind es die Technokraten, die Medienmacher oder vielleicht die Algorithmen selbst? Mit seiner charakteristischen sprachlichen Präzision und einem scharfen analytischen Blick dekonstruiert der Philosoph die Illusionen der politischen Repräsentation und zeigt auf, wo die wahren Machtzentren heute liegen.
Dieses Buch ist keine einfache Gebrauchsanweisung für Führungskräfte, sondern eine tiefgründige Reflexion über die Verantwortung und die Unausweichlichkeit von Elitenbildung – ein Thema, das in aktuellen Debatten oft tabuisiert wird. Sloterdijk zwingt den Leser, unbequeme Fragen zur Struktur unserer Gesellschaft zu stellen. Für alle, die verstehen wollen, warum alte Machtmodelle kriseln und welche neuen Formen der „Fürstlichkeit“ im 21. Jahrhundert entstehen, ist diese Lektüre unverzichtbar. Ein anspruchsvolles, aber höchst gewinnbringendes Werk für den wachen Geist.
More posts
Browse all posts you can see.
Join the Community (44 posts)
Create an account today to start writing your own posts and join 2 authors.
Authors
Discover 2 authors and their 44 postings. Login to join them.
Tags
Explore topics and find content by tags.
Local Mailbox
Preview sent emails in the development environment.
Documentation
Browse the project's API documentation.