chore: restructure repo to /root/lexton-it/NextWks/ with src/ + app/ layout and install.sh

This commit is contained in:
Claus Lohmar 2026-06-14 13:11:56 +00:00
parent ed68a8c51a
commit e3fbe0f9d9
5 changed files with 255 additions and 16 deletions

17
.gitignore vendored
View file

@ -1,8 +1,9 @@
# Binaries # Binaries
/bin/ app/core
/data/*.db app/core.exe
/data/*.db-wal app/data/*.db
/data/*.db-shm app/data/*.db-wal
app/data/*.db-shm
# OS files # OS files
.DS_Store .DS_Store
@ -18,8 +19,6 @@ Thumbs.db
.env .env
.env.local .env.local
# Setup check binary # Generated binaries (development build)
src/setupcheck src/core/setupcheck
src/setupcheck.exe src/core/setupcheck.exe

View file

@ -1,16 +1,17 @@
# Next Workspace (NextWks) Configuration # Next Workspace (NextWks) - Development Configuration
# Path: /opt/nextwks/config.yaml # Path: ./config.yaml (relative to binary)
# For production, install.sh deploys to /opt/nextwks/config.yaml
server: server:
host: "0.0.0.0" host: "0.0.0.0"
port: 8080 port: 8080
admin: admin:
secret_token: "CHANGE_ME_ADMIN_SECRET_TOKEN" secret_token: "dev-admin-secret-token"
database: database:
type: "sqlite" type: "sqlite"
path: "/opt/nextwks/data/nextwks.db" path: "./data/nextwks.db"
authelia: authelia:
host: "http://127.0.0.1:9091" host: "http://127.0.0.1:9091"
@ -25,5 +26,5 @@ smtp:
from: "noreply@nextwks.local" from: "noreply@nextwks.local"
session: session:
secret: "CHANGE_ME_SESSION_SECRET" secret: "dev-session-secret"
expiry_minutes: 60 expiry_minutes: 60

206
install.sh Executable file
View file

@ -0,0 +1,206 @@
#!/bin/bash
# Next Workspace (NextWks) - Bare-Metal Installer
# Deploys compiled binaries to /opt/nextwks/ for production use
#
# Usage:
# ./install.sh # Build and install
# ./install.sh --skip-build # Install existing binaries only
# ./install.sh --config-only # Generate config only
# ./install.sh --uninstall # Remove installation
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
error() { echo -e "${RED}Error:${NC} $1" >&2; }
success() { echo -e "${GREEN}$1${NC}"; }
info() { echo -e "${BLUE}$1${NC}"; }
warn() { echo -e "${YELLOW}Warning:${NC} $1"; }
# Configuration
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
INSTALL_DIR="/opt/nextwks"
BIN_DIR="${INSTALL_DIR}/bin"
DATA_DIR="${INSTALL_DIR}/data"
MODULES_DIR="${INSTALL_DIR}/modules"
CONFIG_FILE="${INSTALL_DIR}/config.yaml"
SERVICE_FILE="/etc/systemd/system/nextwks.service"
# Parse arguments
SKIP_BUILD=false
CONFIG_ONLY=false
UNINSTALL=false
for arg in "$@"; do
case "$arg" in
--skip-build) SKIP_BUILD=true ;;
--config-only) CONFIG_ONLY=true ;;
--uninstall) UNINSTALL=true ;;
*) error "Unknown argument: $arg"; exit 1 ;;
esac
done
# --- Uninstall ---
if [ "$UNINSTALL" = true ]; then
info "Uninstalling Next Workspace..."
if [ -f "$SERVICE_FILE" ]; then
systemctl stop nextwks 2>/dev/null || true
systemctl disable nextwks 2>/dev/null || true
rm -f "$SERVICE_FILE"
systemctl daemon-reload
info "Removed systemd service"
fi
if [ -d "$INSTALL_DIR" ]; then
rm -rf "$INSTALL_DIR"
success "Removed $INSTALL_DIR"
else
info "No installation found at $INSTALL_DIR"
fi
success "Uninstall complete"
exit 0
fi
# --- Build ---
if [ "$SKIP_BUILD" = false ] && [ "$CONFIG_ONLY" = false ]; then
info "Building Next Workspace core..."
if ! command -v go &>/dev/null; then
error "Go is not installed. Install Go 1.22+ first."
exit 1
fi
cd "$REPO_DIR/src"
# Build the core binary
go build -o "$REPO_DIR/app/core" -ldflags="-s -w" .
success "Core binary built: app/core"
fi
# --- Install ---
if [ "$CONFIG_ONLY" = false ]; then
info "Installing to $INSTALL_DIR..."
# Create directory structure
mkdir -p "$BIN_DIR" "$DATA_DIR" "$MODULES_DIR"
# Copy binary
if [ -f "$REPO_DIR/app/core" ]; then
cp "$REPO_DIR/app/core" "$BIN_DIR/core"
chmod 755 "$BIN_DIR/core"
success "Installed binary to $BIN_DIR/core"
else
error "Binary not found. Run without --skip-build or build manually."
exit 1
fi
# Copy modules if any exist
if [ -d "$REPO_DIR/app/modules" ] && [ "$(ls -A "$REPO_DIR/app/modules" 2>/dev/null)" ]; then
cp -r "$REPO_DIR/app/modules"/* "$MODULES_DIR/"
success "Installed modules"
fi
fi
# --- Configuration ---
info "Generating configuration..."
if [ ! -f "$CONFIG_FILE" ]; then
# Generate unique secrets
ADMIN_SECRET=$(openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | xxd -p -c 32)
SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | xxd -p -c 32)
cat > "$CONFIG_FILE" << CONFIGEOF
# Next Workspace (NextWks) - Production Configuration
# Auto-generated by install.sh on $(date)
server:
host: "0.0.0.0"
port: 8080
admin:
secret_token: "${ADMIN_SECRET}"
database:
type: "sqlite"
path: "${DATA_DIR}/nextwks.db"
authelia:
host: "http://127.0.0.1:9091"
config_path: "/opt/authelia/config/configuration.yml"
users_db_path: "/opt/authelia/data/users_database.yml"
smtp:
host: ""
port: 587
username: ""
password: ""
from: "noreply@nextwks.local"
session:
secret: "${SESSION_SECRET}"
expiry_minutes: 60
CONFIGEOF
chmod 600 "$CONFIG_FILE"
success "Configuration generated: $CONFIG_FILE"
warn "Admin secret token: ${ADMIN_SECRET}"
warn "Save this token! You need it for admin API access."
else
info "Configuration already exists at $CONFIG_FILE (not overwritten)"
fi
# --- Systemd Service ---
if [ "$CONFIG_ONLY" = false ]; then
info "Setting up systemd service..."
cat > "$SERVICE_FILE" << SERVICEEOF
[Unit]
Description=Next Workspace (NextWks) Core
After=network.target authelia.service
Wants=authelia.service
[Service]
Type=simple
User=root
WorkingDirectory=${INSTALL_DIR}
ExecStart=${BIN_DIR}/core -config ${CONFIG_FILE}
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
SERVICEEOF
systemctl daemon-reload
success "Systemd service created: $SERVICE_FILE"
info "Enable with: systemctl enable --now nextwks"
info "Start with: systemctl start nextwks"
info "Status with: systemctl status nextwks"
fi
# --- Summary ---
echo ""
success "═══════════════════════════════════════════"
success " Next Workspace (NextWks) installed!"
success "═══════════════════════════════════════════"
echo ""
info " Binary: ${BIN_DIR}/core"
info " Config: ${CONFIG_FILE}"
info " Data: ${DATA_DIR}/"
info " Service: nextwks"
echo ""
info " Admin UI: http://localhost:8080/admin"
info " Health API: http://localhost:8080/api/health"
echo ""
info " Start with: systemctl start nextwks"
info " Logs: journalctl -u nextwks -f"
echo ""

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
@ -15,10 +16,15 @@ import (
func main() { func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})) logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
logger.Info("starting Next Workspace (NextWks)")
// Config path: default to ./config.yaml for dev, override with -config for production
configPath := flag.String("config", "./config.yaml", "path to configuration file")
flag.Parse()
logger.Info("starting Next Workspace (NextWks)", "config", *configPath)
// Load configuration // Load configuration
cfg, err := config.Load("/opt/nextwks/config.yaml") cfg, err := config.Load(*configPath)
if err != nil { if err != nil {
logger.Error("failed to load config", "error", err) logger.Error("failed to load config", "error", err)
os.Exit(1) os.Exit(1)

27
testdata/authelia/configuration.yml vendored Normal file
View file

@ -0,0 +1,27 @@
# Authelia Configuration (Development Mock)
# Path: used for testing config parsing
host: 0.0.0.0
port: 9091
log:
level: debug
jwt_secret: dev-jwt-secret-change-in-production
session:
name: authelia_session
secret: dev-authelia-session-secret-please-change
expiration: 1h
inactivity: 5m
storage:
local:
path: /opt/authelia/data/db.sqlite
access_control:
default_policy: deny
authentication_backend:
file:
path: /opt/authelia/data/users_database.yml