Changelog
All notable changes to APBoard are documented in this file.
Format based on Keep a Changelog, versioning follows Semantic Versioning.
[3.0.1-rc.2] - 2026-06-29
Added
- apbcli: Full interactive setup wizard
- apbcli: CLI tool for board administration (user/package/db/config/forum/system management)
- Docker:
APBOARD_FIRST_ADMIN_NAMEenv var to set admin display name on first start - Install ping to count active installations (weekly, anonymous, HMAC-signed)
Changed
- Docker entrypoint: Admin user initialization now performed by
php apbcli install:admininstead of the removedsetup/docker-init.php
Fixed
- Web installer: PHP version check corrected from 8.0 to 8.5
- Web installer: added missing
intlandzipextension checks - Docs: corrected Docker setup step 7 to reference
apbcli install:admin
Removed
setup/docker-init.php: Admin init logic fully replaced byapbcli install:admin- Profile visibility privacy setting: Users can now restrict their profile page, pinboard, and activity feed to logged-in members only
- APBoard Package System
- Plugin unit tests: Options, Permissions, Language, Assets, Cron, Migrations
- Developer documentation under
docs/packages/
Changed
- Profile area (all 5 stylesets): Removed left sidebar; replaced with a full-width card featuring a horizontal scrollable tab navigation.
- Moderator area (all 5 stylesets): Removed left sidebar; replaced with a full-width card featuring a horizontal tab navigation
- Admin area (all 5 stylesets): Replaced flat link list with a grouped, icon-based sticky sidebar .
- Dark-mode overrides (sets 4 & 5): Removed stale sidebar gradient and link-colour rules for profile/admin/mod sidebars.
- Admin sidebar reduced from 310 px to 220 px to give more room to the content area.
Fixed
- Package language importer now skips language files whose DB table does not exist (language not installed on this instance)
- Plugin JS assets now render correctly.
[3.0.1-rc.1] - 2026-06-27
Added
- Browser and app push notifications
- User ignore and follow controls
- Moderator-only user notes on the moderation user detail page
- Accepted-answer marking for solved support topics
Fixed
- Push settings in all stylesets
- Push migration with stale vendor files
- Message inbox and trash count queries missing a bind parameter
[3.0.0] - 2026-06-26
Changed
- Version bump from 3.0.0-rc.2 to 3.0.0
Fixed
- Docker Hub CI login uses --password-stdin (non-TTY fix)
- CI dind TLS/port mismatch; add QEMU for multi-platform builds
- Missing navigation_link_* translations for online list (forgot, 2fa, banned etc.)
[3.0.0-rc.2] - 2026-06-26
Added
- Password strength meter (real-time, client-side) on registration and profile password-change pages
- Production Docker image for Docker Hub distribution
- CI pipeline publishes multi-platform image on release tags
docker-compose.hub.ymlfor Docker Hub installations
Changed
- Password policy enforced: 8–100 chars, upper+lower, digit, special character
- Rewrote LAMP and Docker installation guides
Fixed
resources/klaromissing from release ZIP- Klaro symlink missing from web installer and LAMP docs
[3.0.0-rc.2] - 2026-06-25
Security
- Fix SSRF in ActivityPub: central
apb_AP_ValidateOutboundUrl()resolves DNS and blocks all private/reserved IP ranges (RFC1918, loopback, link-local, ULA, metadata) before every outbound cURL call - Fix APB-SEC-004: defederation policy now applies to inbox URI, shared-inbox URI, and avatar URL host - not just the actor domain
- Fix APB-SEC-002: shared inbox
/ap/inboxenforces 64 KB payload limit via Content-Length and actual body length before parsing JSON - Fix APB-SEC-005: setup wizard supports
APB_SETUP_TOKENenv var to gate access - Fix APB-SEC-006: profile homepage validates scheme (http/https only); javascript:/data: URIs are rejected
- Fix FINDING-01: remove
htmlspecialchars()on password beforepassword_verify()- raw input required for correct bcrypt verification - Fix FINDING-02: escape LIKE metacharacters (
%,_) in search queries to prevent wildcard injection - Fix APB-SEC-007: rate-limit autocomplete endpoints (
search_users,search_topics) - 60 req/60 s per IP; newapb_search_attemptstable - Fix FINDING-06:
data-hrefclick handler enforces same-origin navigation in all three stylesets; external URLs are silently ignored - Add
@deprecatedannotations and security warnings to legacy raw-query methods indb_mysql.php - Document non-image upload MIME+extension-only protection and admin raw-HTML field security implications
Fixed
- Avatar-cache migration: add missing
apb_AP_Config.phpinclude for fresh installs
[3.0.0-rc.1] - 2026-06-25
Security
- Nonce-basierte Content Security Policy - kein unsafe-inline mehr für Scripts
- Alle Inline-Event-Handler durch CSP-sichere data-Attribute ersetzt
[3.0.0-beta.6] - 2026-06-25
Fixed
- GDPR export: all ZIP content now fully translated, no hardcoded German
- GDPR export: ZIP filename changed to
apboard-gdpr-*.zip - GDPR export: ZIP files renamed to English (access-notice.md, profile.md, etc.)
- GDPR export: stat labels in template now use translation system
- GDPR export: revoked warning check uses correct
revokedflag
[3.0.0-beta.5] - 2026-06-25
Added
- User Ranks: 13 Stufen basierend auf Post-Anzahl
- Rank-Badge + Post-Count in Reply-Sidebar und Nutzerprofil
- Admin: User-Ranks CRUD unter /admin/ranks/
- Admin Settings: Ränge global aktivierbar/deaktivierbar
- Honeypot-Feld bei Registrierung gegen Bots
- Disposable-E-Mail-Blockliste (~400 bekannte Wegwerfanbieter)
- DSGVO-Datenexport: ZIP mit Profil, Beiträgen, PMs, Pinboard (Art. 15 & 20)
[3.0.0-beta.4] - 2026-06-25 (continued)
Changed
- Mobile: Boardinfos und letzter Beitrag jetzt sichtbar
- Mobile: Topic-Titel wird abgekürzt
- Mobile: Schriftgröße in „Last Topics" angepasst
- Mobile: Topic-Stats und letzter Reply jetzt sichtbar
- Mobile: Abstand und Icon-Ausrichtung in Topics verbessert
- Mobile: Reaction-Picker Position korrigiert
- Profil-Infos in Replies kompakter und moderner gestaltet
- Mobile: Profil-Header als Flexbox mit Meta-Chips
- Homepage-URL jetzt sichtbar (nicht nur Icon)
- Back-to-top Button modernisiert: rund, FA-Icon, Hover-Animation
Added
- Cookie-Banner via Klaro (lokal, keine externen Requests)
- ToS-Seite: neue Legal-Page, im Admin konfigurierbar
- Inline-Bulk-Moderation: Checkbox-Mehrfachauswahl im Mod-Panel
- Topics: Bulk-Delete, Bulk-Pin/Unpin, Bulk-Lock/Unlock
- Posts: Bulk-Delete (erste Posts und einzige Posts werden übersprungen)
- Bulk-Toolbar erscheint dynamisch beim ersten Tick, verschwindet wieder
- Select-All-Checkbox mit Indeterminate-State im Tabellenkopf
[3.0.0-beta.4] - 2026-06-24
Added
- Emoji reactions: the single "Like" feature has been completely replaced by a full six-emoji reaction system
- Warning system: a structured moderation tool
- Two-Factor Authentication (TOTP/RFC 6238)
- Thread Move: moderators can move a topic and all its replies to any other board
- Thread Merge: moderators can merge a secondary topic into a primary topic
- Thread Split: moderators can extract selected replies from a topic into a new topic
Fixed
- Reaction notifications
- the "Back to user" link was rendered unconditionally
- the submit-button confirm dialog
- warnings overview query
- 2FA challenge page
- Warning system
- Ban enforcement: banned users were not stopped at login
- Mute enforcement: muted users could still send private messages, edit their profile bio/infotext/signature, and post to their pinboard
Build
- PHPStan memory limit in CI raised from 256 M to 512 M
[3.0.0-beta.3] - 2026-06-24
Added
- Word filter system
- @Mention system
- New topic form layout unified with all other content pages
- Poll system
- Logout link added to the bottom of the profile sidebar
- Logout icon added to the right of the welcome string in the subheader bar
- New public statistics page
- The username in the subheader welcome string ("Welcome Christin!") is now a link to the user's own public profile
- Moderators and admins now see a red badge with the count of unresolved reports on the "Moderator" top-navigation link and on the "Reports" entry in the mod-area sidebar;
Fixed
- Reporting a post showed a JavaScript error popup
- Mod area post edit no longer silently discards edit-tracking metadata
- Broadcast detail page now renders with the same styled card layout as the About/Legal pages
- Admin and moderator post/topic listings now show the Fediverse handle (
@user@domain) for ActivityPub-sourced content - Broadcast detail page now shows author name and publication date below the title
- Collation mismatch caused 500 errors on mod dashboard, mod/admin posts and mod/admin topics
- Public user profile now displays the username in white with a subtle text-shadow
- "Last activity here:" on user profiles and the Profile Preview was always empty
- Profile sidebar navigation now highlights the currently active page
- Statistics page showed incorrect post count
Build
- minified Chart.js build was causing CI to fail with a "file appears to be minified" warning (exit code 1)
[3.0.0-beta.3] - 2026-06-23
Added
- Profile Preview page shows the logged-in user's own profile exactly as other members see it, including all privacy filters applied
- "Profile Preview" link added at the top of the profile sidebar navigation across all three stylesets
Changed
- Navigation: "Usermenu" renamed to "Profile" - links directly to
/profile/preview/, no dropdown submenu - Navigation: "Admin" links directly to
/admin/dashboard, no dropdown submenu - Navigation: "Moderator" links directly to
/mod/dashboard, no dropdown submenu - Only the "Info" nav entry retains its dropdown submenu
[3.0.0-beta.2] - 2026-06-22 (continued)
Added
- Forgot-password feature at
/forgot/: users enter their email address and receive a time-limited reset link (30 minutes); the response is always identical regardless of whether the address is registered, preventing account enumeration - Rate limiting for the
/forgot/endpoint: max 3 requests per IP per 15 minutes - HTML email templates for account activation and password reset; both use inline-styled table-based layouts compatible with all common email clients
email_template_forgot_password_bodyandemail_template_forgot_password_subjecttranslation keys
Changed
- Login, registration, and password-reset forms redesigned: dark header band with logo (using the styleset's
--apb-darkcolor), merged input group styling, accent-colored submit button, and cross-navigation links (forgot password, register, back to sign in) - Message/confirmation box redesigned: accent-colored header for success, red header for error, SVG status icon, outlined back button; removed inline
<style>hack and<p> </p>spacers - "Forgot your password?" link on the login form now points to
/forgot/instead of/password/ - All outbound emails are now sent as HTML with a plain-text fallback; registration confirmation email updated to match the new styled layout
apb_password_resetstokens now carry atypefield (registrationvsreset) so the activation endpoint can apply the correct account-update logic for each flow
Fixed
- Cross-navigation links on login form: "Forgot your password?" and "No account yet? Register"
- Cross-navigation links on register form: "Already have an account? Sign in"
- Back-to-login link on password-reset form
[3.0.0-beta.2] - 2026-06-22
Added
- Broadcast-Nachrichten: Admins können Board-weite Hinweisbanner erstellen, aktivieren und verwalten; Besucher sehen eine Broadcast-Bar mit Link zur Detailseite
X-Robots-Tag: index, follow, archivewird gesendet wenn Suchmaschinen-Indexierung aktiv ist
Changed
- robots.txt wird dynamisch generiert und funktioniert auf jedem Webserver ohne zusätzliche Konfiguration
- Sitemap-Generator komplett neu gebaut: datenbankbasiert, kein HTTP-Crawling mehr, skaliert ohne Limits, alle öffentlichen Seiten korrekt abgedeckt
- Sitemap ist an die Suchmaschinen-Indexierungs-Einstellung gekoppelt: wird beim Deaktivieren sofort gelöscht, beim Aktivieren neu generiert
Fixed
<h1>-Überschrift auf Broadcast-Detailseite (war fälschlicherweise<h2>)
3.0.0-alpha.3 - 2026-06-07 (continued fixes)
Added
User-editable posts
- Regular users can edit their own posts within a 30-minute window; admins and moderators can edit any post at any time
- Edit opens a TinyMCE modal (lazy-initialized on first use)
- Subject is editable when editing the first post of a topic
- Edit history shown in reply footer: editor name, edit count, and timestamp of last edit
- New AJAX handlers:
get_post_for_edit,save_edit_post - New database columns on
apb_replies:edit_count,last_edited_at,last_edited_by
Forum statistics box
- Full-width stats bar displayed below the category grid on the homepage
- Shows: registered user count, users online (last 30 min), topic count, reply count, board count, newest member
- Configurable via Admin → General Settings (
apb_show_stats)
Subheader welcome message
- Breadcrumb bar is now two-column: breadcrumbs on the left, "Welcome [username]!" on the right (logged-in users only)
- Multilingual via
apb_welcome_stringtranslation key
Changed
- Reply footer redesigned: renamed
.reply-meta→.reply-footer; likes and action buttons are now right-aligned (justify-content: flex-end); minimum height 33 px .reply-contentusesflex-direction: columnso the footer is always pinned to the bottom of the card regardless of content length#contentbackground removed; individual board, topic, and reply list items now carry explicit white backgrounds, letting the page background show through between cards- Topic header redesigned: white card with border and box-shadow, flexbox layout with mod buttons and subscribe button aligned in a single row
- Footer info text replaced with a short, factual description of APBoard
Fixed
- TinyMCE edit modal was visible on page load due to missing
display:noneon the modal container - Edit info showed the post author instead of the actual editor
- Edit info rendered raw
<strong>Today</strong>HTML instead of plain text; fixed withstrip_tags() - TinyMCE sub-dialogs (emoji picker, link dialog) rendered behind the edit modal overlay; fixed with
.tox-tinymce-aux { z-index: 9500 !important }
Data consistency
- Admin dashboard
stat_replies(Replies card) incorrectly usedCOUNT(*) FROM replies, counting first posts as replies; now usesCOALESCE(SUM(replies), 0) FROM topics- consistent with homepage stats box andboards.num_replies topics.lastreply/lastreplyid/lastreplyuseridwere never updated after a reply deletion; stale values broke board sort order (ORDER BY lastreply DESC) and read/unread tracking (last_read_at < lastreply); bothdelete_posthandlers now callapb_RecalcTopicLastReply()after the deletetotal_repliesin the homepage forum stats box incorrectly counted first posts (topic text) as replies; now derived fromSUM(topics.replies)which already excludes first posts by design- Admin
delete_topicdid not update board or categorynum_threads/num_repliescounters; now mirrors the moderator path (fetch → clean up → delete → decrement) - Admin and moderator
delete_postdid not update the categorynum_repliescounter;catidnow included in the JOIN query and the missingUPDATEadded - Admin and moderator
delete_postanddelete_topicdid not recalculatelastpost/lastaction/lastuseron boards and categories after deletion; the board listing could reference a now-deleted reply indefinitely - Deleting a reply via
delete_postdid not remove itsapb_statustable(like) entries; deleting a topic did not remove like entries for any of its replies - fixed in all four deletion paths - Deleting a topic did not remove
apb_user_read_topicsentries, leaving orphaned read-tracking rows; fixed in bothdelete_topichandlers - The
delete_postguard only rejected requests when the reply was the sole post in the topic; a second reply still allowed deleting the first post (topic text) independently, which would orphan the topic; the guard now also blocks deletion of the first post byMIN(id)comparison
Topic deletion UX
- The delete button on the first reply (topic text) in the topic view previously showed an error message; it now routes directly to
delete_topicwith a strongly worded multi-line confirmation warning (via a dedicated form action, notdelete_post)
Topic view
is_first_postwas determined by loop counter ($bcounter === 0), which misidentified the first visible reply on page 2+ as the topic opener; the correct first reply ID is now fetched once before the loop and compared by ID
Admin UI
- AP federation handle input fields in the admin board-edit form stacked vertically instead of appearing inline; root cause was Bootstrap 5's
flex-wrap: wrapon.input-groupcombined with a too-narrowmax-width: 360px; fixed withflex-nowrapclass andmax-width: 480pxon the outer wrapper - Topic link in the admin topics list used
/topic/{id}which routed to a 404; corrected to/topic/view/{id}/(both set_1 and set_2) - Reply link in the admin posts list used
/topic/{id}#post{id}which routed to a 404; corrected to/topic/view/{id}/#apb-reply-{id} - Admin and moderator posts lists included first posts (topic openers) alongside actual replies, and attempting to delete them produced a confusing error; first posts are now excluded from both listings - they are managed exclusively via the Topics section
Added (post-release fixes)
apb_RecalcTopicLastReply(topicid)helper inlibs/functions.php- queries the surviving reply with the highestcreatedat/idand writeslastreply,lastreplyid,lastreplyuseridon the topic; called by bothdelete_posthandlersapb_RecalcBoardLastPost(boardid, catid)helper inlibs/functions.php- queries the most-recent surviving reply after any deletion and writeslastpost,lastaction,lastuseron the board and its parent category; resets all three to 0 when the board is emptymod_confirm_delete_first_posttranslation key - strongly worded confirmation text shown when a mod/admin uses the delete button on the first post of a topic (which triggers full topic deletion)admin_confirm_delete_topictranslation key - proper warning dialog for the topic delete action in the admin panel, replacing the previous generic "Delete #N?" prompt
Changed (post-release fixes)
- Newest Member stat box now uses a two-line layout (username above label) consistent with all other stat items (icon → value → label)
Chore
.phpunit.cache/added to.gitignoreand removed from version control
3.0.0-alpha.3 - 2026-06-07 (logging, bot detection, search engine indexing)
Added
Search Engine Indexing setting
- New admin toggle in General Settings: "Search Engine Indexing"
- When set to Disabled, every response carries
X-Robots-Tag: noindex, nofollow, noarchive - New config key
apb_robots_noindex(default0= indexing allowed) - New function
apb_SendConfigHeaders()- config-dependent headers sent afterapb_LoadConfig()instead of inapb_SendSecurityHeaders()(which runs before config is available)
Online-page summary line
- Persistent summary above the user list: "N member(s), N guest(s), N bot(s) in the last 30 minutes"
- Always visible - does not depend on any count being non-zero
engine/online.phpnow passesmember_count,guest_count, andbot_countto templates
Bot detection
apb_UserOnlineHandler(): extended bot detection fromcurl/only to ~35 patterns- Covered: Googlebot, Bingbot, YandexBot, Baiduspider, ClaudeBot, GPT-Bot, ChatGPT-User, CCBot, ByteSpider, PetalBot, AppleBot, AhrefsBot, SemrushBot, DotBot, MJ12Bot, BLEXBot, Screaming Frog and others
- Monitoring bots: UptimeRobot, Pingdom, Site24x7, StatusCake
- Social/messaging bots: LinkedInBot, TwitterBot, WhatsApp, Telegram, Discord, Slack, Pinterest
- Fediverse crawlers / media cachers: Wafrn, Mastodon, Pleroma, Misskey, Pixelfed, Lemmy, Friendica, Akkoma, Calckey, Firefish, IceShrimp
- Empty User-Agent treated as bot - no real browser omits the UA header
- Detected bots are stored with
isbot = 1; the online page filters them out of the user list and counts them separately
set_2 templates
online.htmlandonline_user_entry.htmladded to set_2 (were missing entirely)
Fixed
- Bot dedup was broken for sessionless crawlers: every request generated a new
Guest#XXXXXX(new PHP session = new publicname), causing N rows per crawl; bots are now deduplicated byipaddressonly (isbot = 1guard), so any number of pages crawled from the same IP produces exactly one online-table row - Guest dedup query tightened:
AND isbot = 0added so a human guest and a bot from the same IP are never merged into the same row
Chore
Access logging
- Apache log format changed from
combined(%h= Traefik internal IP) toproxy_combined(%{X-Forwarded-For}i %h …) - real client IPs now visible in the log - Persistent access log written to
/var/log/apboard/access.log(secondCustomLogdirective alongside the existing stdout log); available on the host atdeploy/logs/access.log deploy/docker-compose.yml: added./logs:/var/log/apboardvolumedeploy/docker/entrypoint.sh: creates/var/log/apboardwithwww-dataownership on startupdeploy/.gitignore:logs/excluded from version control
3.0.0-alpha.2 - 2026-06-06
Added
ActivityPub / Fediverse federation
- Each board can be activated as an ActivityPub
Groupactor (/ap/board/{id}) - WebFinger endpoint (
/.well-known/webfinger) for handle-based actor discovery (@board@domain) - NodeInfo 2.0 endpoints (
/.well-known/nodeinfo,/nodeinfo/2.0) for Fediverse directory listings - Outbound federation: new topics and replies are delivered as
Create(Note)activities to all board followers via signed HTTP POST (parallel cURL fan-out withshared_inboxdeduplication) - Inbound federation:
Follow,Undo(Follow),Create(Note),Update(Note),Deleteactivities accepted and processed via/ap/board/{id}/inboxand shared inbox/ap/inbox - Remote actors cached locally (
apb_ap_remote_actors); avatars downloaded, GD-re-encoded, and served from the local domain (no external image requests during browsing) - Per-board AP configuration: enable/disable federation, custom handle, manual follower approval, allow/deny inbound topics and replies
- Emergency kill-switch (
ap_force_disabled) disables all federation instantly without touching per-board settings - Admin UI: AP settings integrated into board edit form; follower list with domain, URI, accepted date, and kick action
- Fediverse handle and follow link displayed in board header when AP is active
- Dedicated AP endpoint router (
public/ap.php) separate from the main request stack - no session, no Twig overhead for AP requests - Person actors for local users (
/ap/user/{id}) with WebFinger support; required by Mastodon to resolveattributedToon delivered notes - RSA-4096 key pairs generated per board actor and per user actor, stored in
apb_ap_board_keys/apb_ap_user_keys - Delivery log (
apb_ap_delivery_log) and outbox (apb_ap_outbox) for auditing sent activities - Instance blocklist (
apb_ap_instance_blocks) with admin UI for defederation
Security
- HTTP Signatures (Draft-Cavage-12) enforced on all inbound POST requests; unsigned requests rejected with HTTP 401
apb_AP_verifyRequest()returns the verified actor URI (derived fromkeyId), not just a boolean; callers must cross-validate againstactivity['actor']- prevents impersonation and defederation bypass via spoofed actor field- Actor cross-validation in inbox: verified signing actor must equal
activity['actor']; mismatch → HTTP 401 - Activity
idrequired on all inbound activities (AP spec §5.1); id-less activities rejected with HTTP 400 (replay protection requires a deduplication key) - Instance block check runs twice: preliminary on unverified body actor (fast path), definitive on cryptographically verified domain (closes spoofed-actor bypass)
- SSRF protection on all outbound cURL:
CURLOPT_PROTOCOLSandCURLOPT_REDIR_PROTOCOLSrestricted toCURLPROTO_HTTPS, preventing redirect-based bypass of the HTTPS-only guard - Remote actor ID validation: fetched
actor['id']must match the requested URI; prevents cache poisoning via malicious actor documents apb_SanitizeApHtml()- dedicated HTMLPurifier profile for inbound AP content; stricter than local-post allowlist (noimg, nodiv, no tracking pixels)attributedToin inboundCreate(Note)validated against the verified signing actor- Date header directional check (replaces
abs()): future-dated requests beyond 60 s clock skew tolerance rejected, closing pre-signed replay window - Payload size hard limit: 64 KB; oversized inbox POST rejected with HTTP 413 before any processing
- Rate limiting: 100 activities per 60-second window per verified remote domain
- Custom board handles re-validated against
[a-z0-9-]at read time; non-conforming DB values fall back to auto-generation
3.0.0-alpha.1 - 2023-06-12 - 2026-06-05
Complete rewrite of APBoard from scratch. Development started 12 June 2023. PHP 8.3, MariaDB, Twig templating, Composer. Licensed under GPL v3.
Added
Core forum
- Category and board hierarchy with sort order and active/hidden flags
- Board listing with topic count, reply count, last activity info
- Topic view with paginated replies and breadcrumb navigation
- New topic creation with rich text editor (TinyMCE)
- Fast reply form inline in topic view
- Topic subscriptions (subscribe/unsubscribe per topic)
- Reply likes with per-user tracking and batch loading
- Quote reply with automatic attribution
- Pin and lock topics (admins/mods)
- Board locking (prevents new topics from non-admins)
- Read/unread tracking per user per topic (via
apb_user_read_topics) - Unread indicators on boards and topics (bold + colored icon)
- AJAX mark-as-read for individual topics and entire boards
- Hot topics widget on homepage
- Latest replies widget on homepage
Search
- Full-text search across forum posts, pinboard, and user profiles
- Filter by category: All / Posts / Pinboard / Users
- Highlighted query terms in result excerpts
- Clickable result rows with permalink icon
User accounts
- Email-based registration with verification link
- Login with generic error messages (no user enumeration)
- Password reset via email with one-time token
- Session management stored in database
- Rate limiting on login, registration, and password reset
User profiles
- Avatar upload and cover image upload (GD re-encoded, EXIF stripped)
- Profile fields: birthday, city, country, zipcode, gender, bio, quote/signature
- Social links: Homepage, Matrix, Mastodon, Friendica, Facebook, YouTube, Instagram
- Per-field privacy settings (18+ toggles, three-state: hidden / members-only / public)
- Post display preferences (show/hide group badge, reg date, gender, city, social icons)
- Notification preferences (12 individual toggles)
- Account settings: display name, email, language, theme, timezone, date/time format
- Password change with current-password verification
Pinboard
- Blog-style posts per user with title, subtitle, teaser, and rich text content
- Teaser image upload with GD re-encoding
- Draft/publish toggle
- Edit and delete own posts
Private messaging
- Folders: Inbox, Sent, Drafts, Trash
- TinyMCE editor in compose view
- Recipient autocomplete via AJAX
- Reply with automatic quoting, Forward with original-message header
- Save as draft, edit and send draft later
- Auto-mark-as-read on open
- Bulk actions: mark read/unread, move to trash, restore, permanently delete
- Empty trash action
- Unread count badge in navigation
- Privacy setting: allow/deny incoming messages per user
- Rate limiting: max 30 messages per 60 minutes
Members & community
- Member directory with username search
- Sort by name, registration date, last login, last post date, post count
- Admin-configurable guest visibility for member list and online list
- Who's online list (last 30 minutes, with last-seen location)
Moderation
- Moderator panel: user list with ban/mute status badges
- Ban user (moves to group 4, stores previous group, invalidates all sessions)
- Unban user (restores previous group)
- Mute user (time-limited: 1h/12h/24h/7d/30d, or permanent)
- Unmute user
- Mods cannot ban/mute other mods or admins
- Topic management: pin, lock, edit subject, delete
- Post management: edit content (TinyMCE), delete single post
- Inline mod buttons in topic view (header and per-reply)
- Report system: users can report posts with optional reason
- Mod panel reports queue: resolve or dismiss reports
Administration
- Admin dashboard with total stats (users, boards, topics, replies)
- User management: list, search, edit, delete (anonymizes posts)
- User group management: custom groups with permission flags
- Category management: create, edit, delete
- Board management: create, edit, delete, lock/unlock
- Topic and post management with delete and toggle actions
- Legal page editor: About, Contact, Privacy Policy, Imprint (multi-language, rich text)
- Site settings: title, description, limits, pagination, guest visibility
- System info page: PHP version, DB version, loaded extensions, memory limits
Legal & static pages
- About, Contact, Privacy Policy, Imprint as admin-editable pages
- Multi-language support for all legal pages
Installation & deployment
- Browser-based setup wizard
- Docker Compose deployment stack (
deploy/) - LAMP installation guide (EN + DE)
- GitLab CI pipeline with deploy jobs for develop→dev and master→main
- PHP lint and Composer audit jobs on every branch push
- Health check endpoint (
/health.php)
UI & frontend
- Two themes included (set_1, set_2) built with Twig templates
- Prism.js syntax highlighting for code blocks in posts
- TinyMCE image upload endpoint (
/upload/) for inline images in rich text - 404 and 403 error pages (multilingual)
- Banned-user page
Internationalization
- Database-driven translation system
language_enas canonical source; other languages inherit English as fallback- User-selectable language and timezone
Security
- CSRF token validation on every POST handler without exception
- Prepared statements for all database queries (no string concatenation with user input)
- HTMLPurifier (
apb_SanitizeHtml()) for all rich text input - Plain-text sanitization (
apb_SanitizePlainText()) for names, subjects, etc. - File uploads: MIME/extension whitelist, mismatch rejection, GD re-encoding, EXIF strip
- Admin hard gate (
apb_IsAdmin()) at the top of every admin engine file - Role-based access control: Guest, User, Moderator, Admin
- Ban enforcement: session invalidation on ban (immediate effect)
- Mute enforcement: checked in
apb_DoTheReply()andapb_DoTheNewTopic() - Redirect validation: open redirect prevention on all
redirect_toparameters - Rate limiting on login (brute force), registration (spam), messaging (abuse)
- GPL copyright integrity check with public violation warning