Bonfire is an unusual piece of software, developed in an unusual way. It originally started as a project to create a generic federation library/framework, while building an app for educators to share and collaborate on learning resources with their peers, and has been forked and evolved a lot since then.
Hacking on it is actually pretty fun. The codebase has a unique feeling to work with and we've relentlessly refactored to manage the ever-growing complexity that a distributed social networking toolkit implies. That said, it is not easy to understand without context, which is what this document is here to provide.
Our main implementation language is [Elixir](https://www.elixir-lang.org/), which is designed for building reliable systems. We have almost [our own dialect](./BONFIRE-FLAVOURED-ELIXIR.md).
We use the [Phoenix](https://www.phoenixframework.org/) web framework with [LiveView](https://hexdocs.pm/phoenix_live_view/) and [Surface](https://surface-ui.org/documentation) for UI components and views.
Surface is a different syntax for LiveView that is designed to be more convenient and understandable to frontend developers, with extra compile time checks. Surface views and components are compiled into LiveView code (so once you hit runtime, Surface in effect doesn't exist any more).
We like to think of bonfire as a comfortable way of developing software - there are a lot of conveniences built in once you know how they all work. The gotcha is that while you don't know them, it can be a bit overwhelming. Don't worry, we've got your back.
The code is broadly composed namespaces such as these, many of which are packaged as "extensions" which live in separate git repositories, which are included in the app by way of mix dependencies:
Contexts are were we put any core logic. A context often is circumscribed to providing logic for a particular object type (e. g. `Bonfire.Posts` implements `Bonfire.Data.Social.Post`).
All Bonfire objects use an ULID as their primary key. We use the `Needle` library (with extra logic in `Bonfire.Common.Needles`) to reference any object by its primary key without knowing what type it is beforehand. This is very useful as it allows for example following or liking many different types of objects (as opposed to say only a user or a post) and this approach allows us to store the context of the like/follow by only storing its primary key (see `Bonfire.Data.Social.Follow`) for an example.
Context modules usually have `one/2`, `many/2`, and `many_paginated/1` functions for fetching objects, which in turn call a `query/2` function. These take a keyword list as filters (and an optional `opts` argument) allowing objects to be fetched by arbitrary criteria.
-`Bonfire.Me.Characters` (a shared abstraction over users, organisations, categories, and other objects that need to have feeds and behave as an actor in ActivityPub land)
-`Bonfire.Federate.ActivityPub` and `ActivityPub` (ActivityPub integration)
-`Bonfire.Search` (local search indexing and search API, powered by Meili)
-`Bonfire.Mailer`, `Bonfire.Me.Mails`, and `Bamboo` (for rendering and sending emails)
-`Bonfire.Files`, `Waffle`, `TreeMagic` and `TwinkleStar` (for managing uploaded content)
-`Bonfire.GraphQL` (GraphQL API abstractions)
-`Queery` and `Bonfire.Repo.Query` (Helpers for making queries on the database)
It is said that naming is one of the four hard problems of computer science (along with cache management and off-by-one errors). We don't claim our scheme is the best, but we do strive for consistency.
This namespace handles the ActivityPub logic and stores AP activities. It is largely adapted Pleroma code with some modifications, for example merging of the activity and object tables and new actor object abstraction.
This namespace contains the ActivityPub Server-to-Server REST API, the activity ingestion pipeline (`ActivityPub.Federator.Transformer`) and the push federation facilities (`ActivityPub.Federator`, `ActivityPub.Federator.APPublisher` and others). The outgoing federation module is designed in a modular way allowing federating through different protocols in the future.
for outgoing federation using the hooks in `Bonfire.Federate.ActivityPub.Outgoing` and for incoming federation using the hooks in `Bonfire.Federate.ActivityPub.Incoming`.