sektorCMS

sektorCMS is a small content system for a personal site, written in C# with ASP.NET Core and Blazor. It is meant to be read: every part is a short file you can open and change.

It handles:

  • Projects with a description, links, platforms and downloadable releases
  • Products with a price and purchase link
  • Posts written in Markdown
  • Release files you upload once and visitors download from a stable link such as /download/my-app/latest
  • A JSON API and an admin area to manage all of it
  • Colours, fonts and hover effects set from plain JSON files

What you need

  • The .NET 10 SDK
  • MariaDB or MySQL

First run

  1. Create an empty database and a login that only has rights on it.

    CREATE DATABASE cms CHARACTER SET utf8mb4;
    CREATE USER 'cms'@'localhost' IDENTIFIED BY 'choose-a-long-password';
    GRANT ALL PRIVILEGES ON cms.* TO 'cms'@'localhost';
    
  2. Keep the password out of the code. From the project folder, store the connection string with .NET user secrets:

    dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=cms;User=cms;Password=choose-a-long-password"
    
  3. Create the tables and start the site:

    dotnet ef database update
    dotnet run
    

    On the first start the app creates one blog and a few example projects.

  4. Open /Account/Register and create your account.

  5. Make that account the site admin, then restart the app:

    dotnet user-secrets set "Setup:SuperAdminEmail" "you@example.com"
    
  6. Log in at /login and open /admin.

Settings

Set these in appsettings.json or, for anything secret, with dotnet user-secrets or environment variables (Api__Key for Api:Key).

Setting What it does
ConnectionStrings:DefaultConnection How to reach the database
Setup:SuperAdminEmail The account that gets the SuperAdmin role at startup
Api:Key Secret for changing content through the API. At least 16 characters. Leave it unset to keep the API read-only
Site:Blog Name of the blog to show when there is more than one. Defaults to the first
Storage:Path Where uploaded release files are kept. Defaults to App_Data/releases
Storage:Media Where uploaded screenshots and gifs are kept. Defaults to App_Data/media. Keep it outside the app folder on a server so updates do not remove it
Database:ServerVersion The MariaDB version the app talks to, for example 10.11.14. Defaults to 13.0.2

Where things are

Folder What is in it
Data/Classes/Objects The data classes: Project, Product, Page (a post), ReleaseFile, Blog and so on, plus ApplicationDbContext
Data/Classes/Utils The services: SiteService (what the public site shows), ReleaseStorage (uploaded files), SektorApi (the API), Seeder
Data/Migrations Database changes made with dotnet ef migrations add
Data/Style Colours.json, Theme.json and Actions.json, turned into /theme.css
Components/Pages The public pages
Components/Pages/Admin The admin pages
Components/Cms Small shared pieces: the Markdown view, the project card
Docs The Markdown files you are reading

Publishing a release

You can upload from /admin/projects (choose Releases) or from a script with the API:

curl -X POST https://example.com/api/projects/my-app/releases \
  -H "X-Api-Key: YOUR_API_KEY" \
  -F file=@MyApp-1.2.0.exe \
  -F version=1.2.0 \
  -F platform=WINDOWS \
  -F architecture=amd64

Visitors then get the newest file from /download/my-app/latest. The project page lists every version with its size and SHA-256 checksum.

Screenshots and gifs

Upload images at /admin/media. Each upload shows its address, for example /media/my-app/home.png. Paste the address into the project's Screenshots field, one per line, with an optional caption after a |:

/media/my-app/home.png | The home screen
/media/my-app/demo.gif | A short demo

The first image is also used as the cover of the project card.

Projects whose source code is private only show the downloads. Untick Source code is public on the project to hide the repository links.

Styling

Edit the JSON files in Data/Style and refresh the page. There is nothing to rebuild.

  • Colours.json gives names to colours, for example "Primary": "006BB7".
  • Theme.json sets fonts, colours and sizes per area (navigation bar, headings, links, buttons, forms, footer). The word default means "same as the Default section".
  • Actions.json sets what hover, click, focus, disabled and similar states look like.

Notes

  • Posts, descriptions and docs use Markdown. Raw HTML inside Markdown is switched off on purpose.
  • Pages and products are only shown when they are Active, Published and Public.
  • Registration is open by default. Only accounts with the SuperAdmin role can reach /admin.
An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.