Releases: tnandla/portfolio-os
Release list
v1.0.1 — security and performance hardening
A security and performance pass over the whole app. No schema change — upgrade by uploading the new code and rebuilt assets. Full detail in CHANGELOG.md.
Security
- Decrypted credential secrets no longer persist in Livewire component state. Revealing a secret stored the plaintext in a public property, which Livewire serialises into
wire:snapshotand echoes back to the browser on every later interaction with that page. Only the credential id is kept now. - Closed cross-project reads through client-controlled state. A partner could change
userIdon their own statement to read another partner's ledger; the approval queue rendered work items from unassigned projects; the links screen exposed budget totals for unauthorised projects. - Staff can no longer reassign tasks without
tasks.assign, including through the bulk bar. - Exported CSVs neutralise spreadsheet formulas. A description starting
=,+,-or@executed on open in Excel and Sheets. /_opshardened: tokens shorter than 32 characters are refused with a 404, responses areno-store/no-referrer/noindex,cache-clearno longer rewrites layouts, and the asset recovery action discards downloads that are not plausibly the asset.- Livewire is served from the app, not a third-party CDN.
- Attachment downloads are authorised and never renderable. Files are served against the permission of the record they hang off, as an attachment with an opaque content type, so an uploaded
.htmlor.svgcannot execute on the app's origin.
Money integrity
- Distribution shares add up exactly. Rounding each share half-up independently could pay out more than the profit (101 paisa split 50/50 paid 102).
- Concurrent approvals can no longer double-credit the partner ledger, and an approved run keeps the ownership snapshot it was computed from.
- Auto-expenses from article and link approval are idempotent under double-submit and concurrent requests, and a deliberately deleted recurring expense is not resurrected.
Fixed
- Attachments can be downloaded at all. Task evidence, project files and expense receipts could be uploaded and deleted but never read back, so an approver could not open the evidence they were approving against.
Performance
The sixteen main screens went from roughly 3,100 queries to 170, displaying the same thing. Causes were per-request permission lookups, repeated settings reads against the database cache store, per-row aggregates called from Blade, a P&L report running three queries per project, and shared-expense allocations rebuilt (and rewritten) on read.
Lazy loading now throws outside production so the next N+1 fails in CI.
Honesty fix
Two-factor authentication is columns and a settings toggle only — no enrolment, no login challenge. The settings screen and SECURITY.md now say so, because the toggle could previously be mistaken for a control.
Docs
README rewritten around what the app does; setup moved to docs/INSTALL.md.
103 tests green on PHP 8.3, 8.4 and 8.5.
v1.0.0 — Portfolio OS
First complete release. Built as seven milestones, each shipped and verified before
the next began.
Milestone 1 — Foundation
- Laravel application skeleton, authentication, password reset.
- Many-to-many roles and permissions: 49 granular permissions across 5 seeded roles
(admin, partner, supervisor, staff, accountant). Effective permissions are the union
of a user's roles; norolecolumn and no role switcher. - User administration, activation state, and an app settings store.
- Application shell: navigation rail, top bar, command palette, mobile drawer and
thumb bar. - Design system: tokens, dark mode, density modes and a Blade component library.
- Seeders for roles, permissions, settings and task templates.
Milestone 2 — Projects & credentials
- Project portfolio CRUD with status, CMS, niche, monetisation state, acquisition cost.
- Per-project ownership shares validated to total 100%, and team assignment that scopes
staff visibility. - Encrypted credential vault, with reveal gated by its own permission and every reveal
written to an audit log. - Scheduled credential expiry alerts with configurable warning windows.
- Portfolio dashboard.
Milestone 3 — Work
- Tasks with checklists, priorities, due dates, attachments, comments and evidence
on submit. - Recurring task generation and reusable task templates.
- Article pipeline from brief to published, with word-count targets and per-article cost.
- Link building log with per-project monthly budgets.
- A single keyboard-driven approval queue across tasks, articles and links, optionally
raising the matching expense on approval.
Milestone 4 — People
- Attendance derived from the first login of the day, with a configurable late hour,
plus supervisor leave and holiday marking. - Login history with IP and user agent.
- Daily work logs.
- Monthly scorecards aggregating output per person, costed against mixed pay rates
(monthly salary and/or per-article, per-link, per-task).
Milestone 5 — Money
- Revenue per project per month, entered directly or imported from CSV, with the FX
rate frozen on each row so historical figures never re-convert. - Direct and shared expenses, receipt uploads, recurring expense templates, paid state.
- Monthly profit and loss with shared costs allocated across projects in proportion
to revenue. - Manual partner distributions computed from ownership shares; approving a run locks it
permanently, and corrections are new adjusting entries. - Partner ledger and per-partner statements for capital, withdrawals and distribution
credits. - All monetary values stored as integer minor units.
Milestone 6 — Deployment
- FTP packaging scripts for shared hosting (
deploy/package.sh,deploy/package.ps1)
producing an app archive and a public archive. - Dual-path
public/index.phpthat works both in the split shared-hosting layout and
locally. - Token-gated
/_ops/{action}maintenance route for hosts without SSH, disabled
entirely when no token is set. storage:linkfallback that copies whensymlink()is unavailable, plus a public
media fallback route.- Pure-PHP database backup command requiring no
mysqldumpor shell access. DEPLOYMENT.md.
Milestone 7 — AI assistant
- Optional natural-language "ask your data" assistant and drafted monthly summaries,
completely hidden when no provider key is configured. - Questions map onto a fixed whitelist of read-only report methods that re-apply the
caller's permissions and project scope; a model never generates executed SQL. - Credentials, passwords, keys and bank details are stripped before any prompt is built.
- Monthly spend cap, per-request token and cost logging, and response caching.