Why Northvale
What makes it better
than the alternatives
- 01
Six complete homepage designs
Switch themes instantly without losing content, blog posts, leads or media
- 02
Full Arabic site at /ar/ with right-to-left layout, Arabic fonts and translated content; language switch and hreflang tags built in
Full Arabic site at /ar/ with right-to-left layout, Arabic fonts and translated content; language switch and hreflang tags built in
- 03
First-party, cookie-less visitor analytics
No IP addresses stored, visitors hashed daily, optional GeoLite2 country lookup
- 04
Theme pipeline included
Python converter turns static HTML into editable CMS themes with pixel-diff validation (tools/theme-converter/)
- 05
Optional public demo mode
Demo account, content auto-reset, design switcher for visitors, iframe embedding (CMS_DEMO_MODE=true)
Website (6 themes)
- Six homepage designs: Corporate Classic (home-01)
- Editorial Agency (home-02)
- Luxury Advisory (home-03)
- Swiss Studio (home-04)
- Soft Modern (home-05)
- Creative Collage (home-06)
- Pages: Home
- About
- Team
- Services
- Service detail
- Portfolio
- Blog
- Article
- Contact
- Privacy/Terms/Cookie; custom pages can be added
- Arabic site at /ar/ with RTL layout
- Arabic font (Noto Kufi Arabic)
- translated content; language switch button
- Dark-mode toggle
- responsive layouts
- self-hosted fonts (Schibsted Grotesk
- Newsreader
- DM Mono
- Work Sans
- Libre Baskerville
- Manrope
- Montserrat
- JetBrains Mono
- Roboto Mono
- Inter
- Outfit
- Space Grotesk
- DM Serif Display
- Jost
- Cormorant Garamond
- IBM Plex Mono)
- SEO meta tags
- Open Graph
- JSON-LD structured data
- sitemap.xml
- robots.txt
- hreflang links
- Contact form (name
- company
- phone
- message
- service
- budget
- extra fields) with honeypot
- timing check
- rate limiting
- optional reCAPTCHA v3
- Newsletter form (email) with honeypot
- timing check
- rate limiting
- optional reCAPTCHA v3
- Security headers
- framing rules (ALLOW_FRAMING_FROM)
- CSRF protection
- script URL removal from rendered pages
Admin Panel
- Dashboard: new leads panel
- visitor stats (today
- yesterday
- last 7/30 days)
- top pages
- recent activity
- Configurable admin path (Settings → Security or CMS_ADMIN_PATH; default /admin)
- Two roles: administrator (full access) and editor (cannot change settings
- users
- email templates)
- Sign-in with email/password
- remember me
- session timeout (SESSION_LIFETIME minutes)
- activity log
- Every admin route requires auth + active user; Livewire components re-check user on every request
- Admin mutations only through authenticated Livewire components or routes; public writes limited to contact/newsletter forms and analytics beacon
Pages & SEO
- Page editor: sections (edit
- reorder
- hide
- duplicate
- add from theme's section library)
- draft → preview (signed link) → publish
- 30 restorable revisions per page (page_revisions table)
- Per-page SEO: meta title
- meta description
- canonical URL
- Open Graph title/description/image
- robots index/follow
- show in sitemap
- Page templates: home
- about
- team
- services
- service (detail)
- portfolio
- blog
- post (article)
- contact
- privacy
- terms
- cookie
- custom
- Section content keys: t# (text)
- a# (link/image)
- g# (repeatable group)
- v# (hidden design value); Arabic = <key>_ar
- Section schema defined in resources/themes/<slug>/schema/<type>.json (text
- textarea
- richtext
- image
- link
- select
- repeater
- toggle
- color
- number)
- Rich text sanitised with HTMLPurifier (App\Cms\Prose::sanitize); script URLs removed by UrlGuard
Blog
- Rich-text editor (TipTap: bold
- italic
- link
- image
- headings
- lists
- blockquote
- code)
- Categories
- tags
- author name
- cover image
- excerpt
- featured article toggle
- Scheduling: draft
- scheduled (published_at future)
- published
- Per-article SEO: meta title
- meta description
- canonical URL
- Open Graph title/description/image
- robots index
- Article URL: /blog/{slug}; Arabic: /ar/blog/{slug}
- JSON-LD structured data (Article schema) with headline
- description
- image
- datePublished
- dateModified
- author
- publisher
Content Blocks (shared by all themes)
- Services: title
- slug
- summary
- description (rich text)
- icon
- image
- is_active
- order
- meta_title
- meta_description; URL /services/{slug}
- Case studies (Portfolio): title
- client
- category
- year
- description (rich text)
- cover_image
- gallery (images)
- is_featured
- order
- Team: name
- role
- bio (rich text)
- photo
- linkedin_url
- order
- is_active
- Testimonials: client_name
- client_role
- client_company
- quote
- photo
- rating (1-5)
- is_featured
- order
- Clients (logos): name
- logo
- website_url
- order
- Offices: city
- address
- phone
- map_url
- order
- Key numbers: label
- value
- suffix
- order
- Process steps: title
- description
- icon
- order
- FAQ: question
- answer (rich text)
- category
- order
- All content blocks translatable (English + Arabic); Arabic fields stored in translations JSON column (HasTranslations trait)
Leads & Subscribers
- Leads: name
- company
- phone
- message
- service
- budget
- extra fields (JSON)
- source_url
- ip
- status (new/contacted/qualified/converted/closed)
- notes
- created_at
- Lead workflow: New → Contacted → Qualified → Converted / Closed; status filter
- search (name
- company
- message)
- period filter
- service filter
- CSV export (leads.export route): Received
- Status
- Name
- Phone
- Company
- Interest
- Budget
- Message
- Page
- Other fields
- Newsletter subscribers: email
- status (subscribed/unsubscribed)
- language (en/ar)
- source_url
- ip
- created_at
- Subscriber actions: add
- unsubscribe
- delete
- CSV export
- Welcome email sent on subscription (newsletter_welcome template) unless demo mode
Media Library
- Upload images (JPEG
- PNG
- GIF
- WebP
- SVG); images re-encoded to JPEG/PNG
- SVGs sanitised
- Image details: filename
- size
- dimensions
- upload date
- usage (pages
- posts
- services
- team
- case studies
- testimonials
- clients)
- Delete with usage check (warns if used); bulk delete
- Storage: public/storage/media/ (symlinked from storage/app/public/media/)
- Media picker component (Livewire) for selecting images in admin forms
Themes
- Six installed themes: corporate-classic (default)
- editorial-agency
- luxury-advisory
- swiss-studio
- soft-modern
- creative-collage
- Theme structure: theme.json (pages
- bindings
- compose)
- sections/ (Blade views)
- schema/ (field definitions)
- chrome/ (header/footer)
- custom/ (CSS/JS)
- seed/content.json
- media/images/
- Theme preview: view any installed theme with your content before activating (signed URL with ?_theme=slug)
- Brand colours: primary
- secondary
- accent (per theme); font families: heading
- body
- mono (per theme)
- Theme bindings: connect section lists to content modules (services
- team
- posts
- case studies
- testimonials
- clients
- offices
- key numbers
- process steps
- FAQ) via theme.json → bindings
- Theme installation: php artisan cms:install --theme=<slug> or cms:theme-refresh <slug> --force (re-imports original content)
- Theme converter: tools/theme-converter/convert.py (static HTML → CMS theme); pixel-diff checker: tools/theme-converter/pixel_diff.py
Analytics
- First-party
- cookie-less visitor tracking: visitor hash = sha256(daily salt + IP + user agent + host); no IP addresses stored
- Sessions: visitor_hash
- started_at
- last_seen_at
- landing_path
- exit_path
- referrer_host
- referrer_url
- utm_source
- utm_medium
- utm_campaign
- device
- browser
- os
- country_code
- country
- city
- pageviews
- duration_seconds
- Page views: session_id
- path
- title
- viewed_at
- duration_seconds (updated by ping beacon every 15s)
- Dashboard stats: visits today/yesterday/last 7 days/last 30 days
- page views
- top pages (path
- views
- avg duration)
- Optional GeoLite2 country/city lookup (MaxMind DB reader; database not included
- download separately)
- Optional Google Analytics 4 integration (GA4 tracking ID in Settings → Analytics)
- Exclude admins toggle (Settings → Analytics); bots ignored (UserAgent::isBot)
- Data retention: delete analytics older than retention_days (Settings → Analytics; default 395 days); cron: php artisan cms:analytics-prune (scheduled daily at 03:15)
Settings & Configuration
- General: site name
- tagline
- default language
- timezone
- Email delivery: SMTP host
- port
- username
- password (encrypted)
- from address
- from name
- encryption (TLS/SSL/none)
- Forms: contact success message
- newsletter success message
- reCAPTCHA enabled
- site key
- secret key (encrypted)
- min score (0.0-1.0)
- Analytics: enabled
- exclude admins
- retention days
- GA4 tracking ID
- SEO: organization name
- default meta description
- title suffix
- robots index
- Open Graph image
- Scripts: header scripts (before </head>)
- footer scripts (before </body>)
- Security: admin path (CMS_ADMIN_PATH)
- allowed framing origins (ALLOW_FRAMING_FROM)
- Language & display: Arabic site enabled
- dark mode enabled
- Header & Footer: menus (label
- URL
- Arabic label
- order
- parent_id for dropdowns)
- logos (main logo
- footer logo
- dark mode variants)
- Email templates: contact_notification
- newsletter_welcome
- lead_status_update (subject
- body with {{placeholders}})
- Users: name
- role (administrator/editor)
- is_active
- last_login_at; create
- edit
- deactivate
- delete
- Account: change name
- password (current password required; min 10 chars
- mixed case
- numbers
- symbols)
| Language | Version | Framework | Used for | Share of code |
|---|---|---|---|---|
| CSS | — | — | Styling | 74.2% |
| PHP | — | — | Web, API | 18.4% |
| JavaScript | — | — | Front-end | 2.9% |
| Python | — | — | Web, API | 2.3% |
| SQL | — | — | Database | 2% |
| HTML | — | — | Front-end | 0.2% |
| Shell | — | — | Scripts | 0% |
- Primary language
- PHP 8.2+
- Framework
- Laravel 12 + Livewire 4
- Database
- MySQL 8 / MariaDB 10.6+
- Authentication
- Session-based (Laravel auth, database sessions)
- Licence
- Single-site
- Screens
- 42
- Database tables
- 29
- Supported languages
- English, Arabic (RTL)
- Browser support
- Modern browsers (Chrome, Firefox, Safari, Edge)
| Minimum | Recommended | |
|---|---|---|
| CPU | 1 vCPU | 2 vCPU |
| RAM | 2 GB RAM | 4 GB RAM |
| OS | PHP 8.2+ (pdo_mysql, mbstring, openssl, fileinfo, gd, intl, zip), Composer 2, Node 20+ (build only), MySQL 8 / MariaDB 10.6+ | PHP 8.2+ (pdo_mysql, mbstring, openssl, fileinfo, gd, intl, zip), Composer 2, Node 20+ (build only), MySQL 8 / MariaDB 10.6+ |
| Est. monthly hosting | $15 | $15 |
```bash cp docker.env.example .env # Edit .env: set DB_PASSWORD, DB_ROOT_PASSWORD, ADMIN_PASSWORD (openssl rand -base64 24) docker-compose up -d docker-compose exec app php artisan migrate --force docker-compose exec app php artisan cms:install --all-themes --email=you@example.com # Visit http://localhost:8080 (site) and http://localhost:8080/admin ```
```bash
sudo apt update && sudo apt install -y php8.2 php8.2-{cli,fpm,mysql,mbstring,xml,curl,gd,intl,zip} mysql-server nginx composer
cd /var/www && sudo git clone <repo> northvale && cd northvale/Laravel\ Project
sudo chown -R www-data:www-data storage bootstrap/cache
composer install --no-dev --optimize-autoloader
cp .env.example .env
# Edit .env: APP_URL, DB_* (create database + user), SESSION_SECURE_COOKIE=true
php artisan key:generate
php artisan migrate --force
php artisan storage:link
php artisan cms:install --all-themes --email=you@example.com
php artisan config:cache && php artisan view:cache
# Configure Nginx: root /var/www/northvale/Laravel Project/public; try_files $uri /index.php
# Add cron: * * * * * php /var/www/northvale/Laravel\ Project/artisan schedule:run
sudo systemctl restart nginx php8.2-fpm
``````bash # Upload Laravel Project/ to public_html/northvale # In cPanel: create MySQL database + user, note credentials # SSH or File Manager: cd public_html/northvale cp .env.example .env # Edit .env: APP_URL, DB_*, SESSION_SECURE_COOKIE=true php artisan key:generate php artisan migrate --force php artisan storage:link php artisan cms:install --all-themes --email=you@example.com php artisan config:cache && php artisan view:cache # Point domain document root to public_html/northvale/public # Add cron job: * * * * * php /home/user/public_html/northvale/artisan schedule:run ```
```bash cd Laravel\ Project composer install npm ci && npm run build cp .env.example .env php artisan key:generate # Edit .env: DB_CONNECTION=sqlite, DB_DATABASE=/full/path/database.sqlite, SESSION_SECURE_COOKIE=false touch database/database.sqlite php artisan migrate php artisan cms:install --all-themes --email=demo@example.com --password=demo123456 php artisan serve # Visit http://127.0.0.1:8000 (site) and http://127.0.0.1:8000/admin ```
Quality report
Manually reviewedHow to read the quality report
What this is. Every project on Vibe96 goes through an automated audit of its source code before a reviewer in Dubai checks it by hand. The score is out of 100; 75 is the minimum to be listed, and any single failing check blocks a listing regardless of the score.
- Security
- No real credentials in the code, every data-changing route protected, admin areas role-gated, no SQL built from user input.
- Code structure
- A developer can navigate and extend it: clear module boundaries, no giant files, little copy-paste.
- Docs & completeness
- The setup guide, example config, schema and required files the builder committed to are actually in the archive.
- Dependency health
- Packages pinned, no known critical vulnerabilities, no abandoned libraries in production paths.
- Build & deploy
- A clean machine can restore, build and start it by following the shipped instructions.
Warnings are problems that didn't block the listing; they stay visible here until a later version clears them. The audit reads the code — it does not run it — so always try the live demo before you buy. Lines of code are counted from the same audited archive.
Reviewer notes (3 minor)
Strong auth guards on all mutating endpoints; minor ownership gaps on read-only analytics; no critical vulnerabilities; some outdated packages and missing composer.lock; weak default passwords in docker-compose.yml and example files; database access is mostly safe; a few missing indexes and one unscoped delete; moderate code duplication and some oversized components; generally well-structured but refactoring opportunities exist; build reproducible with gaps: missing node build step, unclear db setup, demo password exposed. None of these stop the software from working; the developer has been told and improvements come in a future update.
Versions & updates
No updates yet. New versions appear here with a changelog.
Buyers receive updates free for 1 year.
What you get
- </>Full source codeThe complete audited source, delivered as a download from your account. No obfuscation.
- ▤DocumentationSetup guide, architecture notes, CLAUDE.md and AGENTS.md.
- ↻One year of updatesEvery new version the builder publishes, free for 12 months.
- ♧30 days of supportInstallation and defect support through Vibe96 tickets.