Usage

Working in the admin panel: posts and Markdown, albums and file uploads, authors and tags, SEO, short links, protection mode, the audit log and roles.

All content work happens through /dashboard. You never need to touch code for anything except the static pages (history, about, projects, educational programmes) — their markup lives in the templates.

Logging in and roles#

The panel opens at /auth. After logging in the user lands on /dashboard.

RoleValue in the databaseWhat it can reach
ModeratorROLE_MODERATORposts, media, authors, tags
AdministratorROLE_ADMINall of the above plus users, SEO, site settings, the log, protection mode, cache clearing

The split is enforced at the controller level: "content" operations live in StaffController and accept either role, "administrative" ones live in AdminController behind a check for ROLE_ADMIN specifically.

Заметка

The role is a plain string set when the user is created, and you must type the full value — ROLE_ADMIN or ROLE_MODERATOR. A typo raises no error: the user is created, can log in, and then gets a 403 on every page of the panel.

The password must contain at least 8 characters, at least one Latin letter and at least one digit; the login must be at least 4 characters. When editing a user, an empty password field means "keep the current one", not "clear it".

The last administrator cannot be deleted — the server returns 406 and explains why.

The order to fill things in#

The dependencies between entities are strict: a post and an album must have an author, so authors come first and everything else after.

1. Authors mandatory, nothing works without them 2. Tags optional 3. Posts and albums exactly one author each 4. SEO page titles 5. Go live lift protection

Authors#

/dashboard/authors. An author has a name (2–30 characters) and an optional "about" text. On the site this produces a page at /author?id=N listing all of their posts and albums, newest first.

Осторожно

Deleting an author deletes all of their content. The relationship is configured with orphanRemoval, so every post and every album record belonging to the author goes away with them. The photo directories are left behind on disk as orphans and have to be removed by hand. If all you want is to rename someone, edit the author rather than creating a new one.

Tags#

/dashboard/tags. A tag name is 2–30 characters and must be unique; the description starts at 4 characters. A tag is shared between posts and albums, and its page is /tag?id=N.

Deleting a tag is safe: its links to posts and albums are severed automatically beforehand, and the content itself stays where it is.

Posts#

/dashboard/posts. The fields:

FieldConstraintWhere it shows
Title4–50 charactersin the card, in the page title
Introductionfrom 4 charactersin the feed card and in the social preview
BodyMarkdown, requiredon the /records/read?id=N page
TypeNEWS, STORY, ANNOUNCEMENTas a localized display label
Authorexactly one, requiredas a link under the title
Tagsany number, optionalin the card and in the filters

The date is set automatically at creation time and cannot be edited. The "published by" field is filled with the name of the signed-in staff member — which is not the same thing as the author: the author is whose name appears on the site, "published by" is whoever pressed the button. The latter is only visible inside the panel.

The body of a post#

The body is written in Markdown in the EasyMDE editor. An important characteristic: Markdown is turned into HTML in the reader's browser, not on the server. The database holds the original Markdown, the /records/read page serves it as-is, and marked.js renders it on the client.

Two practical consequences follow:

  • HTML inside Markdown works — you can drop in a table, a <details> block or a YouTube clip. The sources you are allowed to embed are limited by the content security policy: YouTube, Rutube, Instagram, Telegram, MAX;
  • dangerous tags are stripped — with protection enabled the client-side sanitizer throws out script, iframe, form, object, svg, event handlers such as onclick, and links using the javascript: and data: schemes.

Внимание

iframe is on the list of stripped tags. That means embedding a video directly into the body of a post will not work while protection is enabled — the sanitizer removes it. Turning protection off for the sake of this is a bad trade: without it anyone who can edit posts gains the ability to run arbitrary scripts in every visitor's browser.

Editing a post changes the title, introduction, body and type. The author and tags of an existing post cannot be changed through the edit form — the edit handler ignores those fields.

Albums: photo and video#

/dashboard/media. This is the least obvious part of the workflow, so here it is step by step.

Open the form browser generates a UUID batchId Drag the files in each one goes as its own request POST /dashboard/media/upload Files on disk media/batchId/preview.jpg media/batchId/01.jpg ... only now press "Create" Database record: title, type, author, tags, batchId the gallery itself is not stored — it is read from the directory when the page opens
  1. Open the creation form. The browser immediately generates a batchId — a random UUID. This is the future directory name on disk and the only link between the database record and the files.
  2. Upload the cover. A separate drop zone that accepts exactly one file and only .jpg, up to 15 MB. The file is always saved as preview.jpg no matter what it was called on your machine. This is the album's cover in the feeds.
  3. Upload the contents. The second drop zone accepts images and video. Files go up one at a time and keep their names.
  4. Fill in the fields and press "Create". The title is 4–50 characters, the type is PHOTO or VIDEO, there is exactly one author, and tags are optional.

Важно

The order really is that: the files are physically on disk by the time the record is created. If you close the form without pressing "Create", the directory with the uploaded files stays on the server with no record pointing at it — leftover data that can only be removed from the filesystem by hand.

Things worth knowing about the gallery:

  • file order is alphabetical. The only way to control it is through names, so number them: 01-..., 02-.... Otherwise 10 sorts before 2;
  • preview.jpg never appears in the gallery — it is always excluded from the listing;
  • a cover is not mandatory. Without preview.jpg the fallback image from web.storage.default-preview is used, but the album will look anonymous;
  • the type selects the template, not the contents. An album typed VIDEO opens in a video player; a request to /media/album?id=N for a video album forwards itself to the right template, so you cannot get the link wrong;
  • editing an album changes only the title and the type. The edit form does not touch the author, the tags or the set of files.

Deleting an album deletes the files from disk — the whole batchId directory, irreversibly. It is the only operation in the panel that physically erases data.

SEO#

/dashboard/seo. A title and a meta description are stored for each address. There are two kinds of entry:

Ordinary pages/, /records, /media, /history, /about, /education, /projects. The title and description are used verbatim.

Templates for dynamic pages/media/album, /media/video_album, /media/read, /author, /tag. These support placeholders that are replaced with the data of the specific item:

PlaceholderValueWhere it is available
<title>the post or album titlealbums, posts
<author>the author's namealbums, posts
<date>the publication datealbums, posts
<type>the post typeposts
<name>the author's name or the tag nameauthor and tag pages

For example, the template <title> | PHOTO | Our site applied to an album called "Summer trip" yields Summer trip | PHOTO | Our site.

Заметка

Only title and description are editable through the panel. Keywords, the Schema.org type and the parent page used for breadcrumbs are set in code on first startup, and changing them means editing properties.json by hand (with a restart afterwards) or editing the sources.

sitemap.xml is assembled automatically and includes every static page, every author, every tag, every post and every album. It is cached for an hour — new material shows up in the sitemap either after that hour or immediately after a cache clear.

Site settings#

All of this is on the panel's front page, /dashboard, and is available to administrators only.

Contacts — phone, address, e-mail. Displayed in the footer and included in the Organization markup for search engines.

Social links — a list of links with a name, a description and an icon. The icon is given as a path to a file, for example /assets/icons/telegram.svg. Deletion looks the link up by name, so avoid two entries with the same name.

Notification banner — a strip of text shown on every page. Toggled with a checkbox, the text is arbitrary. Handy for things like "Registration is open until 15 August".

Short links — "from → to" pairs. Add /camp → /records/read?id=42 and you get a working address at example.org/go/camp. Case does not matter: both the key and the request are lowercased. Technically this is not a redirect but an internal forward — the address bar keeps showing /go/camp, which is convenient for printed materials and QR codes.

Clear cache — a single button that flushes the caches for posts, albums, authors, tags and the sitemap. Needed if you edited properties.json outside the panel, or if you want to see changes right away.

Protection mode#

While the site is being filled in, the public part can be closed off. It is toggled with a checkbox in /dashboard, which also holds a ready-made link with the token — you can send that to a client for acceptance testing.

request Protection on? Staff? Service address? Session marker? yes no the site opens ?token=... valid? remembered in the session yes let through locked .html

Points that matter:

  • the token is remembered in the session. Open the token link once and you browse the rest of the site without it. The token itself is stripped from the address bar by a redirect so it does not leak through browser history or somebody else's screenshot;
  • staff always pass, so locking yourself out is impossible;
  • the panel stays reachable/auth, /process_login, /dashboard, the error page, robots.txt and the icons are not part of what gets closed;
  • the token can be reissued with a button in the panel: earlier links stop working, though sessions that are already open keep their access until they expire;
  • protection is not meant for guarding secrets. It is a screen against casual visitors and crawlers, not an access control system.

The audit log#

/dashboard/journal, administrators only. Every significant operation in the panel is recorded: who, what, when and with which arguments. Successful and failed logins are logged separately.

Passwords never reach the log — ****** is written instead of the value. The body of a post is not written in full either, to keep the log from ballooning.

Log entries have no lifetime and accumulate indefinitely. For a site with a few editors that is not a problem, but clearing out the action_logs table from time to time is worthwhile.

What the panel cannot change#

An honest list of what requires going into the code and rebuilding:

  • the text and layout of the history, about, projects and educational programmes pages — these are Thymeleaf templates with the content written into the markup;
  • the domain in robots.txt;
  • keywords, Schema.org types and the breadcrumb structure;
  • the design, colours and fonts — plain CSS in src/main/resources/static/assets/;
  • the page size in the feeds (page-size, 6 by default) and the cache lifetime.

Совет

Template edits can also be made without rebuilding: uncomment spring.thymeleaf.prefix=file:/opt/OtryadWebsite/templates/ and the application will read templates from a directory on disk. Handy for quick text fixes, but keep an eye on that directory not drifting away from the code version.