PubliraGitHub

Four surfaces, one catalog

Three Next.js apps, a Flutter client, and the mail they send, each with its own audience.

The reader-facing site

apps/web-storefront

The site a reader lands on, published under the publisher's own brand. Browsing, searching, ranking, following, signing in, and the viewer that turns the pages.

CatalogThe work the tenant is leading with, above the shelves the rest of the page is built from: the week's chart, the newest episodes, the day's schedule, and the labels and authors it wants read. An announcement the console pins runs across the top of every page until the reader closes it, and everything carries the publisher's brand rather than Publira's.
GenresEach genre drawn from the covers of the series it ranks highest, or from artwork the editors upload for it, with the number of series behind it. A genre opens into its most-read series of the week above all of its series, sorted and narrowed the way the whole list is, and the genres themselves are the tenant's own classification rather than a fixed list.
RankingThe daily chart and the weekly one, each row carrying how far the series moved since the chart before it. The positions come from what readers did — episodes opened and reacted to — aggregated by a batch job rather than arranged by hand, and R15 and R18 titles are ranked in charts of their own that open only to a reader who may see them.
SeriesEvery published series, sorted and narrowed by genre, by serialization status, or down to the ones with free episodes. An age-rated title is marked wherever it is listed and stays hidden until the reader has confirmed they can see it.
Series detailThe cover, synopsis, label, genres, and tags, with every author in the role they are credited in, and Follow and Share beside them. The episodes run below in reading order, each marked free or paid, so what can be read now is clear before anyone signs in.
Episode viewerPages drawn on a canvas and turned as spreads, right to left, from the page the editor set the spreads to start on. The toolbar's slider moves a spread at a time, and past the last page the reader reacts to the episode and is offered the next one. The viewer is the package published on npm, so the paging, the spread, and the direction are the library's behaviour.
SearchOne keyword answered by the series, the authors, and the labels that match it, each group opening into a list of its own. Only what the tenant has published is searchable, so nothing still sitting in the editorial queue can be reached from here.
AuthorsThe authors published on the tenant, with the number of series behind each name, and each author's page with a portrait, a profile, a follow, and every series credited to them. An author is a profile the editorial console manages, so one name carries across every series it is credited on.
Signing inAn email address and a password, or the Apple and Google accounts a reader already has, on the sign-in and the sign-up form alike, and a passkey for a reader who has registered one. The providers are the tenant's own: they appear once its console holds their credentials, and readers are asked to accept the tenant's terms when it names them, and again when it revises them.
A reader's own pagesWhat is new from the series and authors the reader follows, the episodes they bought with how long each stays readable, and how they want to be told about a new episode — by mail, or by a notification from the browser.

The tenant console

apps/web-admin

Where editors work: the catalog and the publishing queue, the payment and sign-in providers, the theme and the pages of the public site, the messages readers send, the purchases they made and their refunds, what each author is owed, and the record of every change made to any of it.

DashboardPublished series, draft episodes, and scheduled releases, above the queue of everything still needing attention. The queue gathers the drafts and the upcoming releases with when each goes out, so an editor opening the console is shown what is waiting rather than having to go looking for it.
SeriesTitles, labels, publication dates, reading period, age rating, and status in one table, narrowed by serialization state or by rating. A series opens into its details: its title and synopsis in each language the tenant offers, and a credit for every author in the role they hold and the share of sales it earns, with the publisher's remainder worked out as the shares are typed. Those credits are the template its new episodes start from.
EpisodesEvery episode of a series in reading order, dragged into place — or moved with an arrow key — rather than renumbered by hand. An episode is scheduled for a time in the tenant's own zone, and its pages go up as images, a ZIP, or an EPUB, are reordered the same way, and can each be replaced or deleted even after the episode is out.
AuthorsThe roles this tenant credits authors in, renamed and moved into the priority the credits follow, and each author's own page. A tenant admin links the reader accounts that belong to an author there, so the author reads their own episodes without buying them and is not asked to rate them.
PaymentsThe provider this tenant's web checkout runs through — Stripe or PAY.JP — with its keys, and the App Store and Google Play credentials its app sells through. A secret is write-only: coming back, an editor sees its state and a mask, never the value.
Sign-in and app linksThe Apple and Google accounts this tenant's readers can sign in with, and the Android and iOS apps its links open in. Both are per tenant, so every publisher on one install signs its readers in under its own name and hands its links to its own app.
ThemeThe brand colors, the text drawn on each of them, and the typefaces readers see first, beside the logo and the icon the public site carries, with a preview built from the parts the public site is made of. The preview follows every edit while the public site keeps its current colors, so nothing reaches readers until the theme is saved.
Pages and announcementsThe tenant's own pages written in Markdown, with a translation per language and every published version kept to compare and roll back to, and the announcements it delivers to everyone who opens the site — one of them pinned as a banner across the top of every page.
Contact messagesWhat readers sent through the site's contact form, with the address to answer at, who on the staff has it, and where it stands. An answer written on the message's page is mailed to the reader and kept under it, and a new message is mailed to the staff as well, so nobody has to keep the console open to hear about it.
Reports and royaltiesHow many members finish each episode, and a month's sales, refunds, and what each author is owed, cut at the month's edges in the tenant's own time zone. Closing the month turns it into a statement that no later sale changes and that downloads as CSV, and a refund recorded after the close is carried into the next statement as an adjustment.
Audit logWho did what, when, and how it turned out, with the actor and the record each action touched. It filters by period, action, or actor, and the dates are read as calendar days in the tenant's own time zone rather than the server's.

The platform console

apps/web-platform

One level above the tenants, for whoever operates the install: what the install still needs set up, tenant status, cross-tenant events, the readers of every tenant, and the settings every tenant shares, from object storage to security policy.

DashboardWhat the install still needs set up, with a way into each setting, above the count of tenants and the recent cross-tenant events — tenants created, roles granted, accounts added. An operator opening the console sees whether the install is ready before anything else.
TenantsEvery registered tenant with its status and the day it was created, searchable by name or ID, and each one's profile, domains, and members. This console manages a tenant's status and who administers it, and stays out of the catalog, which each tenant runs from its own console.
UsersThe readers of every tenant in one list, with the tenant they belong to, the day they registered, and their status. This is where an operator suspends or removes an account, while what those readers may read stays with the tenant that published it.
Install settingsThe one S3-compatible bucket every tenant's uploads go to, the SMTP relay the install sends through, the limits that guard sign-in and mail, and the key pair Web Push signs with. A saved change reaches every running server without a restart.

The mobile app

mobile

The same catalog on a phone, from one Flutter codebase for Android and iOS, under the tenant's own name and theme. It calls the public API directly rather than going through the site, signs a reader in with an email address, a passkey, Apple, or Google, sells episodes through the store or the site's checkout, and keeps the episodes a reader has opened or saved on the device.

CatalogThe tenant's name and theme in the app bar, the announcement the console pinned, and the episode the reader stopped at, above the genres and the week's chart. A bar along the bottom reaches home, search, the library, notifications, and the account from every screen but the viewer.
Genres and searchThe genres drawn as tiles of their covers, each opening into its series with the same sorting and filters the site offers, and one keyword answered by the series, the authors, and the labels that match it. Every list is answered by the same public API the site reads, so only what the tenant has published can be found.
Series and authorsCover, credits in the roles the tenant defined, label, genres, and tags, with a follow for the series and for each author and Share handing out the site's own link. An author's page carries the same follow, and a new episode from someone the reader follows arrives as a push notification that opens straight into the viewer.
Episode viewerThe episode the site serves, laid out from the spread and the reading direction the editor set on it, with a slider that moves through the pages. A paid episode is bought in the store's own sheet or through the site's checkout, whichever the tenant chose, and a screenshot of a page is met with the tenant's notice on how its pages may be used.
Library and inboxContinue reading, follows, the episodes saved on the device, and recommendations, each a list of its own; the episodes the reader bought with how long each stays readable; and the inbox of what was sent to them. Saved pages are kept encrypted under a key the device mints for itself, and reading done offline is sent once the network returns.
AccountEverything a reader does with their account without leaving the app — the icon, the name, the address, the password, the linked Apple and Google accounts, mail notifications, the tenant's own pages, a message to the tenant, and deleting the account — and a sign-in that offers Google on Android and Apple on iOS beside an email address.

The mail it sends

apps/email-renderer

Account mail and the notices staff receive, drawn as HTML from React components by a renderer of its own and sent with a plain-text part beside it. Mail to a tenant's readers and staff carries the tenant's name rather than Publira's and is written in the tenant's language; in Japanese, Korean, and Chinese the spacing between scripts is left to the mail client's text rendering, as it is on the site.

Confirming an addressThe first mail a new reader receives: the button that confirms the address, when the link expires, and the link written out for a client that shows no buttons.
Resetting a passwordThe link that sets a new password, expiring a day after it was sent, in the same layout the tenant's other mail uses.
A message for staffWhat a reader sent through the contact form, with the address to answer at and the account they were signed in as, so staff can answer from the message's page in the console or from their own mail client.