Legacy stack audit & modernization roadmap.
WooCommerce listings front-end + Laravel lead portal + Ubuntu 18.04 VPS
Executive summary
Northpine's web stack is functional and revenue-positive but materially fragile. The two main applications — the WooCommerce-based public listings site and the custom Laravel lead portal — both run on software that has reached end of security support, on a host operating system that has reached end of life. There is no validated backup, no staging environment, and a single individual holds the only working knowledge of how deploys are performed.
The good news: none of the urgent risks require a rewrite. A scoped 8-week refit, executed in three stages, can move the stack onto a maintainable baseline without disrupting the lead pipeline or the public listings.
Top three things to do in the next 14 days
- Test a backup restore. Daily backups are running but have never been restored. Until proven, treat backups as not existing.
- Patch PHP 7.2 → 7.4 on staging. The current version has been out of security support since November 2020. A staging-only patch is enough to validate the upgrade path.
- Capture deploy procedure. Currently lives in one developer's head. Forty minutes of recorded screen-share, transcribed, removes the highest-impact single point of failure.
Engagement context
Northpine engaged StackRefit on April 18, 2026, following a prospective replatform conversation with their existing agency. The agency quoted a full Laravel rebuild at approximately €85,000. Northpine's CEO requested a second opinion and a fixed-scope assessment of whether a rebuild is genuinely necessary.
Audit scope as agreed
- Inventory of all software, services, and infrastructure in the production path of northpine.example.
- Read-only review of code repositories, server configuration, and deployment artefacts.
- Risk register with severity, effort, and recommended remediation owner.
- 30 / 60 / 90-day modernization roadmap with cost ranges.
- Recommendation on refit vs. rebuild for the lead portal.
Out of scope
- Penetration testing or active vulnerability exploitation.
- Production changes of any kind during the audit window.
- Review of marketing, SEO, or commercial performance of the platform.
Information sources
| Source | Provided by | Date |
|---|---|---|
| SSH read-only on web1.northpine.example | M. Carter, IT Lead | 2026-04-22 |
| BitBucket repo: northpine/portal | M. Carter | 2026-04-22 |
| BitBucket repo: northpine/wp-listings | M. Carter | 2026-04-22 |
| 30-min context call | S. Whitfield, CEO | 2026-04-23 |
| 60-min walkthrough call | J. Petersen, sole developer | 2026-04-24 |
| Hosting invoices & provider portal screenshots | M. Carter | 2026-04-25 |
Stack inventory
The Northpine production stack runs on a single Hetzner CX31 instance, with two distinct applications served behind one Nginx instance.
Applications
| Component | Version | Released | Support status |
|---|---|---|---|
| WordPress core | 5.8.6 | Jul 2021 | Outdated |
| WooCommerce | 6.4.1 | Apr 2022 | Outdated |
| WP plugins (active) | 38 | — | 12 unmaintained |
| WP theme | heavily customized child of "Avada 5.x" | — | Outdated |
| Laravel (lead portal) | 6.20.44 | Mar 2022 | EOL |
| Composer deps | — (lock 2022-03) | — | 4 yrs stale |
Runtime & database
| Component | Version | Support status |
|---|---|---|
| PHP | 7.2.34 | EOL since Nov 2020 |
| PHP-FPM | 7.2 pool · 8 workers | Tuned for 2 GB host, currently 8 GB |
| MySQL | 5.7.38 | EOL since Oct 2023 |
| Redis | 5.0.7 | Outdated |
| Nginx | 1.14.0 | Outdated |
Operating system & host
| Component | Detail | Status |
|---|---|---|
| Distribution | Ubuntu 18.04.6 LTS (Bionic) | Standard support EOL Apr 2023 |
| Kernel | 4.15.0-213-generic | Outdated |
| Host | Hetzner CX31 · 4 vCPU · 8 GB · 80 GB SSD | Adequate |
| Disk usage | 61 GB / 80 GB (76%) | Watch |
Services map
External integrations
| Service | Purpose | Auth | Notes |
|---|---|---|---|
| Stripe | Listing fees, premium placements | live keys in .env | API version pinned to 2020-08-27 |
| Postmark | Transactional email | key in .env | OK |
| Twilio | SMS lead alerts | key in .env | 1.4M unbilled SMS — see Risk R-09 |
| Cloudflare | DNS + edge caching | shared admin login | 2FA disabled — see Risk R-04 |
Risk register
Each risk is rated by severity (potential business impact) and includes an effort estimate and the service line in which we propose to address it. The full register has 23 entries; the top 15 are reproduced below.
| ID | Risk | Severity | Impact | Effort | Owner | Phase |
|---|---|---|---|---|---|---|
| R-01 | PHP 7.2 in production | Critical | High | Low | Upgrade | Sprint |
| R-02 | Laravel 6 (out of security support) | Critical | High | Med | Upgrade | Upgrade |
| R-03 | Backups never restore-tested | Critical | Critical | Low | Sprint | Sprint |
| R-04 | Cloudflare admin lacks 2FA | High | High | Low | Sprint | Sprint |
| R-05 | Ubuntu 18.04 EOL | High | High | Med | Upgrade | Upgrade |
| R-06 | 12 unmaintained WP plugins | High | Med | Med | Sprint | Sprint |
| R-07 | MySQL 5.7 EOL | High | Med | Med | Upgrade | Upgrade |
| R-08 | No staging environment | High | Med | Low | Sprint | Sprint |
| R-09 | Twilio rate-limit absent — runaway risk | Med | Med | Low | Sprint | Sprint |
| R-10 | Manual SFTP deploys, no rollback | Med | Med | Med | Sprint | Sprint |
| R-11 | Sole-developer knowledge concentration | Med | Med | Low | Handover | Handover |
| R-12 | Stripe webhook handler not idempotent | Med | Med | Low | Sprint | Sprint |
| R-13 | Disk usage at 76% | Med | Low | Low | Sprint | Sprint |
| R-14 | wp-cron via real cron, but not monitored | Low | Low | Low | Sprint | Sprint |
| R-15 | Composer.lock 4 years stale | Med | Med | Med | Upgrade | Upgrade |
Severity distribution
Security posture
This is not a penetration test. The notes below are observations from configuration review only.
What's in good shape
- TLS via Let's Encrypt, A grade on SSL Labs (2026-04-25). Auto-renewal cron is healthy.
- WordPress login is rate-limited via limit-login-attempts-reloaded.
- Stripe and Postmark API keys live in .env, not committed to git.
- Database is bound to 127.0.0.1 only.
What needs attention
- Cloudflare admin account shared between three people, no 2FA. (R-04)
- WordPress admin user has username "admin" and a password last rotated in 2023.
- SSH permits password authentication on port 22; fail2ban active but root login is enabled.
- WP plugins: contact-form-7 v5.4.2 has a known unauthenticated upload vulnerability (CVE-2023-XXXX). Patched in v5.7.
- Laravel app key has not been rotated since initial deploy (visible in git log against .env.example, then never changed).
Backups & restore
What exists today
| Asset | Frequency | Destination | Last verified |
|---|---|---|---|
| MySQL dumps (both schemas) | daily 03:15 | /var/backups/db/ + Hetzner Storage Box | never |
| WP uploads (4.2 GB) | weekly Sun 04:30 | Hetzner Storage Box | never |
| Laravel storage/ | weekly Sun 04:30 | Hetzner Storage Box | never |
| Hetzner host snapshot | none | — | none |
Test restore (read-only, off-host)
We pulled the most recent MySQL dump and the most recent uploads tarball to a sandbox VM and attempted a full restore. Outcome:
The DB dump cannot be restored on the current host without an upgrade to MySQL 8 — the dump was taken in compatibility mode but uses a collation only present in 8.0+. Uploads tarball is intact and restorable.
Deployment & ops
Current process
Per walkthrough with J. Petersen on 2026-04-24:
- Local development on macOS, MAMP for the WP site.
- Manual git pull on the production host via SSH.
- For the Laravel portal: composer install --no-dev, then php artisan migrate.
- For WP: changes to themes are made directly on production via SFTP. Plugin updates via wp-admin.
- No staging. No rollback. No deploy log. No release tags.
Observed deploys (from shell history)
The pattern of late-night deploys, sometimes followed by an immediate revert, is consistent with deploys made without a staging environment to test against.
Monitoring
- Uptime: UptimeRobot pinging the home page every 5 minutes. No alert on the lead portal.
- Error tracking: none. Laravel logs to storage/logs/laravel.log, currently 1.7 GB.
- Performance: none.
Maintainability
Codebase shape
| Repo | Lines | Tests | CI | README |
|---|---|---|---|---|
| northpine/portal (Laravel) | ~38,000 | 3 (controller smoke tests) | none | setup notes only |
| northpine/wp-listings | ~12,000 (excluding plugins/core) | none | none | none |
Documentation
- One README.md from 2021 covering local dev for the portal. Three of its four steps no longer work without modification.
- No architecture diagram, no API reference, no operational runbook.
- Business logic for premium placements lives in a single Laravel service class (PlacementValuator, 840 lines) with no comments and no tests.
Bus factor
We score operational bus factor at 1. J. Petersen is the only person with deploy ability, the only person who has touched PlacementValuator in 24 months, and the only person who knows the Cloudflare admin password reset flow.
AI-assisted documentation snapshot
As part of the audit, we generated a first-pass map of the Laravel portal using AI-assisted code analysis on a sandboxed copy of the repository (no production data, no external transmission of customer records). Output below has been reviewed and lightly edited by hand. It is not a substitute for a Handover engagement, but it gives Northpine a starting point.
System map (excerpt)
What we noticed
- The PlacementValuator service is the application's commercial core. It scores incoming leads against premium placement contracts. It has no tests and no documentation. Any rebuild that doesn't preserve its behaviour will be a regression.
- The lead-lifecycle state machine is implicit (string field, hand-rolled transitions). Not broken, but the cause of three of the issues in the public Trello board.
- The PDF reporter uses an old version of dompdf. Migrating to a current version requires Composer cleanup (R-15) but is otherwise straightforward.
30 / 60 / 90-day roadmap
Recommended sequencing. Costs are indicative ranges based on StackRefit standard rates; final scope and price come in the proposal.
Phase 1 — Stabilize (days 0–14)
StackRefit Sprint Standard · €4,500 · 10 business days
- Stand up MySQL 8 staging host. Verify full restore from latest dump.
- Patch contact-form-7 and 6 other high-risk plugins on staging then production.
- Add 2FA to Cloudflare. Rotate WordPress admin credentials. Disable SSH password auth.
- Wrap Twilio sender in a rate-limit bucket. Add Sentry to the Laravel app.
- Document deploy procedure as a 1-page runbook.
Phase 2 — Upgrade (days 15–45)
StackRefit Upgrade · €6,000 · 4 weeks
- PHP 7.2 → 8.2 in two stages, on staging first. WP plugin compatibility fixes.
- MySQL 5.7 → 8.0. Schema migration tested against production-shape data.
- Laravel 6 → 8 → 10, one major version at a time, tests added incrementally for PlacementValuator first.
- Composer dep cleanup. dompdf upgrade.
- Ubuntu 18.04 → 22.04 via host swap (new Hetzner instance, blue/green cutover).
Phase 3 — Operate (days 45–90)
StackRefit Care Standard · €1,000/mo · ongoing
- Monthly update window. Backup verification on a schedule.
- Quarterly mini-audit. Monthly technical report.
- Optional: AI Retrofit scoping for lead triage automation (Phase 4 candidate, separate scope).
Estimated cost summary
| Phase | Service | Duration | Cost |
|---|---|---|---|
| Stabilize | Sprint Standard | 10 days | €4,500 |
| Upgrade | Upgrade (PHP/MySQL/Laravel/OS) | 4 weeks | €6,000 |
| Operate | Care Standard | ongoing | €1,000 / mo |
| Total to maintainable baseline | — | ~8 weeks | €10,500 + retainer |
Scope & limitations
- This audit is based on read-only access conducted between 2026-04-22 and 2026-04-28. Findings reflect that snapshot.
- We did not run active vulnerability scans, fuzzers, or load tests.
- Risk severities are StackRefit's professional judgement and should not be interpreted as compliance certifications.
- Cost estimates assume no surprises in the WordPress plugin set during the upgrade. A 15% contingency is recommended.
- The PlacementValuator behaviour was inferred from code reading; behaviour-equivalence testing during the upgrade is included in the Upgrade scope.
Appendix
A. Full risk register (23 entries)
Attached as SR-AUD-2026-0042-A.csv
B. AI prompt log
Attached as SR-AUD-2026-0042-B.txt · 14 prompts, all against sandboxed code repository, no production data
C. Access checklist
Attached as SR-AUD-2026-0042-C.pdf · credentials inventory and rotation recommendations
D. Restore test transcript
Attached as SR-AUD-2026-0042-D.log
Issued 2026-04-28 by Dan Voinea
Confidential — distributed to Northpine Property Group only