The new website for the EllieBot project
  • JavaScript 63.4%
  • CSS 18.3%
  • C# 16.6%
  • Dockerfile 1.2%
  • HTML 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-06 18:25:09 +12:00
elliebot.net Updated changelog and upped version to 2.0.2. 2026-06-06 18:25:09 +12:00
.gitignore Removed staff.json from being tracked. 2026-05-17 01:09:24 +12:00
CHANGELOG.md Updated changelog and upped version to 2.0.2. 2026-06-06 18:25:09 +12:00
compose.yaml Added a user settings page as well as updated the developers page to show the avatar for a developer if they have an account with the same name, also centered the developer list card. 2026-05-18 16:20:09 +12:00
DEPLOY.md Updated the docker system hopefully? 2026-05-17 20:04:49 +12:00
Dockerfile Updated the docker system hopefully? 2026-05-17 20:04:49 +12:00
elliebot.net.conf Updated the docker system hopefully? 2026-05-17 20:04:49 +12:00
elliebot.net.sln Updated the docker system hopefully? 2026-05-17 20:04:49 +12:00
global.json Added initial project files. 2025-11-13 00:23:12 +13:00
LICENSE Made some major changes to the site and upped version to 0.2.17 and updated the changelog to match. 2026-01-08 03:14:57 +13:00
README.md Updated the readme 2026-05-21 01:45:57 +12:00

elliebot.net

A website for the EllieBot Discord bot. Built with ASP.NET Core 8 on the backend and Vue 3 (via ES modules, no build step) on the frontend.


Features

Public

  • Command reference — searchable table of all bot commands loaded from commandlist.json, with expandable rows showing usage examples, options, requirements, and submodule info. Commands display in original file order and are grouped by module via a sidebar filter.
  • Blog — published posts with full Markdown rendering, author cards with avatars, and clean slug-based URLs (/blog/my-post-title)
  • About — includes a version history timeline and a commands-per-module bar chart
  • Developers — team cards with optional uploaded avatars; single card is centred automatically
  • 404 page — unknown routes show a proper not-found page
  • Dark mode — calm dark theme throughout
  • URL routing — all pages have clean URLs via the History API; refreshing or sharing a link always lands on the correct page

Staff

  • Login — JWT-authenticated login; sessions persist across page refreshes
  • Post editor — write posts in Markdown with a live preview tab; converts to HTML on save. Supports headings, bold, italic, inline code, fenced code blocks, links, images, blockquotes, and lists
  • Staff dashboard — manage all posts (edit, delete, publish/draft status); admins also have a Team tab to add and remove staff accounts
  • User settings — each staff member can update their display name, change their password, and upload a profile avatar. Avatars appear on developer cards and blog post author cards
  • Role system — two roles: author (own posts only) and admin (all posts + team management)

Tech Stack

Layer Technology
Backend ASP.NET Core 8 minimal API
Frontend Vue 3 (ES modules, CDN — no bundler)
Auth JWT (HS256, 7-day tokens)
Storage Flat JSON files (posts, staff accounts, avatars)
Markdown Custom parser (md.js) — no dependencies
Reverse proxy nginx (host) with Let's Encrypt
Container Docker + Docker Compose

Project Structure

elliebot.net/
├── Program.cs                  # All API routes and backend logic
├── elliebot.net.csproj
├── Dockerfile
├── appsettings.json
├── libs/                       # Local JWT library DLLs
│   ├── Microsoft.IdentityModel.Abstractions.dll
│   ├── Microsoft.IdentityModel.JsonWebTokens.dll
│   ├── Microsoft.IdentityModel.Logging.dll
│   ├── Microsoft.IdentityModel.Tokens.dll
│   └── System.IdentityModel.Tokens.Jwt.dll
├── data/
│   └── staff.json              # Staff accounts (created on first run)
└── wwwroot/
    ├── index.html              # SPA shell
    ├── commandlist.json        # Bot command data
    ├── posts/                  # Blog posts — one .json file per post
    ├── avatars/                # Uploaded staff avatars
    ├── css/
    │   ├── variables.css       # Design tokens (:root CSS variables)
    │   ├── layout.css          # Nav, page shell, footer, transitions
    │   ├── components.css      # Buttons, badges, cards, module colours
    │   └── pages.css           # Per-page styles including version timeline
    └── js/
        ├── app.js              # Vue app, URL routing, nav
        ├── data.js             # Static content (features, devs, about sections)
        ├── md.js               # Markdown → HTML parser
        └── pages/
            ├── Home.js
            ├── Commands.js
            ├── About.js
            ├── Developers.js
            ├── Blog.js
            ├── BlogPost.js
            ├── Login.js
            ├── StaffDashboard.js
            ├── PostEditor.js
            ├── Settings.js
            └── NotFound.js

docker-compose.yml
nginx-elliebot.conf             # Drop into /etc/nginx/sites-available/
DEPLOY.md                       # Full deployment instructions

URL Scheme

URL Page
/ Home
/commands Command reference
/commands/:module Commands filtered to a module
/about About
/developers Developers
/blog Blog list
/blog/:slug Individual blog post
/staff/login Staff login
/staff/dashboard Post management + team admin
/staff/editor New post
/staff/editor/:id Edit existing post
/staff/settings Account settings (display name, password, avatar)

API Reference

Public

Method Endpoint Description
GET /api/commands Full command list JSON
GET /api/posts All published posts (summary fields — no body)
GET /api/posts/{slug} Single published post with full body. Also accepts id for backwards compatibility
GET /api/staff/members Public staff list — id, displayName, role, avatarUrl only

Auth

Method Endpoint Description
POST /api/auth/login Login — returns JWT token and user info
GET /api/auth/me Currently authenticated user including avatarUrl
PUT /api/auth/me Update display name and/or password — returns a fresh token
POST /api/auth/avatar Upload avatar image (jpg/png/gif/webp, max 2 MB)

Staff (requires valid JWT)

Method Endpoint Description
GET /api/staff/posts All posts — admins see all, authors see only their own
GET /api/staff/posts/{id} Single post including unpublished
POST /api/staff/posts Create a new post
PUT /api/staff/posts/{id} Update a post
DELETE /api/staff/posts/{id} Delete a post (authors can only delete their own unpublished drafts)

Admin (requires JWT with admin role)

Method Endpoint Description
GET /api/admin/staff List all staff accounts
POST /api/admin/staff Create a new staff account
DELETE /api/admin/staff/{id} Remove a staff account
POST /api/admin/staff/{id}/password Reset a staff member's password

Staff Roles

Role Permissions
author Create posts, edit and delete their own unpublished drafts, manage their own avatar and display name
admin Everything an author can do, plus publish/unpublish any post, delete any post, and manage staff accounts

Admins cannot delete their own account.


Markdown Support

Posts are written in Markdown in the editor and converted to HTML on save. Supported syntax:

Syntax Output
# Heading###### Heading <h1><h6>
**bold** or __bold__ <strong>
*italic* or _italic_ <em>
`code` <code>
```lang ... ``` <pre><code> fenced block
~~strikethrough~~ <del>
[text](url) <a>
![alt](url) <img>
> quote <blockquote>
- item / * item / + item <ul>
1. item <ol>
--- <hr>

Legacy posts saved as raw HTML before Markdown support was added are loaded and displayed as-is.


Docker Volumes

Three named volumes persist data across container rebuilds:

Volume Mount path Contents
posts_data /app/wwwroot/posts Blog post JSON files
avatars_data /app/wwwroot/avatars Staff avatar images
staff_data /app/data Staff accounts (staff.json)

Running Locally

cd elliebot.net
dotnet run

The site is available at http://localhost:5000.

On first run with no data/staff.json present, create one manually:

[
  {
    "id": "1",
    "username": "user1",
    "displayName": "Example User",
    "role": "admin",
    "passwordHash": "demo:password123"
  }
]

The demo: prefix stores the password in plain text for development. All passwords set through the UI are stored as SHA-256 hashes.


Deployment

See DEPLOY.md for full instructions. The short version:

# 1. Set a strong JWT secret in docker-compose.yml
# 2. Start the container
docker compose up -d --build

# 3. Configure nginx
sudo cp nginx-elliebot.conf /etc/nginx/sites-available/elliebot
sudo ln -s /etc/nginx/sites-available/elliebot /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

# 4. Get a certificate
sudo certbot --nginx -d yourdomain.com

Configuration

Setting Where Default Description
Jwt__Secret docker-compose.yml env Random on startup JWT signing secret — set a fixed value in production or all sessions are invalidated on every restart
ASPNETCORE_ENVIRONMENT Dockerfile / docker-compose.yml Production Set to Development for detailed error pages
ASPNETCORE_URLS Dockerfile http://+:8080 Port the app listens on inside the container

Important: always set a fixed Jwt__Secret in production. If it is left unset, a new random key is generated on each startup and all existing login sessions will be invalidated.


Updating the Command List

Replace wwwroot/commandlist.json with the updated file. The structure must be an object keyed by module name, each containing an array of command objects:

{
  "ModuleName": [
    {
      "Aliases": ["commandname", "alias"],
      "Description": "What this command does",
      "Usage": [".commandname <arg>"],
      "Submodule": "optional",
      "Module": "ModuleName",
      "Options": [],
      "Requirements": ["ManageMessages"]
    }
  ]
}

Commands are displayed in the same order they appear in the file. If running in Docker, copy the new file into the container or mount it as a volume.