diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index efc97bd..ddfc38f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: run: python3 scripts/verify-local.py mysql-integration: - name: API v2 + updater MySQL integration + name: API v2 + updater + dashboard MySQL integration runs-on: ubuntu-latest services: mysql: @@ -84,6 +84,7 @@ jobs: php tests/api_v2_db_integration.php php tests/admin_v2_ui_db_integration.php php tests/updater_db_integration.php + php tests/dashboard_db_integration.php windows-python-contract: name: Windows Python builder portability @@ -133,18 +134,18 @@ jobs: run: | short_sha="${GITHUB_SHA:0:12}" mkdir -p release - bash scripts/package-release.sh v5.5.1 "$GITHUB_SHA" "release/Licora-5.5.1-ci-${short_sha}.zip" - cp "release/Licora-5.5.1-ci-${short_sha}.zip" "release/Licora-5.5.1.zip" - python3 scripts/build-update-manifest.py --version 5.5.1 --ref "$GITHUB_SHA" --package "release/Licora-5.5.1.zip" --output release/licora-update-manifest.json - rm "release/Licora-5.5.1.zip" + bash scripts/package-release.sh v5.6.1 "$GITHUB_SHA" "release/Licora-5.6.1-ci-${short_sha}.zip" + cp "release/Licora-5.6.1-ci-${short_sha}.zip" "release/Licora-5.6.1.zip" + python3 scripts/build-update-manifest.py --version 5.6.1 --ref "$GITHUB_SHA" --package "release/Licora-5.6.1.zip" --output release/licora-update-manifest.json + rm "release/Licora-5.6.1.zip" - name: Upload CI release-candidate artifact uses: actions/upload-artifact@v6 with: - name: Licora-5.5.1-${{ github.sha }} + name: Licora-5.6.1-${{ github.sha }} path: | - release/Licora-5.5.1-ci-*.zip - release/Licora-5.5.1-ci-*.zip.sha256 + release/Licora-5.6.1-ci-*.zip + release/Licora-5.6.1-ci-*.zip.sha256 release/licora-update-manifest.json if-no-files-found: error retention-days: 14 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 100d24d..8b94a3b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,7 +61,7 @@ jobs: - name: Full source verification run: python3 scripts/verify-local.py - - name: API v2 and updater database integration + - name: API v2, updater and dashboard database integration env: LICORA_V2_TEST_ALLOW_SCHEMA_RESET: '1' LICORA_TEST_DB_DSN: mysql:host=127.0.0.1;port=3306;dbname=licora_test;charset=utf8mb4 @@ -76,6 +76,7 @@ jobs: php tests/api_v2_db_integration.php php tests/admin_v2_ui_db_integration.php php tests/updater_db_integration.php + php tests/dashboard_db_integration.php - name: Build exact-tag release ZIP and checksum shell: bash diff --git a/BASELINE_v5.6.1.md b/BASELINE_v5.6.1.md new file mode 100644 index 0000000..c708699 --- /dev/null +++ b/BASELINE_v5.6.1.md @@ -0,0 +1,36 @@ +# Licora v5.6.1 — Next Source Baseline Freeze + +## Freeze Status + +- Version: `5.6.1` +- Freeze type: **Verified source baseline freeze — Phase 1 COMPLETE + VERIFIED** +- Parent Official Baseline Freeze: `Licora_v5.6.0_Baseline.zip` +- Parent ZIP SHA-256: `ba99c6e4fd74c2b59d392c3010b3aefe493390b3b0b0c94bd3c211218f14d597` +- Parent Git commit: `5c685636e955422bc70e3bf07694f55d9c7fb1dc` +- Parent Git tree: `848801c1785ebba0b2523a34afcf6af3ee05d5d6` +- Database migration: `NONE` +- Deleted files: `NONE` +- External API v1/v2 contract change: `NONE` +- Phase 2 implementation: `NONE` + +## Frozen Corrective Scope + +This source freeze contains only the verified Phase 1 corrective scope: + +1. foreign-key-safe Dashboard MySQL integration fixture isolation; +2. exact top-level Dashboard `recent_activity` contract parity; +3. API v2 readiness based on complete schema plus valid matching signing key pair; +4. v5.6.1 version/release/CI/documentation alignment; +5. browser-agnostic runtime verification guard after confirming no Chrome installer/downloader exists in Licora source. + +## Local Verification + +`python3 scripts/verify-local.py` passed after the corrective runtime/test changes. The targeted release-readiness check also passed after final publication-status documentation correction. Final `git diff --check` and delta extraction/hash parity are recorded in the v5.6.1 delta manifest. + +Environment-dependent DB tests were skipped locally where the dedicated test database was unavailable. The mandatory remote acceptance gate was then satisfied by PR #8 Actions run `32423210356`: MySQL integration, PHP 8.0–8.4, Windows Python portability, and verified source artifact jobs all passed. + +## GitHub/Release Status + +The verified v5.6.1 Phase 1 implementation commit is `ab085ae1738ef49be506cb10ae2353799108a969`. PR #8 Actions run `32423210356` completed successfully. `v5.6.0` was not published as a GitHub tag/release. + +Phase 1 is `COMPLETE + VERIFIED`. Phase 2 is `NOT STARTED`. This documentation-completion delta records the passed remote gate; after it is committed/pushed and the resulting PR CI remains green, PR #8 can be merged into `main`, followed by the v5.6.1 tag/release flow. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0922fc5..3f5ef28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,32 @@ All notable public-release changes are recorded here. Historical project notes r ### Planned -- Continue reviewed Zero Freedom development after the v5.1.0 installer release. +- Continue the reviewed Dashboard production program with Phase 2: compact UI and reload-free refresh. + +## [5.6.1] - 2026-08-20 + +### Fixed +- Corrected the Dashboard MySQL integration test cleanup so prior API v2 foreign-key tables are removed safely before the dashboard fixture is created. +- Aligned the implemented Dashboard JSON response with the declared top-level `recent_activity` contract while preserving separate API v1 and API v2 tracked sources. +- Tightened Dashboard API v2 readiness so `Ready` now requires the complete v2 schema and a readable, cryptographically matching private/public signing key pair; only readiness booleans are exposed to the browser. +- Added a runtime source guard confirming Licora does not require or download Google Chrome; Licora remains browser-agnostic server software. + +### Compatibility +- No database migration, deleted files, external API contract change, license/device enforcement change, Cron mutation change, updater protocol change, or Phase 2 polling/UI implementation. +- Signed update compatibility accepts both the official v5.5.1 source and an already-applied v5.6.0 baseline. + +## [5.6.0] - 2026-08-20 (unreleased source baseline; superseded by 5.6.1) + +### Added +- Added a centralized read-only Dashboard data model and authenticated `GET /admin/ajax/dashboard-data.php` JSON endpoint. +- Added explicit license, device, API v1/API v2, expiration and measured health/config reporting semantics. +- Added Dashboard contract/MySQL integration tests and made the Dashboard DB test mandatory in CI/tagged-release MySQL gates. + +### Fixed +- Replaced misleading Dashboard health labels with measured facts, separated API v1 and Secure API v2 tracked activity, split past/future expiration data, and changed device reporting from an active flag to explicit recently-seen semantics. + +### Compatibility +- No database migration or deleted files. Signed direct source is `v5.5.1`; external API contracts, license/device enforcement, authentication/roles, Cron mutation behavior and updater protocol/state machine remain unchanged. The existing 30-second full-page Dashboard reload remains intentionally in Phase 1 for Phase 2 replacement. ## [5.5.1] - 2026-08-18 diff --git a/DASHBOARD_PRODUCTION_UPDATE_INDEX.md b/DASHBOARD_PRODUCTION_UPDATE_INDEX.md new file mode 100644 index 0000000..28b2ac8 --- /dev/null +++ b/DASHBOARD_PRODUCTION_UPDATE_INDEX.md @@ -0,0 +1,49 @@ +# Licora Dashboard Production Update — Documentation Index + +## Authority + +এই documentation program v5.5.1 থেকে শুরু হয়েছিল; বর্তমান corrective source authority হলো uploaded **Licora v5.6.0 Official Baseline Freeze**। + +- Current baseline ZIP SHA-256: `ba99c6e4fd74c2b59d392c3010b3aefe493390b3b0b0c94bd3c211218f14d597` +- Current baseline Git commit: `5c685636e955422bc70e3bf07694f55d9c7fb1dc` +- Current baseline Git tree: `848801c1785ebba0b2523a34afcf6af3ee05d5d6` +- Current baseline version: `5.6.0` +- Original Phase-program baseline: `v5.5.1 / 2f48ef569e6c532ab0de974a418c644e4ea8423f` +- Development implementation status: **v5.6.1 Phase 1 COMPLETE + VERIFIED — PR #8 Actions run 32423210356 PASS** +- Planned update phases: **2** +- Current corrective target: **v5.6.1 — Phase 1 verified baseline; Phase 2 NOT STARTED** + +এই document set Phase 1 runtime implementation এবং v5.6.1 corrective verification state record করে। v5.6.1 কোনো database migration, external API contract change, license/device enforcement change, Cron mutation change, updater protocol change বা Phase 2 polling/UI feature যোগ করে না। + +## Document Map + +| Document | Purpose | +|---|---| +| `audit/V5.5.1_DASHBOARD_PRODUCTION_READINESS_FORENSIC_REPORT.md` | Baseline forensic findings, production-readiness gaps, scope boundary | +| `docs/DASHBOARD_PRODUCTION_ROADMAP_2_PHASE.md` | A–Z implementation roadmap, maximum 2 phases | +| `docs/DASHBOARD_UPDATE_PHASE_LOG.md` | Phase completion ledger and continuation point | +| `docs/ERROR_HANDLING_BASELINE_AND_TARGET.md` | Existing error handling + required additions | +| `docs/ACTUAL_IMPLEMENTATION_LEDGER.md` | What actually works now, what becomes working after each phase, what remains | +| `docs/DASHBOARD_DATA_CONTRACT.md` | Exact implemented read-only dashboard data semantics and AJAX response contract | +| `docs/DASHBOARD_PRODUCTION_VALIDATION_GATES.md` | Automated/manual acceptance gates before phase completion/release | +| `docs/DASHBOARD_CHANGE_CONTROL.md` | Freeze rules, decision rules, no-scope-creep rules, rollback discipline | +| `audit/DASHBOARD_PRODUCTION_DOCS_DELTA_MANIFEST.md` | Documentation delta contents and extraction instructions | +| `audit/DASHBOARD_PRODUCTION_DOCS_DELTA_SHA256SUMS.txt` | SHA-256 checksums for every file in this patch | + +## Mandatory Working Order + +1. Baseline Freeze remains immutable. +2. Read forensic report. +3. Read exact data contract. +4. Implement **Phase 1 only**. +5. Run Phase 1 validation gates. +6. Update `DASHBOARD_UPDATE_PHASE_LOG.md` and `ACTUAL_IMPLEMENTATION_LEDGER.md`. +7. Only after Phase 1 is verified, implement **Phase 2**. +8. Run final production gates. +9. Update logs/ledger. +10. Only then prepare a runtime delta/release. + +## Continuation Rule + +যে phase `COMPLETE + VERIFIED` নয় সেটিকে completed ধরা যাবে না। +যে feature source/tests দিয়ে verify হয়নি সেটিকে `ACTUAL WORKING` লেখা যাবে না। diff --git a/README.md b/README.md index 6523323..749738e 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ The application accepts deployment-specific values through environment variables | Database password | `LICENSE_DB_PASS` | empty | | Application name | `APP_NAME` | `Licora` | | Application URL | `APP_URL` | `http://localhost` | -| Application version | `APP_VERSION` | `5.5.1` | +| Application version | `APP_VERSION` | `5.6.1` | | Environment | `APP_ENV` | `production` | | Encryption key | `LICENSE_ENCRYPTION_KEY` | empty fallback | | API limit | `API_RATE_LIMIT` | `1000` | @@ -155,6 +155,8 @@ The validation script checks PHP syntax, security behavior, compatibility invari - [Secure in-app updater](docs/UPDATER.md) - [UI design system](docs/UI_DESIGN_SYSTEM.md) - [Troubleshooting](docs/TROUBLESHOOTING.md) +- [v5.6.1 release notes](RELEASE_NOTES_v5.6.1.md) +- [v5.6.0 release notes](RELEASE_NOTES_v5.6.0.md) - [v5.5.1 release notes](RELEASE_NOTES_v5.5.1.md) - [v5.5.0 release notes](RELEASE_NOTES_v5.5.0.md) - [v5.4.1 release notes](RELEASE_NOTES_v5.4.1.md) @@ -171,6 +173,14 @@ The validation script checks PHP syntax, security behavior, compatibility invari - [Dependency review](audit/DEPENDENCY_REPORT.md) +## Phase 1 verification corrective update (v5.6.1) + +Licora v5.6.1 is a no-migration corrective update over the applied v5.6.0 Phase 1 source baseline; v5.6.0 was not published as a GitHub tag/release and is superseded by v5.6.1. It fixes the MySQL integration-test foreign-key cleanup exposed by PR #8 CI, aligns the authenticated Dashboard JSON envelope with its documented top-level `recent_activity` field, and makes the Dashboard API v2 `Ready` status depend on a verified matching server signing key pair rather than the public key alone. Licora remains a browser-based PHP application and contains no Google Chrome installer/downloader dependency. Phase 2 reload-free polling/UI work remains unimplemented. + +## Dashboard data truth and read model (v5.6.0) + +Licora v5.6.0 completes Phase 1 of the Dashboard production program without changing external API, license/device enforcement, database schema, Cron mutation or updater contracts. Dashboard initial rendering now uses a centralized read-only data model; an authenticated GET-only JSON endpoint exposes the same safe snapshot for the Phase 2 reload-free controller. API v1 `api_logs` and Secure API v2 `v2_audit_logs` are reported as distinct tracked sources, expiration data separates past from upcoming expirations, device reporting distinguishes active flags from five-minute recently-seen activity, and hardcoded operational-health claims are replaced by measured facts. The existing 30-second full-page Dashboard reload is intentionally retained until Phase 2. + ## Settings and About UI finishing (v5.5.1) Licora v5.5.1 is a no-migration UI corrective release over v5.5.0. Settings shortcuts use a balanced responsive grid, the integration area uses a dedicated API + Cron/Signing composition without forced blank card height, Settings child routes are available through a collapsible accessible submenu, and About Licora uses shared product/feature/company components instead of the previous sparse definition-list layout. Backend/API/license/device/cron/updater behavior remains unchanged. diff --git a/RELEASE_COMMANDS_v5.6.0.md b/RELEASE_COMMANDS_v5.6.0.md new file mode 100644 index 0000000..12281e1 --- /dev/null +++ b/RELEASE_COMMANDS_v5.6.0.md @@ -0,0 +1,52 @@ +# Licora v5.6.0 Release Commands + +Run after applying the verified v5.6.0 Phase 1 replace-ready delta to a clean `v5.5.1` working copy. + +## Local verification + +```cmd +python scripts\verify-local.py +php tests\dashboard_data_contract.php +php tests\dashboard_db_integration.php +php tests\ui_v551_contract.php +php tests\ui_route_contract.php +php tests\ui_component_contract.php +php tests\ui_form_contract.php +php tests\ui_updater_contract.php +php tests\updater_dom_contract.php +node tests\updater_browser_runtime.js +node tests\sidebar_submenu_runtime.js +python tests\updater_builder_contract.py +git diff --check +git status +``` + +`tests/dashboard_db_integration.php` requires the same dedicated MySQL test environment used by CI (`LICORA_V2_TEST_ALLOW_SCHEMA_RESET=1` plus the `LICORA_TEST_DB_*` variables). Without that explicit test DB, it reports a skip rather than touching a normal database. + +## Commit and push + +Stage only the reviewed v5.6.0 Phase 1 paths; do not use `git add -A` on a mixed worktree. + +```cmd +git diff --check +git status +git commit -m "feat: add truthful dashboard read model and data endpoint in Licora v5.6.0" +git push -u origin feature/v5.6.0-dashboard-phase1 +``` + +Do not create the tag until the reviewed changes are on the intended release branch/main and GitHub CI is green. + +## Tag and release + +```cmd +git pull --ff-only +git tag -a v5.6.0 -m "Licora v5.6.0 - Dashboard Data Truth and Read Model" +git push origin v5.6.0 +``` + +The tag-triggered release workflow must publish: + +- `Licora-5.6.0.zip` +- `Licora-5.6.0.zip.sha256` +- `licora-update-manifest.json` +- `licora-update-manifest.sig` diff --git a/RELEASE_COMMANDS_v5.6.1.md b/RELEASE_COMMANDS_v5.6.1.md new file mode 100644 index 0000000..1e8fc27 --- /dev/null +++ b/RELEASE_COMMANDS_v5.6.1.md @@ -0,0 +1,44 @@ +# Licora v5.6.1 Release Commands + +Run these commands only after applying the reviewed v5.6.1 corrective delta. + +## Local verification + +```cmd +python scripts\verify-local.py +php tests\dashboard_data_contract.php +git diff --check +git status --short --branch +``` + +`tests/dashboard_db_integration.php` requires the dedicated MySQL test environment used by GitHub Actions. Do not point it at a normal/production database. + +## Recommended feature-branch commit + +Stage only the reviewed v5.6.1 corrective paths. Do not use `git add -A`. + +```cmd +git status +git diff --check +git add -- .github/workflows/ci.yml BASELINE_v5.6.1.md CHANGELOG.md DASHBOARD_PRODUCTION_UPDATE_INDEX.md README.md RELEASE_COMMANDS_v5.6.1.md RELEASE_NOTES_v5.6.1.md REPOSITORY_METADATA.md ROADMAP.md admin/ajax/dashboard-data.php admin/index.php audit/V5.6.1_DELTA_MANIFEST.md audit/V5.6.1_DELTA_SHA256SUMS.txt audit/V5.6.1_PHASE1_VERIFICATION_AUDIT.md config.sample.php docs/ACTUAL_IMPLEMENTATION_LEDGER.md docs/ARCHITECTURE.md docs/CONFIGURATION.md docs/DASHBOARD_CHANGE_CONTROL.md docs/DASHBOARD_DATA_CONTRACT.md docs/DASHBOARD_PRODUCTION_ROADMAP_2_PHASE.md docs/DASHBOARD_PRODUCTION_VALIDATION_GATES.md docs/DASHBOARD_UPDATE_PHASE_LOG.md docs/ERROR_HANDLING_BASELINE_AND_TARGET.md docs/FEATURE_MATRIX.md docs/INSTALLATION.md docs/RELEASE.md docs/UPGRADE_GUIDE.md includes/config.php includes/dashboard.php includes/installation.php install.php scripts/verify-local.py tests/compatibility_regression.php tests/dashboard_data_contract.php tests/dashboard_db_integration.php tests/installer_smoke.php tests/release_readiness.php tests/updater_state_machine.php update/release-spec.json +git status +git commit -m "fix: verify Dashboard Phase 1 and correct CI contract in Licora v5.6.1" +git push +``` + +The existing PR #8 should update automatically when the commit is pushed to `feature/v5.6.0-dashboard-phase1`. + +## CI stop rule + +Run/check PR #8. If the MySQL integration job or any other check fails, stop and inspect that new concrete failure; do not repeatedly rerun unchanged failing jobs. + +Do not merge or tag until all required checks are green. + +## Tag after merge and final verification + +```cmd +git switch main +git pull --ff-only origin main +git tag -a v5.6.1 -m "Licora v5.6.1 - Dashboard Phase 1 Verification Fix" +git push origin v5.6.1 +``` diff --git a/RELEASE_NOTES_v5.6.0.md b/RELEASE_NOTES_v5.6.0.md new file mode 100644 index 0000000..afd76e6 --- /dev/null +++ b/RELEASE_NOTES_v5.6.0.md @@ -0,0 +1,47 @@ +# Licora v5.6.0 — Dashboard Data Truth & Read Model + +**Release type:** Backward-compatible dashboard data foundation release +**Stable base:** v5.5.1 +**Database migration:** None +**Deleted files:** None +**API v1/v2 external contracts:** Unchanged +**License/device enforcement:** Unchanged +**Updater protocol/state machine:** Unchanged +**Dashboard browser refresh model:** Existing 30-second full-page reload intentionally retained for Phase 2 + +## Summary + +Licora v5.6.0 completes Phase 1 of the Dashboard production program. It replaces duplicated Dashboard SQL with one read-only data model, makes Dashboard metrics and labels match their real data sources, adds an authenticated read-only JSON endpoint for the next reload-free UI phase, and adds dedicated dashboard contract/MySQL validation. + +## Added + +- Central `DashboardReadModel` in `includes/dashboard.php`. +- Authenticated `GET /admin/ajax/dashboard-data.php` JSON endpoint. +- Stable dashboard endpoint errors: `AUTH_REQUIRED`, `METHOD_NOT_ALLOWED`, `DASHBOARD_DATA_ERROR`. +- Explicit license metrics for total, active, expired, suspended and expiring-soon licenses. +- Device reporting for total records, active-flagged records and five-minute recently-seen devices. +- Secure API v2 device-recency contribution through `v2_device_credentials.last_seen_at` when the v2 schema is available, without double-counting the same base device. +- Separate API v1 tracked verification activity (`api_logs`) and Secure API v2 audit activity (`v2_audit_logs`). +- Explicit `legacy_check_license_included=false` reporting because `/api/check_license.php` is not written to `api_logs`. +- Separate expired-last-30-days and expiring-next-30-days datasets. +- Measured Dashboard health/config facts for database access, PHP runtime, environment, config-local presence, Cron script availability and API v2 readiness. +- Dashboard data contract and MySQL integration tests; both CI and tagged release gates run the DB integration test. + +## Corrected + +- `System Status: Live` no longer presents the production environment as a service-health signal. +- Removed hardcoded `Security: Active` and `API Server: Running` Dashboard claims. +- `Daily API Requests` is now `Tracked API Activity`, with v1/v2 sources distinguished. +- `Expired Trend` is now `Expiration Timeline`, with past and future expiration datasets separated. +- `Top Used Licenses` and recent calls explicitly identify their API v1 verification source. +- Dashboard device presentation uses `Recently Seen Devices` instead of treating the persisted active flag as real-time presence. + +## Compatibility + +This release does not modify external API request/response contracts, license generation/verification, device authorization/revocation, authentication/roles, installer flow, Cron mutation behavior, database schema, updater signing, update state machine or existing shared UI architecture. + +The Dashboard AJAX endpoint is internal/admin-only and read-only. It performs no `INSERT`, `UPDATE`, `DELETE`, migration or cleanup action. + +## Phase boundary + +Phase 1 intentionally does **not** add Dashboard polling JavaScript, manual refresh, stale-state UI, last-updated UI or compact Dashboard composition. The existing 30-second full-page reload remains in v5.6.0 and is the explicit continuation point for Phase 2. diff --git a/RELEASE_NOTES_v5.6.1.md b/RELEASE_NOTES_v5.6.1.md new file mode 100644 index 0000000..06bf809 --- /dev/null +++ b/RELEASE_NOTES_v5.6.1.md @@ -0,0 +1,38 @@ +# Licora v5.6.1 — Dashboard Phase 1 Verification Fix + +**Release type:** Corrective Phase 1 verification release +**Source baselines:** v5.5.1 and applied v5.6.0 +**Database migration:** None +**Deleted files:** None +**External API v1/v2 contracts:** Unchanged +**License/device enforcement:** Unchanged +**Updater protocol/state machine:** Unchanged +**Phase 2 reload-free Dashboard UI:** Not included + +## Why v5.6.1 exists + +GitHub Actions PR #8 run `32420291770` exposed a real test-fixture defect after all PHP 8.0–8.4 validation jobs and Windows Python portability passed. The MySQL integration job failed in `tests/dashboard_db_integration.php` because it attempted to drop `v2_device_credentials` while `v2_refresh_tokens.fk_v2_refresh_device` still referenced it. + +The audit also found two Phase 1 truth/contract mismatches that the original static tests did not catch: + +1. the documented top-level `recent_activity` response field was absent from the actual Dashboard endpoint; and +2. the Dashboard could report Secure API v2 as `Ready` from schema + public-key presence even if the server private signing key was missing or mismatched. + +## Fixed + +- Made the Dashboard DB integration fixture isolate the full relevant v2 table set with foreign-key-safe cleanup. +- Added minimal v2 fixture tables required to verify complete schema readiness in the Dashboard integration test. +- Added top-level `recent_activity.v1_tracked` and `recent_activity.v2_tracked` to the Dashboard snapshot/JSON contract without removing the existing nested source-specific activity arrays. +- Changed Dashboard API v2 readiness to require a readable cryptographically matching private/public signing key pair plus the complete v2 schema. +- Extended Dashboard contract tests to enforce the corrected response shape and key-pair readiness rule. +- Added a verifier guard confirming Licora runtime does not contain a Chrome-specific launcher/download dependency. + +## Browser portability finding + +Licora is server-rendered PHP web software. The audited baseline contains no Google Chrome installer, Chrome executable launcher, or Google Chrome download URL. Therefore the reported “Chrome unavailable → Chrome download failed” behavior is not produced by this Licora repository and no unsupported browser-downloader implementation was invented. Licora continues to work through a compatible user-selected browser. + +## Compatibility + +No schema migration, file deletion, external API change, license/device state transition change, Cron behavior change, updater protocol change, or Phase 2 UI/polling implementation is introduced. + +The 30-second full-page Dashboard reload remains intentionally unchanged for Phase 2. diff --git a/REPOSITORY_METADATA.md b/REPOSITORY_METADATA.md index 045e770..4ef8f2e 100644 --- a/REPOSITORY_METADATA.md +++ b/REPOSITORY_METADATA.md @@ -27,6 +27,29 @@ Licora v5.1.0 adds a ten-step first-run installer, delimiter-aware schema execution, secure administrator and secret generation, atomic private configuration, installation locking, optional demo data, database-port support, safe installer diagnostics, and expanded regression validation. The release preserves the existing license engine, API contracts, database schema, routes, admin UI, cron entry points, and encrypted-data compatibility. +## v5.6.1 release candidate + +- **Intended tag:** `v5.6.1` +- **Publication status:** pending corrected PR #8 CI, merge, and tag publication +- **Title:** `Licora v5.6.1 — Dashboard Phase 1 Verification Fix` +- **Release notes:** `RELEASE_NOTES_v5.6.1.md` +- **Primary assets:** `Licora-5.6.1.zip`, `.zip.sha256`, `licora-update-manifest.json`, `licora-update-manifest.sig` +- **Database migration:** none +- **Delete list:** empty +- **Supported update sources:** `v5.5.1`, `v5.6.0` + +Licora v5.6.1 corrects the Phase 1 DB integration fixture, restores exact Dashboard JSON/data-contract parity, and makes API v2 Dashboard readiness require a valid matching signing key pair. Phase 2 remains pending. + +## v5.6.0 source baseline (not published) + +- **Tag status:** `v5.6.0` was not published on GitHub; this source baseline is superseded by the v5.6.1 corrective candidate +- **Title:** `Licora v5.6.0 — Dashboard Data Truth & Read Model` +- **Release notes:** `RELEASE_NOTES_v5.6.0.md` +- **Primary assets:** `Licora-5.6.0.zip`, `.zip.sha256`, `licora-update-manifest.json`, `licora-update-manifest.sig` +- **Database:** no migration; signed direct update from `v5.5.1`. + +The applied v5.6.0 source baseline centralizes Dashboard reads, adds an authenticated read-only data endpoint, makes API/device/expiration/health metrics truthful to their actual sources, and adds dedicated Dashboard validation while preserving external APIs, license/device enforcement, Cron mutation behavior and updater contracts. Phase 2 will replace the still-preserved 30-second full-page Dashboard reload. + ## v5.5.1 release - **Tag:** `v5.5.1` diff --git a/ROADMAP.md b/ROADMAP.md index 2b8d042..931de86 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,11 @@ # Roadmap +## Dashboard production program (v5.6.x) + +- **Phase 1 — Data Truth, Backend Read Model & Error Contract:** implemented in v5.6.0 and corrected in v5.6.1 after PR #8 exposed a MySQL fixture FK-order failure and contract/readiness mismatches; final remote DB/CI verification remains the release gate. +- **Phase 2 — Compact UI, Reload-Free Refresh & Production Gate:** pending; no Phase 2 polling/UI implementation is included in v5.6.1. + + Roadmap items are proposals and must be implemented through reviewed, backward-compatible changes. ## Security hardening diff --git a/admin/ajax/dashboard-data.php b/admin/ajax/dashboard-data.php new file mode 100644 index 0000000..8ccb8c5 --- /dev/null +++ b/admin/ajax/dashboard-data.php @@ -0,0 +1,62 @@ + false, + 'code' => 'METHOD_NOT_ALLOWED', + 'message' => 'Dashboard data requires GET.', + ]); +} + +$auth = new Auth(); +if (!$auth->isAdminLoggedIn()) { + dashboard_json(401, [ + 'success' => false, + 'code' => 'AUTH_REQUIRED', + 'message' => 'Administrator login is required.', + ]); +} + +try { + $model = new DashboardReadModel(); + $snapshot = $model->snapshot(); + dashboard_json(200, [ + 'success' => true, + 'generated_at' => $snapshot['generated_at'], + 'data' => [ + 'licenses' => $snapshot['licenses'], + 'devices' => $snapshot['devices'], + 'api_keys' => $snapshot['api_keys'], + 'api_activity' => $snapshot['api_activity'], + 'recent_activity' => $snapshot['recent_activity'], + 'expiration' => $snapshot['expiration'], + 'health' => $snapshot['health'], + ], + ]); +} catch (Throwable $e) { + error_log('Dashboard data endpoint failure: ' . get_class($e) . ' ' . $e->getMessage()); + dashboard_json(500, [ + 'success' => false, + 'code' => 'DASHBOARD_DATA_ERROR', + 'message' => 'Dashboard data could not be refreshed.', + ]); +} diff --git a/admin/index.php b/admin/index.php index d73b6c7..29d37b0 100644 --- a/admin/index.php +++ b/admin/index.php @@ -3,6 +3,7 @@ require_once '../includes/functions.php'; require_once '../includes/security.php'; require_once '../includes/database.php'; +require_once '../includes/dashboard.php'; $auth = new Auth(); if (!$auth->isAdminLoggedIn()) { @@ -10,34 +11,50 @@ exit(); } -$system = new LicenseSystem(); -$stats = $system->getStats(); +$dashboard = new DashboardReadModel(); +$dashboardSnapshot = $dashboard->snapshot(); +$licenseStats = $dashboardSnapshot['licenses']; +$deviceStats = $dashboardSnapshot['devices']; +$apiStats = $dashboardSnapshot['api_keys']; +$apiActivity = $dashboardSnapshot['api_activity']; +$expiration = $dashboardSnapshot['expiration']; +$health = $dashboardSnapshot['health']; -// API keys stats -$db = Database::getInstance(); -$apiStats = $db->query(" - SELECT - COUNT(*) as total, - SUM(is_active = 1) as active, - SUM(is_active = 0) as inactive, - SUM(request_count) as total_requests - FROM api_keys -")->fetch(); +$chartV1 = $apiActivity['v1_tracked']['last_14_days']; +$chartV2 = $apiActivity['v2_tracked']['last_14_days']; +$topLicenses = $apiActivity['v1_tracked']['top_licenses']; +$recentCalls = $apiActivity['v1_tracked']['recent_calls']; -// Recent API calls -$chartDaily = $db->query("SELECT DATE(created_at) d, COUNT(*) c FROM api_logs WHERE created_at >= DATE_SUB(NOW(), INTERVAL 14 DAY) GROUP BY DATE(created_at) ORDER BY d ASC")->fetchAll(); -$chartExpired = $db->query("SELECT DATE(expires_at) d, COUNT(*) c FROM licenses WHERE expires_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND expires_at <= DATE_ADD(NOW(), INTERVAL 30 DAY) GROUP BY DATE(expires_at) ORDER BY d ASC")->fetchAll(); -$topLicenses = $db->query("SELECT l.license_key, COUNT(al.id) c FROM api_logs al LEFT JOIN licenses l ON al.license_key = l.license_key GROUP BY al.license_key, l.license_key ORDER BY c DESC LIMIT 5")->fetchAll(); +$apiDates = []; +foreach (array_merge($chartV1, $chartV2) as $point) { + if (!empty($point['date'])) { + $apiDates[(string)$point['date']] = true; + } +} +$apiLabels = array_keys($apiDates); +sort($apiLabels); +$seriesByDate = static function (array $series, array $labels): array { + $indexed = []; + foreach ($series as $point) { + $indexed[(string)($point['date'] ?? '')] = (int)($point['count'] ?? 0); + } + return array_map(static fn(string $date): int => (int)($indexed[$date] ?? 0), $labels); +}; +$apiV1Data = $seriesByDate($chartV1, $apiLabels); +$apiV2Data = $seriesByDate($chartV2, $apiLabels); -$recentCalls = $db->query(" - SELECT l.license_key, a.name as api_key_name, - al.endpoint, al.response_code, al.created_at - FROM api_logs al - LEFT JOIN api_keys a ON al.api_key_id = a.id - LEFT JOIN licenses l ON al.license_key = l.license_key - ORDER BY al.created_at DESC - LIMIT 10 -")->fetchAll(); +$expiredSeries = $expiration['expired_last_30_days']; +$expiringSeries = $expiration['expiring_next_30_days']; +$expirationDates = []; +foreach (array_merge($expiredSeries, $expiringSeries) as $point) { + if (!empty($point['date'])) { + $expirationDates[(string)$point['date']] = true; + } +} +$expirationLabels = array_keys($expirationDates); +sort($expirationLabels); +$expiredData = $seriesByDate($expiredSeries, $expirationLabels); +$expiringData = $seriesByDate($expiringSeries, $expirationLabels); ?> @@ -52,13 +69,13 @@ - +

Dashboard

Create License
- +
@@ -67,30 +84,30 @@
Total Licenses
-

- Active: +

+ Active:
- +
-
Active Devices
-

- Total: +
Recently Seen Devices
+

+ Active flagged: · Total:
- +
@@ -98,8 +115,8 @@
Expired Licenses
-

- Suspended: +

+ Suspended:
@@ -113,21 +130,21 @@
API Keys

- Requests: + Tracked v1 requests:
- +
-
System Status
-

+
Environment
+

Version:
@@ -136,12 +153,12 @@
- +
-
Daily API Requests
-
Expired Trend
-
Top Used Licenses
+
Tracked API Activity
+
Expiration Timeline
+
Top Licenses — API v1 Verify
@@ -199,11 +216,11 @@
- +
-
Recent API Calls
+
Recent API v1 Verify Calls
View All
@@ -245,14 +262,11 @@
- - -
- +
@@ -264,54 +278,27 @@
-
-
- -
-
-
-
Database
- Connected -
+
+
Database
-
-
- -
-
-
-
Security
- Active -
+
+
PHP Runtime
-
-
- -
-
-
-
API Server
- Running -
+
+
Cron Scripts
-
-
- -
-
-
-
Environment
- -
+ +
+
API v2
@@ -320,7 +307,7 @@
- + @@ -331,10 +318,14 @@ }, 30000); \ No newline at end of file diff --git a/audit/DASHBOARD_PRODUCTION_DOCS_DELTA_MANIFEST.md b/audit/DASHBOARD_PRODUCTION_DOCS_DELTA_MANIFEST.md new file mode 100644 index 0000000..1b9a367 --- /dev/null +++ b/audit/DASHBOARD_PRODUCTION_DOCS_DELTA_MANIFEST.md @@ -0,0 +1,46 @@ +# Licora Dashboard Production Documentation Delta Manifest + +## Patch Identity + +- Patch type: `DOCUMENTATION ONLY` +- Baseline: `Licora v5.5.1` +- Baseline ZIP SHA-256: `c443b95ad28b8996526d190c5408671c2c405beeff7ff9b8ba7b4ef42b1161d7f` +- Baseline commit: `2f48ef569e6c532ab0de974a418c644e4ea8423f` +- Baseline tree: `c9986ba8b22f3d32c3b3d746dc24c7754d6d0132` +- Runtime implementation changes: `0` +- PHP files changed: `0` +- JavaScript files changed: `0` +- CSS files changed: `0` +- SQL/migration files changed: `0` + +## Purpose + +এই patch production update শুরু করার আগে forensic findings, exact two-phase roadmap, phase tracking, error-handling plan, implementation ledger, data contract এবং validation/change-control rules project root-এ যোগ করে। + +## Extraction + +Project root থেকে ZIP extract করুন। Paths ইতিমধ্যে project-root-relative। + +No existing runtime file is intentionally overwritten by this patch. + +## Added Files + +- `DASHBOARD_PRODUCTION_UPDATE_INDEX.md` +- `audit/V5.5.1_DASHBOARD_PRODUCTION_READINESS_FORENSIC_REPORT.md` +- `docs/ACTUAL_IMPLEMENTATION_LEDGER.md` +- `docs/DASHBOARD_CHANGE_CONTROL.md` +- `docs/DASHBOARD_DATA_CONTRACT.md` +- `docs/DASHBOARD_PRODUCTION_ROADMAP_2_PHASE.md` +- `docs/DASHBOARD_PRODUCTION_VALIDATION_GATES.md` +- `docs/DASHBOARD_UPDATE_PHASE_LOG.md` +- `docs/ERROR_HANDLING_BASELINE_AND_TARGET.md` +- `audit/DASHBOARD_PRODUCTION_DOCS_DELTA_MANIFEST.md` +- `audit/DASHBOARD_PRODUCTION_DOCS_DELTA_SHA256SUMS.txt` + +## Runtime Safety Statement + +এই delta extract করার পরে application behavior পরিবর্তন হওয়ার কথা নয়, কারণ patch-এ executable/runtime source নেই। + +Implementation শুরু করার exact continuation point: + +`docs/DASHBOARD_UPDATE_PHASE_LOG.md` → `Phase 1 — NOT STARTED` diff --git a/audit/DASHBOARD_PRODUCTION_DOCS_DELTA_SHA256SUMS.txt b/audit/DASHBOARD_PRODUCTION_DOCS_DELTA_SHA256SUMS.txt new file mode 100644 index 0000000..dbff8b1 --- /dev/null +++ b/audit/DASHBOARD_PRODUCTION_DOCS_DELTA_SHA256SUMS.txt @@ -0,0 +1,10 @@ +cb5682f8d6432e958e8375208880b1236fa385b30f00679e72bec24166f81147 DASHBOARD_PRODUCTION_UPDATE_INDEX.md +6a93b01f4106d6e99b78bb097968ef5e7364fd346014a028107797abf4d635fc audit/DASHBOARD_PRODUCTION_DOCS_DELTA_MANIFEST.md +38aa50603ecdb853702a04fc1d4c20bd9cfd7dfe2acd19a37afecc04ae6f9386 audit/V5.5.1_DASHBOARD_PRODUCTION_READINESS_FORENSIC_REPORT.md +ae48178b6e131688d62434a76d5a13cbc00ef21a80b18145bc74ffb1fbee2b1f docs/ACTUAL_IMPLEMENTATION_LEDGER.md +cc0ad1740dd28f585385cc0e9ea76d50dcd314402cb5a4463fa60ea44a516913 docs/DASHBOARD_CHANGE_CONTROL.md +85dd80121fee43937704bb047ec91ccecfa31e51b2622dbd4ff769114173899f docs/DASHBOARD_DATA_CONTRACT.md +51d792e839475fde83e159c1eb63812d256e632017f3383f3cf03596ec333e36 docs/DASHBOARD_PRODUCTION_ROADMAP_2_PHASE.md +6772572ca25599b892fc70fbbcae3fa815b01d90ff0e13fd0aa492051d49a231 docs/DASHBOARD_PRODUCTION_VALIDATION_GATES.md +1b46166a84e9a5f8b325f1eaf9dbc6f0ee4bda08dda2b733f4f174a78d43b632 docs/DASHBOARD_UPDATE_PHASE_LOG.md +76d5963c1fce4ce6d889541f8b81cc05b06d04c7bc6ec43858415902df378113 docs/ERROR_HANDLING_BASELINE_AND_TARGET.md diff --git a/audit/V5.5.1_DASHBOARD_PRODUCTION_READINESS_FORENSIC_REPORT.md b/audit/V5.5.1_DASHBOARD_PRODUCTION_READINESS_FORENSIC_REPORT.md new file mode 100644 index 0000000..b497019 --- /dev/null +++ b/audit/V5.5.1_DASHBOARD_PRODUCTION_READINESS_FORENSIC_REPORT.md @@ -0,0 +1,292 @@ +# Licora v5.5.1 — Dashboard Production Readiness Forensic Report + +## 1. Frozen Evidence + +- Baseline: `Licora_v5.5.1_baseline.zip` +- SHA-256: `c443b95ad28b8996526d190c5408671c2c405beeff7ff9b8ba7b4ef42b1161d7f` +- Branch: `main` +- Commit: `2f48ef569e6c532ab0de974a418c644e4ea8423f` +- Tree: `c9986ba8b22f3d32c3b3d746dc24c7754d6d0132` +- Runtime version: `5.5.1` +- Baseline status: **FROZEN / CLEAN** +- Runtime implementation work performed by this documentation delta: **NONE** + +## 2. Audited Scope + +এই report-এর implementation scope: + +- Dashboard UI/UX +- Dashboard KPI and chart semantics +- Dashboard data-refresh behavior +- Page reload vs AJAX behavior +- Background database mutation sources connected to Dashboard +- Operational status/health presentation +- Dashboard error handling +- Shared UI component constraints +- Required tests and production gates + +Existing license engine, API contracts, updater protocol, authentication rules and cron responsibility are frozen unless an explicit roadmap item below says otherwise. + +## 3. Current Actual Dashboard Architecture + +### Render path + +`admin/index.php` server-side PHP দিয়ে Dashboard render করে। Authentication-এর পরে: + +1. `LicenseSystem::getStats()` runs license/device count queries. +2. `api_keys` aggregate query runs. +3. `api_logs` থেকে 14-day activity query runs. +4. license expiration ±30-day query runs. +5. `api_logs` থেকে top licenses query runs. +6. `api_logs` থেকে last 10 calls query runs. +7. PHP সম্পূর্ণ HTML render করে. +8. Chart.js server-rendered arrays দিয়ে charts তৈরি করে. +9. JavaScript 30 seconds পরে `window.location.reload()` করে. + +**Verdict:** Current Dashboard is **server-rendered snapshot + periodic full-page reload**, not a live partial-refresh dashboard. + +## 4. UI/UX Baseline + +[CONFIRMED] + +- Light theme only. +- Fixed desktop sidebar: approximately 196px. +- Compact topbar: approximately 44px. +- Centralized shared UI system under `admin/assets/css/licora/`. +- Bootstrap markup remains a compatibility layer. +- Page-specific CSS and inline `