Things that cost me a day, so they cost you none
Working notes from building Invision Community and Flarum applications. Mostly the failures that give no error at all — the ones where everything installs cleanly and quietly does the wrong thing.
Invision Community 5
86 articlesExtensions and contracts
39What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.
- A content listener without $class takes down your whole community
- Content behaviours are TRAITS, so instanceof is always false
- Event listeners: all 58 hooks, and the argument-order trap
- Extension method signatures are fixed, and a mismatch is a fatal on installNew
- MemberFilter extensions are gated by a hardcoded area whitelist
- One content listener for every content type, including Pages databasesNew
- The core/AccountSettings extension in Invision Community 5
- The core/AchievementAction extension in Invision Community 5
- The core/AdminNotifications extension in Invision Community 5
- The core/Build extension in Invision Community 5
- The core/CommunityEnhancements extension in Invision Community 5
- The core/ContactUs extension in Invision Community 5
- The core/ContentRouter extension in Invision Community 5
- The core/Dashboard extension: ACP dashboard blocks in Invision Community 5
- The core/EditorMedia extension in Invision Community 5
- The core/FrontNavigation extension in Invision Community 5
- The core/GroupForm extension: adding fields to the member group form
- The core/GroupLimits extension: merging secondary group settings in Invision Community 5
- The core/IpAddresses extension in Invision Community 5
- The core/LiveSearch extension in Invision Community 5
- The core/MemberACPProfileBlocks extension in Invision Community 5
- The core/MemberACPProfileTabs extension: AdminCP member view tabs in Invision Community 5
- The core/MemberExportPersonalInformation extension in Invision Community 5
- The core/MemberHistory extension in Invision Community 5
- The core/MemberRestrictions extension in Invision Community 5
- The core/MetaData extension in Invision Community 5
- The core/MFAArea extension in Invision Community 5
- The core/ModCp extension in Invision Community 5
- The core/ModCpMemberManagement extension: adding tabs to the ModCP member management page in Invision Community 5
- The core/ModeratorPermissions extension in Invision Community 5
- The core/Notifications extension in Invision Community 5
- The core/OutputPlugins extension: how a {tag} in a template is resolved
- The core/OverviewStatistics extension in Invision Community 5
- The core/Permissions extension and node permission integration in Invision Community 5
- The core/ProfileSteps extension in Invision Community 5
- The core/Sitemap extension in Invision Community 5
- The core/Statistics extension in Invision Community 5
- The core/Uninstall extension in Invision Community 5
- Where OAuth account links live, and why you should not keep your own copyNew
Languages and text
5The string table, translation, and the places where text does not appear where you expected it to.
- A core/Notifications extension needs a language key named after the CLASS
- A module shows as module__myapp_thing on the administrator restrictions screen
- addToStack() often returns a placeholder, not translated text
- Creating a language in code: set_short() does not store the locale
- Why your app shows menutab__content or module__myapp_thing to customersNew
Theming, templates and forms
9Theme hooks, CSS that survives both colour schemes, and building forms that do not throw on render.
- "This theme may be out of date" usually means your form field, not the theme
- A container query cannot style its own container
- core/Loader js() and css() must return an array of arrays
- Custom CSS that works in both colour schemes, and the var() name trap
- Form\Editor needs an EditorLocations extension that actually exists
- Setting a theme custom_css and calling save() silently does nothing
- The Invision Community 4 CSS class that silently does nothing in 5New
- Theme hook types are an enum of four, there is no "replace", and how to change the page title anyway
- Widget conventions: two language keys, ipsWidget markup, and cached blanks
Background work and scheduled tasks
5The queue system, work that has to happen after the response, and jobs that finish without doing anything.
- A realtime gateway will let any member join any channel unless you sign the channel into the tokenNew
- Running code on every request, after the page has been sent
- The core/Queue extension in Invision Community 5
- The report that shows nothing: only_full_group_by, and why catching the exception is the real bug
- Your background task is running inside a visitor's page loadNew
Data, settings and storage
11The database layer, settings, tags, file storage, and backing up a live site.
- A Pages category created in code sends every article into a redirect loop
- Building a podcast feed Apple will acceptNew
- Creating a Pages database and categories in code
- Db::insert() third and fourth arguments do very different things
- Dumping an Invision Community database from PHP: ANSI_QUOTES, multi-member gzip, and the 0x trap
- Pages page content is not a template: why template syntax prints itself, and why removing an element does not stick
- S3 and R2 storage break in any CLI script without HTTPS=on
- Taggable::setTags() deletes every existing tag first
- The ?: fallback silently breaks any setting an admin can set to zero
- The core/FileStorage extension in Invision Community 5
- There is no event when a tag is created, and what that means for your app
AI features and expectations
5What these features do, what they cost, and what buyers reasonably but wrongly assume they do.
- A chat model in an embeddings field fails silently, and looks like a broken app
- Why a similarity threshold is never enough for automatic classification
- Why your AI assistant's links arrive as plain textNew
- Your AI assistant is only as good as what you gave it to read
- Your classifier does not learn, and everyone will assume it does
Application structure and releases
11The JSON files an application is made of, versioning and upgrade steps, and testing from the command line.
- "You do not have permission for that" on your own AdminCP screen: the $csrfProtected property
- A malformed manifest silently disables your whole application
- A shared image vanishes the moment one member changes their profile photoNew
- A stray "menutab_system" in your AdminCP: acpmenu.json tabs are not validated
- Application versions: why re-uploading the same version does nothing
- Invision Community already runs an OAuth 2.1 server — do not write another oneNew
- Raw language keys in the AdminCP menu: acpmenu.json must be an object
- Six ways an Invision Community 5 application fails silentlyNew
- What you can and cannot test from the command line
- Your editor toolbar button never appears, and nothing is loggedNew
- Your friendly URLs have the app name in them twiceNew
Realtime, chat and calls
1WebSocket gateways, relays and the server-side pieces live features depend on — where "it works when I test it" and "it works for your members" are different claims.
Flarum 2
6 articles- Flarum 2: AbstractModel mass assignment throws a 500
- Flarum 2: frontend model relations must use the hasOne/hasMany call pattern
- Flarum 2: json-api-server returns 403 for declared but unwritable fields
- Flarum 2: Laravel facades throw "facade root has not been set"
- Flarum 2: never redefine core CSS variables at :root
- Flarum 2: notification Blueprints need getFromUser()
Nothing matches that.
Background work and scheduled tasks
5 Articles in this category
-
A WebSocket gateway that fans Invision Community events out to browsers usually authenticates the connection — a short-lived token, signed with a shared secret, proves the socket came from a page your community served. That is enough while every channel is public, like a forum topic. The moment a channel carries something private — a conversation between two members — it is not enough, because the token says who the member is but not which channels they are allowed to join. Nothing stops a loggeAdded by Ernest Defoe
- 0 comments
- 25 views
-
An Invision Community site that has not been given a cron job runs its scheduled tasks during ordinary page views. That is the default, and most self-hosted communities never change it. If your application does anything slow in a queue or a task — and calling an outside API is slow — a random visitor pays for it with their page load, and with the database connection that page load is holding. This is not a theoretical concern. It took a live community down. The symptom The report to look o
-
You write a reporting query, wrap it in try / catch so a bad query can never take down an AdminCP page, and ship it. The screen renders. The table is empty. You conclude there is no data yet. There is data. The query is broken, and your own catch is what turned a fault into a plausible-looking zero. The query Db::i()->select( 'conv_title, conv_url, conv_class, conv_item, COUNT(*) AS joined', 'my_table', array( 'conv_item > 0' ), 'joined DESC', 25, array( 'conv_c
-
Some work has to happen on every page view — recording an analytic, touching a cache, noting that something was seen — and none of it should make the visitor wait. Invision Community supports this, but the pieces are not obvious and the method that looks right is the wrong one. core/Loader is the only per-request extension point Dispatcher\Front invokes exactly one extension point on every front-end request, and it invokes it three times: // early, while building the page foreach ( Applicati
-
A core/Queue extension is a resumable batch job. You register it in your app's data/extensions.json, hand it work with IPS\Task::queue(), and core writes one row into core_queue. The queue task (IPS\core\tasks\queue) then calls IPS\Task::runQueue() in a loop until it runs out of time, memory, or rows — each call picks one row, instantiates your class, and calls run() exactly once. There are only three consumers in the whole suite, and it is worth knowing all three because they behave different