CLAUDE.md 14 KB

CLAUDE.md

Project Overview

Crop Management Platform — modX CMS → standalone PHP migration Purpose: Centralise records for irrigation, weather, and soil moisture; supports real-time monitoring for Australian conditions. Stack: PHP 8.4, MySQL, Bootstrap 5, jQuery, Chart.js Repository root: f:\GIT_REPO\crop_monitor


Directory Structure

crop_monitor/
├── api/                          # REST API endpoints (legacy)
├── client-assets/                # CSS, JS, images, uploads
│   ├── css/                      # Bootstrap 4 + custom styles
│   ├── js/                       # jQuery, Chart.js, custom scripts
│   ├── table/                    # DataTables AJAX helpers (legacy mysqli)
│   ├── FredTemplate/             # Old template assets
│   └── fullcalendar/             # Calendar widget
├── components/                   # Reusable UI components (migrated)
├── config/                       # Database config (PDO)
├── controllers/                  # Form POST handlers (migrated)
├── dashboard/                    # Main application pages
│   ├── crop-analysis/
│   │   ├── soil-test-data/       # Soil analysis entry + display
│   │   ├── plant-test-data/      # Plant tissue analysis
│   │   ├── animal-dietary-balance/
│   │   └── water-test-data/
│   ├── client-settings/
│   ├── crop-cards/
│   ├── inbox.php
│   └── planning-calendar.php
├── layouts/                      # Page templates (header, footer, nav, sidebar)
├── lib/                          # Utility libraries
├── login/                        # Auth pages (still modX templates)
├── cropmonitor.sql               # Full database schema dump
├── index.php                     # Empty — routing via .htaccess
├── .htaccess                     # Front controller rewrite rules
└── .env                          # Empty — credentials currently in config/database.php

Database Schema

Schema file: cropmonitor.sql

Table Purpose
client_records Client info + weather station API keys (modx_user_id FK)
soil_records Soil analysis data — 80+ columns (nutrients, base saturations, calculations)
soil_specifications Min/max nutrient ranges by soil type (used for recommendations)
soil_comments Element-specific recommendation text
plant_records Plant tissue analysis
plant_specifications Nutrient ranges by crop/growth stage
animal_records Animal dietary balance
animal_specifications Nutrient requirements by species
water_records Water quality analysis
weather_station Weather station data ingestion
fertiliser_specifications Fertilizer product database
block_info Field/block metadata
crop_info Crop definitions
calendar_events User scheduling
reports Comments/notes on analyses
field_sensors IoT sensor readings
sensor_id Sensor registration

Important data notes:

  • Most nutrient values stored as VARCHAR(10) — always cast to float in PHP
  • modx_user_id field links all records to users (legacy modX user system)
  • rand field on soil_records is a secondary verification token for URL access

Migration Status

Completed (PDO + secure)

Original modX Migrated to
[[!clientDetailsFORM]] components/clientDetailsForm.php
[[!newClientDetails]] components/newClientModal.php + controllers/newClientSubmit.php
[[!soilformSubmit]] controllers/soilTestSubmit.php
[[!Personalize?]] + [[Wayfinder?]] components/navigation.php
[[$dash-header]] + [[$dash-footer]] layouts/header.php, layouts/footer.php, layouts/navbar.php, layouts/sidebar.php
soil-test-data.php Uses include-based layout system
soil-analysis.php PDO + Bootstrap 5 + calc functions
[[!Login]] login/login.php (session auth, CSRF, PDO)
[[!Register]] login/register.php (validation, auto-login, CSRF)
[[!ForgotPassword]] login/forgot-password.php + login/reset-password.php (token-based, 1hr expiry)

Still Needs Migration (priority order)

  1. login/login.phpDONE (2026-03-27)
  2. login/register.phpDONE (2026-03-27)
  3. login/forgot-password.phpDONE (2026-03-27)
  4. login/change-password.php — modX [[!ChangePassword]] → rewrite using changePassword() in lib/auth.php
  5. dashboard/crop-analysis/soil-test-data/soil-analysis-pdf.php — mysqli → PDO, SQL injection fix
  6. dashboard/crop-analysis/soil-test-data/soil-report.php — display page audit
  7. dashboard/crop-analysis/soil-test-data/soil-report-pdf.php — mysqli → PDO
  8. dashboard/crop-analysis/plant-test-data/ — full migration
  9. dashboard/crop-analysis/animal-dietary-balance/ — full migration
  10. dashboard/crop-analysis/water-test-data/ — full migration
  11. dashboard/client-settings/product-list.php — mysqli → PDO
  12. dashboard/client-settings/updateproduct.php — SQL injection fix
  13. dashboard/crop-cards/index.php — mysqli → PDO
  14. dashboard/dashboard.php — replace [[$widget]] chunks with PHP components
  15. api/updateweatherstation.php — critical SQL injection fix
  16. api/api.php — remove deprecated mysql_connect(), use PDO
  17. client-assets/table/gettable.php — AJAX DataTable endpoint, mysqli → PDO

Legacy files to delete after migration

  • post.php (replaced by components/clientDetailsForm.php)
  • newClientDetails.php (replaced by components/newClientModal.php)
  • soilAnalysisCalcs.php (dev/debug file)
  • test-analysis.php (dev/debug file)
  • dashboard/crop-analysis/soil-test-data/soil-submit.php (replaced by controllers/soilTestSubmit.php)

Security Audit

Safe (PDO prepared statements)

  • config/database.php
  • lib/soil_calculations.php
  • components/clientDetailsForm.php
  • controllers/newClientSubmit.php
  • controllers/soilTestSubmit.php
  • dashboard/crop-analysis/soil-test-data/soil-analysis.php
  • dashboard/crop-analysis/soil-test-data/soil-report.php

Critical vulnerabilities (SQL injection via unescaped params)

File Issue
api/updateweatherstation.php 40+ unescaped GET params in INSERT
newClientDetails.php POST params concatenated in INSERT
post.php $modx_user directly in SELECT WHERE
soilAnalysisCalcs.php GET id directly in SELECT WHERE
dashboard/crop-analysis/soil-test-data/soil-submit.php POST params in INSERT
dashboard/crop-analysis/soil-test-data/soil-analysis-pdf.php GET params in SELECT
dashboard/crop-analysis/soil-test-data/soil-report-pdf.php GET params in SELECT
dashboard/crop-analysis/soil-test-data/base-saturation-pie.php GET params in SELECT
dashboard/crop-analysis/animal-dietary-balance/animal-submit.php POST params in INSERT
dashboard/crop-analysis/plant-test-data/generating-plant-analysis.php POST params in INSERT
dashboard/client-settings/updateproduct.php String concatenation in INSERT
dashboard/crop-cards/index.php $client_id in SELECT
client-assets/table/gettable.php Dynamic query from POST params
api/api.php Uses removed mysql_connect() (PHP 7+: fatal error)

Other security issues

  • Hardcoded credentials in multiple legacy files (root/R3M0T31 and cropmonitor/brvnCcaEYxlPCS3)
  • .env file is empty — credentials should move there
  • lib/auth.php hasPermission() always returns true — RBAC not yet implemented

Key Files Reference

Config & Libraries

File Purpose
config/database.php PDO connection, getDBConnection() function
lib/auth.php isLoggedIn(), requireLogin(), getCurrentUserId()
lib/csrf.php generateCsrfToken(), verifyCsrfToken(), regenerateCsrfToken()
lib/validation.php sanitizeString(), validateNumeric(), ValidationException
lib/soil_calculations.php soilAnalysisReportCalcs(), soilProgramCalcs()
lib/db.php Empty — intended for shared DB helpers
lib/flash.php Empty — intended for flash messages

Layouts

File Purpose
layouts/header.php HTML <head>, Bootstrap 5 CDN, CSS includes. Expects $pageTitle, $siteName
layouts/navbar.php Top navigation bar
layouts/sidebar.php Left sidebar navigation
layouts/footer.php Closing tags + JS includes

Components

File Purpose
components/clientDetailsForm.php Client dropdown + auto-fill (PDO, session user filter)
components/newClientModal.php Bootstrap modal to add client (CSRF protected)
components/soilAnalysisForm.php Full soil test entry form (~50 fields, 7 sections)
components/navigation.php Auth-aware navigation

Controllers

File Purpose
controllers/newClientSubmit.php AJAX POST handler: creates client in client_records
controllers/soilTestSubmit.php POST handler: validates + inserts soil test, runs calculations, redirects to analysis

modX Tags Reference

Replaced

Tag Replacement
[[!clientDetailsFORM]] components/clientDetailsForm.php
[[!newClientDetails]] components/newClientModal.php
[[!soilformSubmit]] controllers/soilTestSubmit.php
[[!Personalize?]] + [[Wayfinder?]] components/navigation.php
[[$dash-header]] layouts/header.php + layouts/navbar.php
[[$dash-footer]] layouts/footer.php

Still present in codebase (needs replacement)

Tag Location Replace with
[[*longtitle]] login/*.php PHP variable $pageTitle
[[++site_name]] login/*.php config/constants.php constant
[[!++site_url]] login/*.php Base URL constant
[[++modx_charset]] login/*.php 'UTF-8'
[[*introtext]], [[*description]] login/*.php Page-level PHP vars
[[!Login?...]] login/login.php Custom PHP session login
[[!Register?...]] login/register.php Custom PHP registration
[[!ForgotPassword?...]] login/forgot-password.php Custom PHP password reset
[[!ChangePassword?...]] login/change-password.php Custom PHP password update
[[!Profile]] login/login.php Session user data
[[$test-widget]], [[$client-widget]], etc. dashboard/dashboard.php PHP components
[[~4]], [[~5]], [[~10]] login/*.php Hardcoded URL constants

Coding Patterns to Follow

Page template pattern

<?php
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../lib/auth.php';
require_once __DIR__ . '/../../lib/csrf.php';

requireLogin();

$pageTitle = 'Page Title';
$siteName  = 'Crop Monitor';

include __DIR__ . '/../../layouts/header.php';
include __DIR__ . '/../../layouts/navbar.php';
include __DIR__ . '/../../layouts/sidebar.php';
?>
<!-- page content -->
<?php include __DIR__ . '/../../layouts/footer.php'; ?>

PDO query pattern

$pdo  = getDBConnection();
$stmt = $pdo->prepare('SELECT * FROM soil_records WHERE id = ? AND rand = ?');
$stmt->execute([$recordId, $randId]);
$row  = $stmt->fetch();

Output escaping

Always use htmlspecialchars($value, ENT_QUOTES, 'UTF-8') when echoing user or DB data into HTML.

CSRF in forms

<input type="hidden" name="csrf_token" value="<?= generateCsrfToken() ?>">

URL parameters used by soil analysis pages

Param Type Meaning
cid int client_records.id
rid int soil_records.id
rand float soil_records.rand (secondary auth token)
stid string crop/soil type

Architecture Decisions

  • No framework — plain PHP, manual includes, no routing library
  • Layout systemlayouts/ includes (not a templating engine)
  • Folder structure — keep existing dashboard/crop-analysis/ paths (no MVC rename needed unless requested)
  • Authentication — session-based ($_SESSION['user_id']); RBAC via hasPermission() not yet implemented
  • Asset pipeline — Bootstrap/jQuery via CDN; custom CSS/JS in client-assets/
  • PDF generationpdfchrome.php (headless Chrome); also FPDF/mPDF patterns in some pages

New auth files (2026-03-27)

File Purpose
database/migrations/001_create_users.sql Run once — creates users + password_resets tables
lib/auth.php loginUser(), logoutUser(), registerUser(), createPasswordResetToken(), validatePasswordResetToken(), resetPassword(), changePassword()
login/_head.php Shared minimal HTML head for auth pages (Bootstrap 5, no sidebar)
login/_foot.php Closing tags + Bootstrap JS
login/login.php Email + password login with CSRF
login/register.php Full registration form with server-side validation
login/forgot-password.php Email submission for reset token
login/reset-password.php Token-validated password reset
login/logout.php Session destruction + redirect

Note on email sending: forgot-password.php generates the token and logs it via error_log(). No email is sent until SMTP is configured. The reset link format is /login/reset-password.php?token={token}.

Open Questions

  1. URL compatibility: Must URL slugs matching modX resource IDs (e.g., page 41, 66) be preserved for external links?
  2. Credentials: Move DB password to .env file and load with vlucas/phpdotenv or manual parse_ini_file()?
  3. Email / SMTP: Configure SMTP (e.g., PHPMailer + SMTP credentials) to enable password reset emails.
  4. Role-based access: hasPermission() is a stub — what roles/permissions are needed?

Last updated: 2026-03-27