Skip to content
View in the app

A better way to browse. Learn more.

ernestdefoe.online

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
ernestdefoe.online

Extensions, themes & support for Flarum and Invision Community

Vibe coding for the community web. Report a bug, request a feature, or dig into the source — this is where the tools you use get built, in the open.

We do custom Bespoke Invision Community apps. If you have an idea for something you want then use the contact form to get in touch with us.
Knowledge base

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.

92 articles

Invision Community 5

86 articles

Extensions and contracts

39

What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.

Languages and text

5

The string table, translation, and the places where text does not appear where you expected it to.

Theming, templates and forms

9

Theme hooks, CSS that survives both colour schemes, and building forms that do not throw on render.

Background work and scheduled tasks

5

The queue system, work that has to happen after the response, and jobs that finish without doing anything.

Data, settings and storage

11

The database layer, settings, tags, file storage, and backing up a live site.

AI features and expectations

5

What these features do, what they cost, and what buyers reasonably but wrongly assume they do.

Application structure and releases

11

The JSON files an application is made of, versioning and upgrade steps, and testing from the command line.

Realtime, chat and calls

1

WebSocket 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.

Nothing matches that.

Flarum 2

Extension development notes and gotchas for Flarum 2.

6 Articles in this category

  1. Ernest Defoe ·
    A notification Blueprint that omits getFromUser() fails at send time rather than at registration, so the extension installs and enables cleanly and only breaks when the notification actually fires. The required surface public function getFromUser(): ?User { return $this->actor; // may be null for system notifications } public function getSubject() { return $this->thing; } public function getAttributes() { return ['thingId' => $this->thing->id]; } public static func
    • 0 comments
    • 31 views
  2. Ernest Defoe ·
    Redefining a core custom property at :root in an extension changes it for every other extension and for the theme, and whichever stylesheet loads last wins. The result is a conflict that only appears when a particular combination of extensions is installed, which makes it close to unreproducible from a bug report. Wrong :root { --primary-color: #34d399; /* now everyone has this */ } Right Namespace your own variables, and scope any override to your own container: .MyExtension { --m
    • 0 comments
    • 32 views
  3. Ernest Defoe ·
    Frontend relations are declared as calls, not as property definitions. Getting this wrong produces undefined at render time with no console error, which reads as an API problem rather than a model problem. Right Thing.prototype.owner = Model.hasOne<User>('owner'); Thing.prototype.items = Model.hasMany<Item>('items'); Then thing.owner() — called, not read. Eager loading is endpoint-level eagerLoad is declared on the endpoint, not on the field. Putting it on the field silently load
    • 0 comments
    • 27 views
  4. Ernest Defoe ·
    A field that appears in your API schema but is not explicitly marked writable produces a 403 Forbidden on write, not a validation error. The response says nothing about which field caused it. The cause json-api-server treats writability as opt-in. Declaring a field makes it readable; it does not make it settable. A create or update that includes it is rejected as a permissions failure. The fix Mark the field writable explicitly, and gate it with the same check your policy uses: Schema\Str::
    • 0 comments
    • 23 views
  5. Ernest Defoe ·
    File, Cache, Storage and friends are Laravel facades. Flarum boots the Illuminate container without registering the facade root, so calling them throws: RuntimeException: A facade root has not been set. The fix Inject the contract instead of reaching for the facade. Flarum's container resolves them normally: use Illuminate\Contracts\Filesystem\Factory; public function __construct(protected Factory $filesystem) {} // then $disk = $this->filesystem->disk('flarum-assets'); Same pattern f
    • 0 comments
    • 26 views
  6. Ernest Defoe ·
    Since Flarum 2, passing an array of attributes straight into a model constructor or fill() raises a 500 rather than silently ignoring unguarded attributes. Wrong $thing = new Thing($attributes); // or $thing->fill($request->getParsedBody()['data']['attributes']); Right Assign properties explicitly. It is more code and it is also the only version that survives a schema change without quietly writing a column you did not intend: $thing = new Thing(); $thing->title = $attributes['title
    • 0 comments
    • 24 views

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.