toascribe
A self-hosted publishing platform.
In development
Overview
Write posts and pages with a block editor, manage media and organise a publication. Includes tools for menus, themes and users.
What's new
v0.7.0
- changedBefore you update: take a backup (
docker compose exec api toa backup create) and copy it off the server. The update runs eight database migrations (0007to0014);migratemakes a backup of its own first when the site has content. - changedNew in
.env(all optional):TOASCRIBE_UPLOAD_MAX_SIZE_MB(64),TOASCRIBE_CONFIG_DIR(a folder withtoascribe.tomlfor daily, encrypted backups),TOASCRIBE_UPDATE_CHECK=off,TOASCRIBE_DEBUG=1,OTEL_EXPORTER_OTLP_ENDPOINT, andTOASCRIBE_CACHE_VALKEY_URL. New volumes:uploads,backupsandconfig. - changedAfter you update: run
toa secrets exportonce and keep the file with the recovery key (docs/RESTORE.md), and look at «Kontrollpanel → Nettstedshelse» for anything that should be fixed. - changedFor API clients:
POST /api/v1/auth/registerneeds theformTokenfromGET /api/v1/auth/options, fetched from the same IP address and sent between 2 seconds and 1 hour after it was fetched. Scripts use application passwords over HTTPS; they never write raw HTML. - changedThe user documentation is in
docs/user/(bokmål), and «Hjelp» in the admin opens the page for each screen. - addedThe admin in English (K-330): «Profil → Personlige innstillinger → Språk» chooses bokmål, English or the site's language, and the admin follows the profile first, then the site's language. Every admin text exists in both languages (a test fails when one is missing). The public site stays in bokmål.
- addedThe dashboard (K-033): «Aktivitet» lists the posts that will be published soon and the latest published ones; «Hurtigutkast» saves a title and some text as a draft and lists your three newest drafts; «Nettstedshelse» sums up the checks (background jobs, database migrations, the last backup, a newer version, tested e-mail, the cache, debug mode, search engines) as good, «bør forbedres» or «bør fikses», for administrators.
- added«Hjelp» in the admin bar (K-038) opens the page of the new user documentation (
docs/user/, in bokmål: installation, update, backup, content, media, menus, theme, settings, users; K-300) that covers the screen, for the version that runs. - addedProfile pictures (K-015, K-236): a public image from the media library on the profile, shown in the users list and on the author's page on the site; the initials otherwise. Gravatar for accounts without a picture is a choice under «Personvern», off by default, because the browser then fetches images from a service outside the site.
- added
/.well-known/security.txt(K-319) from «Personvern → Sikkerhet» (a contact for security reports and a policy page), andSECURITY.mdin the repository on how to report a vulnerability. - addedThe API (K-251, K-252): the content list takes
include=featured_media, which adds each item's featured image. A route that is to be retired answers withDeprecation,SunsetandLinkheaders and is marked in the OpenAPI document;docs/API.mdhas the rules. - addedSpam protection on registration (K-006): the form carries a signed token, and a form sent within two seconds of loading, or with a hidden field filled in, is refused with «Skjemaet ble ikke sendt. Last siden på nytt, vent et øyeblikk og prøv igjen.» (more than an hour old: the same). The registration form of an older admin will not work against this api.
- addedMoving to a new server (K-271):
toa secrets exportseals the encryption and signing keys with the recovery key from the setup wizard into a 0600 file, and refuses without this install's key;toa secrets importopens it on the new server and writes the keys as.envlines to be appended to.env(>> .env; the file can come on standard input,import -).docs/RESTORE.mddescribes the whole way. A restore now shows where a backup comes from (when, which version, which host) and warns when this install did not make it. - addedLogs and traces (K-297, K-298): the api, the worker, the site and the admin write JSON lines, and one fixed list of fields is never written (passwords, tokens, cookies,
Authorization, secrets, e-mail addresses), nor an e-mail address or credential in any text. A request id follows a page from the site to the api and into the jobs it queues.TOASCRIBE_DEBUG=1adds debug lines and the kind of error in a 500 answer (never a stack or a secret to visitors), and Nettstedshelse warns while it is on. Optional OpenTelemetry: setOTEL_EXPORTER_OTLP_ENDPOINTand the api and the worker send traces and metrics there, with the same fields hidden; without it nothing is loaded or sent. New dependencies: the OpenTelemetry SDK (only loaded when the address is set). - addedUsers (K-016, K-020 to K-022): «Brukere → Legg til ny» makes an account with a password set there, or sends an invitation by e-mail so the person chooses their own. «Slett» on a user moves their content (and files) to another account, or deletes what they wrote alone; one's own account and the last administrator cannot be deleted. The bulk action «Send tilbakestilling av passord» mails a reset link to each ticked user. «Applikasjonspassord» on the profile: a password per program, shown once, with when and from where it was last used and «Tilbakekall». They work against the API with
Authorization: Basicover HTTPS only, never for signing in to the admin, and a wrong one counts as a failed login. - addedMore
toacommands (K-261, K-263 to K-265, K-270 to K-272), as WP-CLI's:toa post,toa term,toa menu(list, get, create, update, delete) andtoa option(list, get, update) act as the account named by--userand go through the same checks as the admin;toa cache flush [--tag];toa jobs list|retry|cancel;toa secrets list(names and where they are, never a value) andtoa secrets rotate(a new encryption key, then every stored secret sealed again with it);toa shell(a Node REPL in the container, with a warning);toa core version. Every change is in the audit log with «cli» as the actor. Exit codes: 0 done, 1 an error underway (not found, not allowed), 2 invalid input. - addedUpdates (K-290): «Kontrollpanel → Oppdateringer» shows the version that runs, the newest release and a link to what is new, and the command to update on the host (the admin cannot update containers). The worker looks once a day (
toa check-updateat once): a plain GET of the public image tags on ghcr.io withUser-Agent: toascribe, nothing about the site. Off on the page, or on the server with the newTOASCRIBE_UPDATE_CHECK=off. - added«Verktøy → Nettstedshelse → Info» (K-203): the version and last migration, the server, the database, the cache, the worker and its queues, the site, the media library, the last backup and the update check, with «Kopier til utklippstavlen» for support (e-mail addresses, addresses, paths and anything that looks like a key are replaced by
[skjult]). - addedBackups (K-292, K-293):
toa backup create|list|verify|prune|restore. A backup is one.tar.zstfile with the database, the uploads and a manifest with a sha256 per part, mode 0600, in the newbackupsvolume. Secrets are left out unless--include-secrets, which needs an age public key intoascribe.tomland encrypts the file;encrypt = trueencrypts every backup. Withschedule = truethe worker makes one a day and keeps the newest seven (keep). A restore runs from themigrateservice, checks the whole file before it changes anything, refuses a newer version, migrates an older one up and keeps the site in maintenance mode meanwhile.migratenow runstoa db migrate, which makes a backup before a pending migration and stops if it fails (--no-backupskips it, with a warning). New: theconfigvolume orTOASCRIBE_CONFIG_DIR(a folder withtoascribe.toml, mounted read only at/etc/toascribe), the migration0014_journal_read_for_backups(the app role may read the migration journal), andpg_dump,zstdandagein the api image. New dependency:tar(reading an archive). - addedMaintenance mode (K-288, K-266):
toa maintenance on|off|status, with an optional message and Retry-After. Visitors get 503 and a maintenance page (a theme can draw its own withtemplates/maintenance.vue), and feeds, the sitemap, robots.txt and/oembedanswer 503 too; an account that may manage the site sees the site as usual, with a notice in the toolbar, and the admin works. - added«Innbygging» (K-225): videos, music and posts from YouTube, Vimeo, Spotify, SoundCloud, TikTok, Bluesky and the Mastodon instances listed under «Innstillinger → Personvern». Paste a link alone on a line, or choose the service in the block inserter. The server reads the service when the post is saved and keeps only the player's address on the service's own hosts and a thumbnail in the media library; any other address is shown as a link. YouTube is shown from youtube-nocookie.com. With «Klikk for å laste» (on by default, «Personvern») the site loads nothing from the service until the reader clicks.
- addedThe site is an oEmbed provider:
/oembed?url=answers for its own published, public content, and such pages name it in their head. - addedSearch engines and sharing (K-224): every page has a canonical address, a description, Open Graph and Twitter cards,
rel="prev"andrel="next"on paged lists and split posts, and JSON-LD (WebSite,BlogPostingorWebPage,BreadcrumbList, and the publisher). Titles are «Tittel – Nettstedstittel», and the front page «Nettstedstittel – Slagord». The SEO panel's fields go first. - added«Deling og søkemotorer» on «Innstillinger → Lesing»: a default sharing image (used when content has neither its own nor a featured image), and whether the site represents an organisation (name and logo, the logo from «Tilpass» by default) or a person.
- addedRSS 2.0 as in WordPress (K-222): the site's
/feed/, and a feed under every category (with its parents), tag and author address (/category/<sti>/feed/,/tag/<slug>/feed/,/author/<navn>/feed/, following the permalink bases). The number of items and the whole text or the excerpt come from «Lesing». A password-protected post has its title and link only; private, draft and scheduled posts are never in a feed. Each page names its feeds in its head. - added
/sitemap.xml(K-223): an index of the posts, pages, categories, tags and authors, 2000 addresses to a file, without password-protected or «noindex» content and without empty terms; it is not there when the site asks search engines not to index it. - added
/robots.txt(K-223): keeps crawlers out of/admin/and names the sitemap, or shuts everything when the site asks not to be indexed, as WordPress does. - added«Utseende → Tilpass» (K-150, K-151), as WordPress' Customizer: the site's title, tagline, logo and icon, the active theme's colours and fonts (each theme keeps its own), the front page and «Ekstra CSS», with a preview of the site beside the panel that shows the choices before they are published. «Ekstra CSS» is for administrators only, and CSS that could break out of the page's style element is refused. The site can now be framed by its own address (the admin's preview), by no other.
- added«Utseende → Menyer» (K-132), as WordPress' menu screen: pages, posts, categories, tags and links of one's own, three levels and more, with drag and drop, buttons or the keyboard, and «Administrer plasseringer» for the theme's locations. An item follows its content when the title or address changes, and leaves when the content is deleted for good; content that is not published is never linked. The default theme has a main menu (with a menu button on phones) and a footer menu.
- added«Utseende → Globale sett» (K-106): named collections of blocks for the whole site, edited in the block editor and shown with the new «Globalt sett» block or by a theme (the default theme shows «Bunntekst» in its footer). One migration (
0013_global_set_blocks). - added«Innstillinger → Permalenker» with WordPress' structures (Enkel, Dag og navn, Måned og navn, Numerisk, Innleggsnavn and Egendefinert with %year%, %monthnum%, %day%, %hour%, %minute%, %second%, %post_id%, %postname%, %category% and %author%) and the category and tag bases (K-197, K-221). «Innleggsnavn» is the default; a site that still has the installer's day and name gets it (migration
0012_permalink_default). Category addresses have their parents in them, as in WordPress. - addedOld addresses keep working (K-207): a changed slug, parent page, structure or base answers 301 to the address now, without chains or loops.
- added«Innstillinger → Generelt», «Skriving», «Lesing» and «Personvern», with WordPress' fields (K-191, K-193, K-194, K-198). A new administrator address is used only after the link sent to it is opened by someone signed in as an administrator (K-192). «Be søkemotorer om ikke å indeksere» adds
noindexto every page of the site. The privacy page is linked in the default theme's footer and on the registration form once it is published (K-199). One migration (0011_admin_email_change). - addedThe password form of a protected post works without JavaScript, and «Forhåndsvis» in the post and page lists opens the signed preview link on the site, as the editor's button does.
- addedThe site shows its content (M1.4): every address goes through WordPress' template hierarchy to the active theme's template, chosen in the new
toascribe.toml([site] theme). A theme is a folder withtheme.json(themeApi: 1); the build stops with a list of what is wrong when it does not pass. A child theme extends its parent and overrides only its own files, one block's look included (blocks/<name>/View.vue). The default theme has the front page, posts with their pages and «Les mer», pages with «Full bredde», archives, search and 404, and passes WCAG 2.2 AA. The custom HTML block runs as written on the site (see SECURITY.md). Signed-in people see a toolbar with «Rediger». «Forhåndsvis» in the editor opens the item on the site through a signed link. The editor offers the heading levels and page templates the theme names. - addedThe Query Loop block lists published posts or pages by type, category, tag and order, as the page is shown (K-085).
- addedThe site caches the api's answers by tag, and a change clears what it touched on the next request. One instance keeps the cache in memory. Several instances share it in Valkey: turn on the
valkeyprofile and setTOASCRIBE_CACHE_VALKEY_URL. Valkey now runs on a network of its own with the site. Nothing is cached for someone who is signed in, has a post password or opens a preview. - addedThe public reading API of the site (M1.4):
/api/v1/public/resolvetells what an address is after WordPress' template hierarchy (front page, posts page, posts with their pages after a page break, pages by their whole path, category, tag, author and date archives, search,?p=as a redirect, 404),/public/querylists published posts or pages by filter,/public/settingsgives what a theme shows. Only published, public content is read; a password-protected item shows its title and the form until its password is given (a ten-day cookie, guesses limited as logins are). A preview link (POST /content/{id}/preview-link) shows an item as it is stored for 30 minutes, until the session that made it ends. One migration (0010_cache_invalidation): the log of cache tags a change clears, which the worker empties after a day. - addedThe default content («Hei, verden!», the sample page and the privacy policy) is made in toascribe's block format, and content stored in WordPress' block form is converted by the migration step, so the editor can change it; only a WordPress block type toascribe does not know keeps an item read-only.
- addedA paste over a selection of several blocks takes their place. «Forhåndsvis» with a session that has run out opens the login dialog in the editor instead of a tab with the login screen.
- addedThe block editor of M1.3 (K-075, K-081): an edit component for every basic block, the inserter with search and categories (and «/» in an empty paragraph), and the block toolbar. A text is shown as the site draws it until it gets the focus, so a long document opens fast, and a block keeps its state when it moves into or out of a column. Several blocks can be selected (Shift+click, Shift+arrow) and deleted, copied, cut and pasted, also into columns, and undone in one step; plain text with empty lines is pasted as paragraphs. Lists take Tab and Shift+Tab. «Hurtigtaster» lists the keys, among them Ctrl+S, Ctrl+Alt+T and Ctrl+Alt+Y.
- addedThe edit screen (PLAN «Redigeringsskjermen»): «Lagre kladd», «Forhåndsvis», «Publiser», «Planlegg» for a time ahead, «Oppdater», and «Send til gjennomgang» for a contributor. The sidebar's «Innlegg»/«Side» tab has the status and visibility (public, private, password), the publish time («Umiddelbart» or a chosen time) and the time it goes back to draft, the authors, «Fest øverst», categories and tags, the featured image, the excerpt (K-107), discussion, the page attributes, the SEO panel with a search and a sharing preview (K-105) and «Flytt til papirkurven»; the «Blokk» tab has the settings of the selected block.
- addedWhen the session runs out while editing, a login dialog opens over the editor, and the save that found it goes on afterwards; nothing written is lost (K-010). Leaving with unsaved changes asks first.
- addedThe basic blocks of M1.3 in the block format (K-078, K-079): heading, list (bulleted and numbered, with levels), quote, code, preformatted, table (with a header row), gallery (columns, cropped or not, linked to the file or not), buttons, group, separator, spacer, «Les mer» (posts only) and page break, and custom HTML, beside paragraph, image and columns. Each block's
block.jsonis checked in the editor and again by the api. - added
@toascribe/block-views: how the blocks look on the site, as server-rendered HTML with no script and no style attribute, and a default stylesheet. The admin's preview uses it; the site's templates will (M1.4). - addedCustom HTML needs
unfiltered_html(only the administrator by default). An account without it may keep, move and delete such a block but never add, change or copy one, also straight through the API (K-088). - addedThe content API takes a featured image (
featuredMediaId, K-070) and the SEO panel (seo: title, description, sharing image, noindex; K-105). Both images must be images in the media library that the account may see. - addedCategories and tags (M1.2): «Innlegg → Kategorier» and «Innlegg → Stikkord» (
manage_categories), with the form on the left and the list on the right, search, Rediger, Hurtigrediger, Slett and bulk delete; categories have a parent. «Ukategorisert» is the default category: it can be renamed, not deleted. Deleting a category works as in WordPress: its child categories move up to its parent, and a post left without any category gets «Ukategorisert». Slugs are made as WordPress makes them, also for Norwegian letters. - addedThe terms API under
/api/v1/taxonomiesand/api/v1/taxonomies/{taxonomy}/terms, and categories and tags in the content API. The post list has the columns «Kategorier» and «Stikkord» as filter links and a category filter; quick edit has the category tree and the tags as text; bulk «Rediger» can add categories and tags. - addedThe media library (M1.2): «Media → Bibliotek» as a grid or a list, filtered by type, month and folder, with search and folders; «Vedleggsdetaljer» with the alternative text, title, caption, description, visibility, folder, «Kopier URL til utklippstavlen» and «Brukes på» (the posts and pages you may read by name, the rest as «og N andre»); Erstatt (a new file under the same id, once the worker is done with it), Rediger bilde (turn, mirror, crop, scale; the original is kept), Lag bildestørrelser på nytt and Slett permanent with a warning that names where the file is used. Everyone who may upload can make folders and put files in them; renaming, moving and deleting a folder needs
edit_others_posts. - added«Media → Legg til ny» and the library's uploader: drag and drop or choose files, each with its progress, the largest size and the allowed types shown; «Sett inn fra nettadresse» fetches a file into the library and refuses private addresses.
- addedThe image sizes of WordPress, made by the worker as WebP: thumbnail (150 × 150, cropped), medium (300), medium_large (768), large (1024), 1536 and 2048, and a
-scaledcopy of an image over 2560 pixels; the original is kept.toa media regeneratemakes them again. Every run gives them new file names, so a cached copy of an old size is never shown for a new one. An image the worker cannot handle is tried three times, then marked «Feilet» in the library with the reason; «Lag bildestørrelser på nytt» tries again. - added«Innstillinger → Media»: the three image sizes and the thumbnail crop, the year and month folders, the upload limit, the pixel limit and which types each role may upload.
- addedThe media API under
/api/v1/mediaand/api/v1/media-folders, and/api/v1/settings/media. An upload's type is read from its bytes and must agree with its name; SVG, HTML, scripts and programs are never accepted. Files are served withnosniffand a sandbox Content-Security-Policy, and a file that is not an image as a download. A file made private moves to new addresses: its old public address stops answering and the old files are deleted. A copy that a CDN or shared cache already holds stays until it expires (public files are cached for a year), unless you purge it there. A private file has no public address: it is served by the api to its uploader and to those who may read private posts. - addedThe image block stores the file's id from the library, with the alternative text (required unless the image is marked decorative) and the caption, and is drawn with
srcsetandsizesfrom the file's sizes. Image blocks with an address from before are upgraded to the file's id when the file is in the library. - addedThe users list takes
per_pageand answers withX-Total-CountandX-Total-Pages. - addedThe content API under
/api/v1/content: list posts or pages (views, author, search, month, sort, pages,X-Total-CountandX-Total-Pages), make, read, change and delete them, publish, move to the trash and restore, bulk actions, and the list of possible authors. Who may do what follows WordPress: posts and pages have their own capabilities, own and others' items, published and not, and a contributor can send for review but not publish. - addedStatuses as in WordPress: draft, pending, scheduled, published, private and trash. A scheduled item is published, and a published item with an unpublish time goes back to draft, by a job in the worker every minute; each change happens once, also with two workers. The trash is emptied after 30 days, and a restored item gets its old status back.
- addedSlugs as WordPress makes them (
Blåbær på Ørlandbecomesblabaer-pa-orland), unique per type, language and parent with-2,-3when taken; a trashed item's slug gets__trasheduntil it is restored. - addedShort links (
/?p=<number>) in every answer, several authors per item, password protection (the password is stored hashed and can be replaced, not read), private items, sticky posts, and the parent, order and template of pages. - addedSearch finds text in the title, the excerpt and the blocks; the blocks are checked against their
block.jsonon every save. - addedThe admin menu has «Innlegg» (Alle innlegg, Legg til nytt) and «Sider» (Alle sider, Legg til ny). The lists have the views with their counts, a month filter, search, sorting, pages, child pages under their parent, row actions (Rediger, Hurtigredigering, Papirkurv, Forhåndsvis; in the trash Gjenopprett and Slett permanent), quick edit, bulk actions (Rediger, Flytt til papirkurven, Gjenopprett, Slett permanent, Tøm papirkurven) and «Skjermalternativer» for the columns and the number per page, saved with the account.
- added«Legg til nytt» and «Rediger» open the block editor on the post or page, with a title field, «Lagre utkast» and «Publiser». «Forhåndsvis» shows the item drawn from its blocks.
- changedAn update of a post asks a service about its embeds only after the rights check, so a refused save fetches nothing.
- changedThe editor's embed preview limit (60 a minute per account) is shared by every api process when Valkey is on (
TOASCRIBE_CACHE_VALKEY_URL); the api joins thecachenetwork for it. - changedThe old administrator address gets a notice naming the new one once the change is confirmed, as in WordPress (K-192).
- changedTwo requests that make the same thing at once (a global set with the same slug, say) answer 409 to the one that loses, not 500.
- changed«Administrer plasseringer» takes only the active theme's menu locations (422 for others), and «Tilpass» stores choices for the active theme only. The api asks the site which theme that is (new variable
SITE_URL_INTERNAL, defaulthttp://site:3000). - changedA theme's «Tilpass» choices are no longer served on the public address; only the site reads them, for its own theme.
- changed«I korte trekk» on the dashboard counts published posts and pages with the content API, and links to the lists.
- changedContent routes check the right of the type: a role with only
edit_pagescan work with pages (M1.2). - changedWords of the admin now follow WordPress' Norwegian translation (nb_NO), among them «Kladd», «Hurtigrediger», «Visningsinnstillinger», «Identifikator», «Masserediger», «Gjør om» and «Vis nettsted».
- changedReleases follow toa-rules 5.0 (release-only):
scripts/release.sh X.Y.Zrunspnpm release:checkand the audit, writes the version, tags and pushesmainand the tag in one push. The tag only builds, scans and publishes the images: there is no GitHub Release any more, so an installation without a clone takesdocker/compose.yamlfrom the release tag (README, «Installer uten å klone repoet»). No git hook is required; the weekly audit workflow, Dependabot and commitlint are gone. - removedThe editor prototype's own page, its preview and its per-account draft endpoints; the editor now saves real posts and pages. The prototype's image upload is gone too (M1.2): images come from the media library.
- removedImages from another address in the editor: they will be brought into the media library first (M1.2). The admin no longer lets images in from other hosts on any page.
- securityFrom a security review of the whole product before the phase 1 release:
- securityAn application password never writes raw HTML or «Ekstra CSS», whatever the account's role: a script on the site would run in a signed-in administrator's browser.
- securityThe role every new registration gets cannot be one that manages the site, its users or its code, or writes raw HTML; the settings screen refuses it.
- securitySaving content with embeds counts against the same per-account limit as the editor's previews.
- securityErrors in the site and the admin are logged without the query string of the address and without stacks (unless
TOASCRIBE_DEBUG=1); the old encryption keys are hidden in every log line. - securityThe keys a restore takes out of a backup are removed from the backups volume after an hour;
toa secrets importrefuses a file with other names than an export writes.
v0.6.02026-10-26
- addedThe block format (
@toascribe/blocks): blocks stored as{ id, type, version, attrs, children }, ablock.jsonfor the paragraph, image, columns and column blocks, and one validation that the editor and the api share. Rich text is stored as data (text with bold, italic, code and links, and line breaks), never as HTML; links may only point tohttp:,https:,mailto:, a path on the site or an anchor. - addedThe editor prototype at
/admin/editor-prototype(accounts that can edit posts): paragraphs with their own formatting, images from an upload or an https address with alt text and a caption, and 2–4 columns. Blocks are added with the «/» menu or «+», moved with buttons or Alt+Shift+Up/Down (also into and out of columns), deleted, split with Enter and joined or removed with Backspace. Undo and redo (Ctrl+Z, Ctrl+Shift+Z) cover typing, formatting, inserting, moving and deleting in one history for the whole document. Everything works from the keyboard. - added
/admin/editor-prototype/preview: the saved draft as HTML rendered on the server from the stored blocks, without the editor. - addedPrototype endpoints under
/api/v1/prototype/editor: read and save the signed-in account's own draft (edit_posts; the blocks are checked against theirblock.jsonand refused withinvalid_blocksand the list of problems), and image uploads (upload_files; PNG, JPEG, GIF or WebP found from the file's bytes, kept in the api's temporary folder, at most 50, gone after a restart). - changedThe audit entry for a test mail that went through names the account that asked by its id, so it stays right if the username is changed before the mail is sent.
- changed
docs/PLAN.md: only the Administrator hasunfiltered_htmlby default (as decided in 0.3.0). - changedReleases come from a tag. A release now starts when the maintainer pushes a tag
vX.Y.Z; merging intomainno longer releases anything, and the release workflow no longer creates the tag. The version is raised once per release in achore(release)commit, and changes are collected under «Unreleased» in this file until then. A release can be run again with the same tag; the images and the release that already exist are left as they are. - changedCI is replaced by local checks. No workflow runs on a push or a pull request.
pnpm checkruns before every push, andpnpm release:checkruns everything CI used to do before a release, on the maintainer's machine: the workflow check, the dependency audit, the database and e-mail tests, the image build, the image scan, the stack started from the scanned images with the route checks aroundtoa core install, a dry run of the publishing, and the end-to-end tests. The dependency audit also runs weekly on GitHub. Dependabot proposes version updates once a month, one batch per ecosystem; security updates still come at once. - securityThe two editor prototype pages allow images from any https address in their Content Security Policy; every other admin page still allows only its own images.
- securityThe release workflow is split into three jobs. The job that builds and scans the images can only read the repository. Only the job that publishes can write packages, and it runs no third-party code: it takes the scanned images from the build as a checked artifact and publishes each one by the digest that was scanned, so what is published is what was scanned. The GitHub Release is made by a third job. All of them run on GitHub's own runners.
v0.5.02026-10-24
- addedThe admin shell. A sidebar menu with WordPress' positions and icons, drawn from a registry on the server (
GET /api/v1/admin/menu) that leaves out what the signed-in account may not use, so an administrator gets «Kontrollpanel» and «Brukere», and an account that cannot list users gets «Kontrollpanel» and «Profil». Code on the server can register more items, which is how later features will join the menu. A top bar with a link to the site and the «Hei, navn» menu (profile, log out). The sidebar can be collapsed to a rail of icons. - addedFour colour schemes per account (Standard, Lys, Midnatt and Hav), chosen on the profile page and applied from the first paint on every device the person signs in on.
- addedThe dashboard at
/admin: notices, a welcome panel that can be dismissed for good, and «I korte trekk» with the number of published posts and pages, the comments (approved and waiting) and the version, each shown only to an account that may see it (GET /api/v1/dashboard/glance). Notices come fromGET /api/v1/notices, and a dismissible one is hidden withPOST /api/v1/notices/{key}/dismiss(audit-logged). Two are computed from the state of the stack and cannot be dismissed: «e-post ikke testet» while no test mail has gone through with the saved mail settings, and a warning whenTOASCRIBE_TRUSTED_PROXYis empty and requests come from one private address. - addedAccount preferences (
PATCH /api/v1/me/preferences): colour scheme, whether the toolbar shows on the site, and whether the welcome panel is dismissed.GET /api/v1/mereturns them. - addedThe profile page at
/admin/profile: personal options, name, contact (an e-mail change is only made when the new address is confirmed, and until then the page shows «Venter på bekreftelse av ny e-post» with the new address), a short bio, password, two-factor and the account's sessions. - addedThe users list at
/admin/users(GET /api/v1/users) with views per role, search, sorting and paging, and role assignment for one or many accounts (PUT /api/v1/users/roles). You cannot change your own role, the last active administrator keeps the role (two requests at once cannot remove both), and nobody can grant a role that holds a capability they do not hold themselves. Every change is written to the audit log. - changedThe images are published under
ghcr.io/toaweb-development/toascribe-*(proxy, site, admin, api, postgres, mailpit), and the labels and links point atgithub.com/toaweb-development/toascribe. 0.4.1 was the last version underghcr.io/toaweb/; those images stay where they are. - changedA test mail that goes through after the install now marks e-mail as verified, as the wizard's test does, and resolves the «e-post hoppet over» notice. The worker marks it when it has sent the mail, and only if the mail settings are still the ones it sent with; a failed mail, or settings saved meanwhile, marks nothing. One function in the install package is the only code that writes the verified time, for the wizard's test and the later ones alike.
- changed
GET /api/v1/meandPATCH /api/v1/mereturnpreferencesandpendingEmail(the address of an e-mail change that waits for its confirmation link, and when the link expires, ornull). - securityThe admin's Content-Security-Policy gets a
style-src-attrthat allows five exact inline style strings by hash, with'unsafe-hashes': the width of Nuxt UI's sidebar (open and collapsed) and three strings that Reka UI writes for Nuxt UI's select, checkbox, radio group (its focus group) and visually hidden fields. They are in the HTML the server sends, so the admin uses Nuxt UI's own form controls on every screen.'unsafe-hashes'is used for style attributes only, never for scripts, and the site has none. The strings are kept in one list; a test fails when a screen draws a string that is not on it, or the list holds one that no screen draws. There is still no'unsafe-inline'and no'unsafe-eval', and a page cannot add a style attribute of its own. - securityThe setup wizard takes a
?token=query out of the address bar at once, without reading its value, so a token put in the wrong place does not stay in the history. The token still travels only in the fragment and theX-Setup-Tokenheader.
More apps
all apps →to
toawowcharA character and gear tracker for WoW Forever. Organise your roster, follow Best-in-Slot goals and import character data through the addon.
Gaming
to
toawmsA warehouse management project under development. More information will follow as the scope and solution are ready to present.
WMS