Soziales Netz im Spiel: Feed, Werbung, Markt, Kalender und Gewerbe

Jeder Spieler waehlt sich ein Handle mit @, Unternehmen und Behoerden bekommen
eigene Profile, fuer die sie Mitarbeiter freigeben.

Verwaltet wird ueber dieselbe Anmeldung wie das Webhosting: wer am IC-Computer
als Anbieter angemeldet ist, richtet Unternehmensprofile ein. Damit gibt es
genau eine Stelle, an der Verwaltungsrechte haengen - ein zweites Rechtesystem
daneben waere eine zweite Stelle, an der man jemanden zu entziehen vergisst.

Bewusst getrennt: wer fuer ein Unternehmen schreiben darf, kann sich nicht
selbst zum Verwalter machen.

Behoben gegenueber dem Ausgangsstand:

  - Die Resource startete nicht. Eine harte Abhaengigkeit zeigte auf eine
    Resource, die es nicht gibt - das verhindert den Start vollstaendig.
  - Das Schema war gegenueber dem Code stehengeblieben: eine Tabelle fehlte
    ganz, sechs Spalten fehlten. Jede Registrierung eines Handles scheiterte
    deshalb mit einem SQL-Fehler. Zwei Migrationen ziehen das nach.
  - Die Identitaet kommt jetzt von ESX statt von einem Charaktersystem, das
    hier nicht laeuft. Ohne das findet das Mailsystem die Postfaecher nicht.
  - Das Fenster hatte keinen Schliessknopf, nur ESC. Im Computerfenster ist
    diese Taste aber schon vergeben.
  - Bilder laden mit referrerpolicy="no-referrer": Bilderdienste sperren
    Hotlinks anhand der Herkunft, und die eines NUI kennen sie nicht.
  - Der Schluessel fuer den Bilder-Upload steht nicht mehr im Code, sondern in
    der server.cfg (set bleeter_imgbb_key). Er gehoert nicht in ein oeffentlich
    einsehbares Repository.

Neu: Unternehmensprofile und Mitarbeiterfreigabe, ueber Netzwerkereignisse und
Konsolenbefehle. Dazu eine Oberflaeche im IC-Computer, die dieselbe Gestaltung
benutzt - die Stildatei wird dafuer mechanisch gekapselt, statt sie nachzubauen.

Enthaelt README.md mit Einrichtung, Rechten und den Fallstricken.
This commit is contained in:
Bjoern Flessing 2026-08-09 12:00:48 +00:00
commit 20076b0aee
41 changed files with 8652 additions and 0 deletions

212
sql/install.sql Normal file
View file

@ -0,0 +1,212 @@
CREATE TABLE IF NOT EXISTS bleeter_accounts (
id INT NOT NULL AUTO_INCREMENT,
char_id VARCHAR(80) NOT NULL,
identifier VARCHAR(80) NULL,
mail_address VARCHAR(120) NOT NULL,
phone_number VARCHAR(20) NULL,
status VARCHAR(24) NOT NULL DEFAULT 'active',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_char_id (char_id),
UNIQUE KEY uniq_mail_address (mail_address),
KEY idx_status (status)
);
CREATE TABLE IF NOT EXISTS bleeter_profiles (
id INT NOT NULL AUTO_INCREMENT,
account_id INT NULL,
profile_type VARCHAR(24) NOT NULL,
handle VARCHAR(40) NOT NULL,
display_name VARCHAR(80) NOT NULL,
avatar_url VARCHAR(255) NULL,
banner_url VARCHAR(255) NULL,
bio VARCHAR(500) NULL,
location VARCHAR(120) NULL,
email_contact VARCHAR(120) NULL,
phone_contact VARCHAR(20) NULL,
is_verified TINYINT(1) NOT NULL DEFAULT 0,
is_lifeinvader_staff TINYINT(1) NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_locked TINYINT(1) NOT NULL DEFAULT 0,
locked_reason VARCHAR(255) NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_handle (handle),
KEY idx_account_id (account_id),
KEY idx_profile_type (profile_type),
KEY idx_active (is_active)
);
CREATE TABLE IF NOT EXISTS bleeter_profile_members (
id INT NOT NULL AUTO_INCREMENT,
profile_id INT NOT NULL,
char_id VARCHAR(80) NOT NULL,
role VARCHAR(40) NOT NULL DEFAULT 'member',
can_post TINYINT(1) NOT NULL DEFAULT 0,
can_edit_profile TINYINT(1) NOT NULL DEFAULT 0,
can_manage_members TINYINT(1) NOT NULL DEFAULT 0,
source VARCHAR(40) NOT NULL DEFAULT 'manual',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_profile_member (profile_id, char_id),
KEY idx_char_id (char_id)
);
CREATE TABLE IF NOT EXISTS bleeter_media (
id INT NOT NULL AUTO_INCREMENT,
owner_profile_id INT NOT NULL,
source_type VARCHAR(24) NOT NULL,
url VARCHAR(500) NOT NULL,
original_name VARCHAR(180) NULL,
mime_type VARCHAR(80) NULL,
size_bytes INT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_owner (owner_profile_id),
KEY idx_source_type (source_type)
);
CREATE TABLE IF NOT EXISTS bleeter_posts (
id INT NOT NULL AUTO_INCREMENT,
author_profile_id INT NOT NULL,
feed_type VARCHAR(24) NOT NULL,
body TEXT NULL,
media_id INT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
self_deleted_at TIMESTAMP NULL DEFAULT NULL,
hidden_at TIMESTAMP NULL DEFAULT NULL,
hidden_by_profile_id INT NULL,
hidden_reason VARCHAR(255) NULL,
restore_until TIMESTAMP NULL DEFAULT NULL,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_feed_created (feed_type, created_at),
KEY idx_author_created (author_profile_id, created_at),
KEY idx_hidden (hidden_at),
KEY idx_deleted (deleted_at)
);
CREATE TABLE IF NOT EXISTS bleeter_comments (
id INT NOT NULL AUTO_INCREMENT,
post_id INT NOT NULL,
author_profile_id INT NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
self_deleted_at TIMESTAMP NULL DEFAULT NULL,
hidden_at TIMESTAMP NULL DEFAULT NULL,
hidden_by_profile_id INT NULL,
hidden_reason VARCHAR(255) NULL,
restore_until TIMESTAMP NULL DEFAULT NULL,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_post_created (post_id, created_at),
KEY idx_author_created (author_profile_id, created_at)
);
CREATE TABLE IF NOT EXISTS bleeter_likes (
id INT NOT NULL AUTO_INCREMENT,
profile_id INT NOT NULL,
target_type VARCHAR(24) NOT NULL,
target_id INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_like (profile_id, target_type, target_id),
KEY idx_target (target_type, target_id)
);
CREATE TABLE IF NOT EXISTS bleeter_follows (
id INT NOT NULL AUTO_INCREMENT,
follower_profile_id INT NOT NULL,
followed_profile_id INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_follow (follower_profile_id, followed_profile_id),
KEY idx_followed (followed_profile_id)
);
CREATE TABLE IF NOT EXISTS bleeter_blocks (
id INT NOT NULL AUTO_INCREMENT,
blocker_profile_id INT NOT NULL,
blocked_profile_id INT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_block (blocker_profile_id, blocked_profile_id),
KEY idx_blocked (blocked_profile_id)
);
CREATE TABLE IF NOT EXISTS bleeter_marketplace (
id INT NOT NULL AUTO_INCREMENT,
author_profile_id INT NOT NULL,
category VARCHAR(40) NOT NULL,
title VARCHAR(120) NOT NULL,
description TEXT NOT NULL,
price_label VARCHAR(80) NULL,
media_id INT NULL,
status VARCHAR(24) NOT NULL DEFAULT 'active',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_category_status (category, status),
KEY idx_author (author_profile_id)
);
CREATE TABLE IF NOT EXISTS bleeter_events (
id INT NOT NULL AUTO_INCREMENT,
author_profile_id INT NOT NULL,
title VARCHAR(140) NOT NULL,
description TEXT NULL,
location VARCHAR(140) NULL,
starts_at DATETIME NOT NULL,
ends_at DATETIME NULL,
status VARCHAR(24) NOT NULL DEFAULT 'active',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_starts_at (starts_at),
KEY idx_author (author_profile_id)
);
CREATE TABLE IF NOT EXISTS bleeter_business_status (
profile_id INT NOT NULL,
status VARCHAR(24) NOT NULL DEFAULT 'closed',
source VARCHAR(40) NOT NULL DEFAULT 'manual',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (profile_id),
KEY idx_status (status)
);
CREATE TABLE IF NOT EXISTS bleeter_lifeinvader_permissions (
id INT NOT NULL AUTO_INCREMENT,
char_id VARCHAR(80) NOT NULL,
permission VARCHAR(80) NOT NULL,
allowed TINYINT(1) NOT NULL DEFAULT 0,
source VARCHAR(40) NOT NULL DEFAULT 'manual',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_char_permission (char_id, permission)
);
CREATE TABLE IF NOT EXISTS bleeter_audit_logs (
id INT NOT NULL AUTO_INCREMENT,
actor_char_id VARCHAR(80) NULL,
actor_profile_id INT NULL,
action VARCHAR(80) NOT NULL,
target_type VARCHAR(40) NULL,
target_id INT NULL,
reason VARCHAR(255) NULL,
payload LONGTEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_actor_char (actor_char_id),
KEY idx_actor_profile (actor_profile_id),
KEY idx_target (target_type, target_id),
KEY idx_action (action)
);
ALTER TABLE bleeter_profiles
ADD COLUMN IF NOT EXISTS is_lifeinvader_staff TINYINT(1) NOT NULL DEFAULT 0 AFTER is_verified;

View file

@ -0,0 +1,31 @@
-- ─────────────────────────────────────────────────────────────────────────────
-- Bleeter | Spalten nachziehen
--
-- server/main.lua schreibt sechs Spalten, die in install.sql fehlen. Das
-- Schema ist gegenueber dem Code stehengeblieben die Registrierung eines
-- Handles scheitert deshalb mit einem SQL-Fehler.
--
-- bleeter_accounts.registered_at wann registriert wurde
-- bleeter_accounts.registration_mail Adresse zum Zeitpunkt der Anmeldung
-- bleeter_accounts.web_password_hash Zugang zum Web-Backend
-- bleeter_accounts.web_password_updated_at
-- bleeter_profiles.owner_source woher das Profil stammt
-- bleeter_profiles.created_by_char_id wer es angelegt hat
--
-- Wiederholbar ausfuehrbar.
-- ─────────────────────────────────────────────────────────────────────────────
ALTER TABLE `bleeter_accounts`
ADD COLUMN IF NOT EXISTS `registered_at` TIMESTAMP NULL DEFAULT NULL,
ADD COLUMN IF NOT EXISTS `registration_mail` VARCHAR(120) NULL DEFAULT NULL,
ADD COLUMN IF NOT EXISTS `web_password_hash` VARCHAR(255) NULL DEFAULT NULL
COMMENT 'Zugang zum Web-Backend, nie im Klartext',
ADD COLUMN IF NOT EXISTS `web_password_updated_at` TIMESTAMP NULL DEFAULT NULL;
ALTER TABLE `bleeter_profiles`
ADD COLUMN IF NOT EXISTS `owner_source` VARCHAR(40) NOT NULL DEFAULT 'personal'
COMMENT 'personal | lifeinvader | superpc woher das Profil stammt',
ADD COLUMN IF NOT EXISTS `created_by_char_id` VARCHAR(80) NULL DEFAULT NULL;
ALTER TABLE `bleeter_profiles`
ADD INDEX IF NOT EXISTS `idx_owner_source` (`owner_source`);

View file

@ -0,0 +1,38 @@
-- ─────────────────────────────────────────────────────────────────────────────
-- Bleeter | Reservierte Handles
--
-- server/main.lua fragt diese Tabelle bei jeder Registrierung ab, sie fehlt
-- aber in install.sql. Ohne sie scheitert die Abfrage und damit jede
-- Registrierung eines Spielerhandles.
--
-- Vorbelegt sind Namen, unter denen sich sonst jemand als Behoerde, Anbieter
-- oder Systemkonto ausgeben koennte. Wer sie vergeben will, nimmt sie hier
-- heraus oder der Anbieter legt das Profil selbst an, das umgeht die Liste
-- bewusst nicht.
--
-- Wiederholbar ausfuehrbar.
-- ─────────────────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS `bleeter_reserved_handles` (
`handle` VARCHAR(40) NOT NULL,
`reason` VARCHAR(200) NOT NULL DEFAULT '',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`handle`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT IGNORE INTO `bleeter_reserved_handles` (`handle`, `reason`) VALUES
('lifeinvader', 'Plattformbetreiber'),
('bleeter', 'Plattformname'),
('admin', 'Verwaltung'),
('support', 'Verwaltung'),
('system', 'Verwaltung'),
('lspd', 'Behörde'),
('police', 'Behörde'),
('lsmd', 'Behörde'),
('ambulance', 'Behörde'),
('lsfd', 'Behörde'),
('doj', 'Behörde'),
('gov', 'Behörde'),
('government', 'Behörde'),
('weazel', 'Presse'),
('weazelnews', 'Presse');