Skip to content

Latest commit

 

History

History
100 lines (75 loc) · 7.47 KB

CLAUDE.md

File metadata and controls

100 lines (75 loc) · 7.47 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What This Is

FluentAuth (fluent-security) is a WordPress security plugin providing login security, audit logging, magic login, 2FA, social login (Google/GitHub/Facebook), login customization, and system email management.

Who It Is For — read this before designing anything

Small businesses. Usually one administrator. Often the owner is the only user.

This is not enterprise software and must not be built like it. Keep things stupid simple. When a design decision is open, take the simpler branch — even when the more thorough one is more defensible in the abstract.

What that rules out, concretely:

  • Do not intercept ordinary traffic to enforce a policy. No blanket refusals of REST calls, admin-ajax calls, or page loads. A guardrail that 403s normal site activity costs a real site owner more than the thing it prevents, and the symptom never points back at this plugin. Enforce at the door — during login — where the answer is unambiguous and nothing else can break.
  • Prefer telling people over stopping them. An admin notice with a link to the fix beats a redirect, a modal, or a locked screen. If a setting takes effect at next login, say so and let them carry on.
  • One way to do a thing, not three. No layered fallbacks or backstops "in case the first one is bypassed".
  • Do not add a setting, filter, or allowlist to soften a guardrail — remove the guardrail instead.

The load-bearing example: 2FA enforcement used to redirect users out of wp-admin and refuse admin-ajax and REST wholesale for anyone who owed a second factor. It broke front-end form submissions and add-to-cart for logged-in members, and one missing allowlist entry locked a 3.0.1 user out of their own site with no route back in. All of it was replaced by a single admin notice (TwoFaReminderHandler), because the requirement is already applied during login by EnrollmentTwoFaMethod, before a cookie exists. Less code, no breakage, same protection where it counts.

Commands

# PHP tests
composer test                          # Run PHPUnit suite
./tests/vendor/bin/phpunit tests/Unit/HelperTest.php  # Single test file
./tests/vendor/bin/phpunit --filter "testMethodName"   # Single test method
composer test-coverage                 # HTML coverage report

# Static analysis
composer phpstan                       # PHPStan level 5 (outputs to phpstan-errors.md)

# Frontend build (Laravel Mix — no npm scripts defined, use npx directly)
npx mix                                # Development build
npx mix --production                   # Production build
npx mix watch                          # Watch mode

# Release build
sh build.sh --loco --node-build        # Full build for WP.org distribution

Architecture

Plugin Bootstrap

Entry point: fluent-security.php — defines constants, registers a custom PSR-4-style SPL autoloader for the FluentAuth\ namespace (maps FluentAuth\App\* to app/*), then loads hooks and REST routes.

Namespace & Directory Map

  • FluentAuth\App\Http\Controllers\ — REST API controllers (5 controllers: Settings, Logs, SocialAuthApi, SystemEmails, SecurityScan)
  • FluentAuth\App\Http\routes.php — All REST endpoint definitions (namespace: /wp-json/fluent-auth/)
  • FluentAuth\App\Services\ — Business logic (AuthService, social auth services, SystemEmailService)
  • FluentAuth\App\Services\DB\ — Custom fluent query builder wrapping wpdb; accessed via flsDb() global
  • FluentAuth\App\Hooks\Handlers\ — 12 WordPress hook handlers, each with a register() method
  • FluentAuth\App\Hooks\hooks.php — Instantiates and registers all handlers
  • FluentAuth\App\Helpers\ — Helper (settings/utilities), Arr (array ops), Activator (DB migrations), BrowserDetection
  • FluentAuth\App\Views\ — PHP templates (magic login views, email templates)
  • src/admin/ — Vue 3 admin SPA (components: Dashboard, Settings, Logs, SocialAuthSettings, AuthCustomizer, ServerMode, SecurityScan, CustomWpEmails)
  • src/admin/styles/ — all admin CSS. Vue SFCs carry no <style> blocks; every rule lives in a partial here, listed in load order in src/admin/app.scss (which documents the layering). A rule belongs with the screen that renders it, and moves up to _ui.scss only once a second screen needs it.
  • src/public/ — Public-facing JS (magic_url.js, one_tap.js, login_helper.js, login_customizer.scss)

Key Patterns

  • Database access: Always use flsDb()->table('fls_auth_logs')->where(...)->get() (Laravel-style query builder). Two custom tables: fls_auth_logs, fls_login_hashes.
  • REST API: Routes defined in app/Http/routes.php using the custom Router class with method chaining. Default permission: manage_options, overridable via fluent_auth/app_permission filter.
  • Error handling: Return \WP_Error objects from controllers/services for API errors.
  • Settings: Stored in wp_options under key __fls_auth_settings. Retrieved/managed via Helper::getAuthSettings().
  • Hook handlers: Each handler in app/Hooks/Handlers/ is a class with a register() method that hooks into WordPress actions/filters.
  • Frontend: Vue 3 + Element Plus + Vue Router, built with Laravel Mix. Admin app bootstraps from src/admin/app.js using window.fluentAuthAdmin for server-side data. REST calls use mixin methods $get, $post, $put, $del. Vue i18n via $t() mixin method.
  • i18n text domain: 'fluent-security'

Testing

Tests run standalone without WordPress via comprehensive mocks in tests/bootstrap.php (mocks WP functions, database, REST classes). Test namespace: FluentAuth\Tests\ (PSR-4 in autoload-dev). Unit tests in tests/Unit/, integration tests in tests/Integration/. Mock WordPress classes (WP_Error, WP_REST_Request, WP_User) are in tests/Unit/MockClasses.php.

Code Style

  • PHP: PascalCase classes, camelCase methods/variables, UPPER_SNAKE_CASE constants. Follow WordPress coding standards. Sanitize input (sanitize_text_field, sanitize_url), escape output (esc_html, esc_url).
  • Vue/JS: PascalCase component files, kebab-case in templates. ES6+, async/await. SCSS with BEM naming (.fframe_app, &__body). <script> before <template> before <style> in SFCs.
  • Translations: Use __('text', 'fluent-security') in PHP and $t('text') in Vue. Never split a sentence across several $t() calls or join a $t() result to a value; use placeholders ($t('Try again in %s minutes.', minutes), $_n('%s file changed', '%s files changed', n)), and $_x('Open', 'Verb') when one English word needs different translations in different places. Vue strings reach translators through the generated app/Services/TransStrings.php: after adding or changing a $t() / $_n() / $_x() string, run npm run translate. Put a <!-- translators: ... --> or // translators: ... comment on the line directly above any string with placeholders; npm run translate fails on a placeholder string without one, on em/en dashes in UI text, and on keys with leading or trailing whitespace. Long paragraphs go in reserved18n.json under a __snake_case_key__ and the template calls $t('__snake_case_key__'). Write for a small-business owner: short sentences, one idea each, everyday words. Rewording a string that is already clear costs its translation in every locale, so leave good strings alone. See docs/js-translations.md.
  • Commits: Run composer phpstan before committing.