UplinkPortal
Public-core WordPress plugin for an MSP client portal: modular operations dashboard, client access control, and entitlement-backed integrations.
by UplinkPortal Contributors · github.com/uplinksync/uplinkportal · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/uplinksync/uplinkportal/archive/refs/heads/main.zipReadme
UplinkPortal
UplinkPortal is a WordPress plugin for a single-site MSP portal deployment where the MSP provider hosts the site and directs clients to it.
Product IA (Source of Truth)
Top-level admin sections:
Operations DashboardAgreements & RecordsService CatalogConfigurationTools & Diagnostics
Configuration is a single hub page with server-rendered tabs (admin.php?page=uplinkportal-settings&tab=<key>):
Client AccessModulesSecurityCompany InfoPortal Preview
Licensing is owned by Configuration > Modules > Database > Licensing.
Only canonical admin routes and submenu slugs are registered.
Admin UI Style Direction
Admin pages follow an Enterprise / Modern SaaS direction while remaining WordPress-native:
- Scoped wrapper:
.uplinkportal-admin/.msp-adminonly. - Shared tokens in
assets/css/admin-console.css(--msp-space-*,--msp-radius,--msp-border,--msp-surface,--msp-surface-muted,--msp-text,--msp-text-muted,--msp-accent). - WP patterns first (
nav-tab-wrapper,widefat, inline notices, button classes). - Module Catalog shows concise cards only: module name, short description, status, primary action.
Public-Core Boundary
This repository is public scaffolding.
- Paid/proprietary logic is not implemented here.
- Entitlement-sensitive behavior is delegated to secure backend/private add-ons.
- Add-on module cards in this repo are UI scaffolds only.
Key Runtime Components
- Entry point:
uplinkportal.php - Runtime includes:
includes/ - Admin and settings:
src/Admin/ - Client portal:
src/ClientPortal/ - Core modules and support:
src/Core/ - Worker and infra helpers:
infrastructure/
Client Access Data Model
Client access now uses custom WordPress tables (not user-meta/options for entitlement state):
*_uplinkportal_client_identity_map*_uplinkportal_client_module_access*_uplinkportal_client_feature_flags(optional feature-flag granularity)
Runtime schema management:
- Activation hook:
src/Core/Activator.php - Upgrade/runtime assurance:
includes/class-main-module.php - Store:
src/Core/Support/ClientAccessStore.php
Reference SQL:
infrastructure/wordpress/migrations/202602170001_client_access_tables.sql
Portal Preview Storage
Portal preview customization is stored in a private directory (not in public uploads):
- Store:
src/Core/Support/PortalCustomizationStore.php - Path:
wp-content/uplinkportal-private/portal-preview/
Screenshots
Development
Requirements:
- PHP
8.3+ - WordPress
6.x
Commands:
npm install --no-save cspell
composer lint
composer test
CI
Workflows:
.github/workflows/ci.yml- PHP lint
- Composer lint (PHPCS + cspell)
- PHPUnit
- repository hygiene scan (secrets/pro-boundary checks)
.github/workflows/release-plugin.yml.github/workflows/db-migrate.yml.github/workflows/deploy-worker.yml
Documentation
CI/CD
- CI (GitHub Actions): PHP lint, Composer lint (PHPCS + cspell), PHPUnit, and
a repository hygiene scan (secret + public-core boundary checks) run on every
push and pull request. See
.github/workflows/ci.yml. - Releases:
.github/workflows/release-plugin.ymlpackages tagged builds. - Database & worker:
.github/workflows/db-migrate.ymland.github/workflows/deploy-worker.ymlprovision the Supabase schema and the Cloudflare Worker used by entitlement-backed features.
main is protected: changes land through pull requests that must pass CI before
they can be merged.
Contributing
Branch from main, open a pull request, and let CI run. Add tests for behavior
changes and keep the public-core boundary intact (no proprietary/entitlement
logic in this repository). Never commit literal secrets — use CI secrets and a
runtime secret manager.
License
Distributed under the terms of the AGPL-3.0-or-later license.