Project: Galette - Membership management web application for non-profit organizations
License: GPL-3.0
Main Branch: develop (development), master (stable releases)
Language: PHP 8.3+ with Twig templates, JavaScript/CSS frontend
Documentation: https://doc.galette.eu/
# Install all dependencies (PHP + JavaScript)
bin/install_deps
# Set up database for testing
bin/console galette:install [options]
# Build frontend assets
npm run build
# Run tests (MySQL)
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/
# Run tests (PostgreSQL)
DB=pgsql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/
# Check code quality
vendor/bin/php-cs-fixer fix --dry-run
vendor/bin/phpcs
vendor/bin/phpstan analysegalette/
├── .github/workflows/ # CI/CD pipelines
├── bin/
│ ├── install_deps # Install all dependencies (USE THIS)
│ └── console # CLI tool (includes galette:install)
├── galette/ # Main application
│ ├── lib/ # Core PHP code
│ ├── templates/ # Twig templates
│ ├── webroot/ # Public web root
│ ├── config/ # Configuration files
│ ├── data/ # Data storage (writable)
│ └── lang/ # Translations (gettext .po/.mo)
├── tests/ # PHPUnit test suite
├── ui/ # Frontend source files
├── patches/ # Database migrations
├── stubs/ # IDE helper stubs
├── composer.json # PHP dependencies
├── package.json # JavaScript dependencies
├── phpunit.xml.dist # Test configuration
├── phpstan.neon # Static analysis config
├── .php-cs-fixer.dist.php # Code style config
└── .phpcs.xml # CodeSniffer config
Minor PHP, MySQL, Postgres versions are defined in galette/includes/sys_config/versions.inc.php (see GALETTE_PHP_MIN, GALETTE_MYSQL_MIN, GALETTE_PGSQL_MIN).
- Backend: PHP with Slim Framework
- Frontend: JavaScript, Gulp build system, Semantic UI
- Templates: Twig
- Databases: MySQL/MariaDB or PostgreSQL (required)
- Testing: PHPUnit with pcov for coverage
- Quality Tools: PHPStan, PHP-CS-Fixer, PHPCS, Rector
- PHP: (see versions)
- PHP Extensions: curl, date, dom, fileinfo, gd, gettext, intl, json, mbstring, pdo (pdo_mysql or pdo_pgsql), session, SimpleXML, ssl, tidy, xml
- pcov (for coverage — not Xdebug):
pecl install pcov - Node.js (LTS), Composer 2.x
- Database: MySQL/MariaDB or PostgreSQL (see versions)
-
Install dependencies:
bin/install_deps
This script handles both
composer installandnpm install. Note: If you encounter permission errors, do NOT usesudo. Check directory permissions forvendor/andnode_modules/. -
Set up database (required for tests):
bin/console galette:install \ --db-type mysql \ --db-host localhost \ --db-name galette_test \ --db-user galette \ --db-pass password \ --admin-user admin \ --admin-pass admin
Check
.github/workflows/ci-linux.ymlfor reference parameters. -
Build frontend assets:
npm run build
When you start working:
- Pull latest changes
- Run
bin/install_depsto update dependencies - Run
npm run buildif frontend files changed
Before committing:
- Fix code style:
vendor/bin/php-cs-fixer fix - Check standards:
vendor/bin/phpcs - Run static analysis:
vendor/bin/phpstan analyse - Run tests:
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/ - Build assets:
npm run build(if you modifiedui/directory)
CRITICAL: Tests require a database. The DB environment variable is mandatory.
# Run all tests on MySQL/MariaDB
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/
# Run all tests on PostgreSQL
DB=pgsql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/
# Run specific test file
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/Core/SpecificTest.php
# Run with HTML coverage report (requires pcov)
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php \
--coverage-filter galette/lib \
--coverage-html tests/coverage \
tests/Galette/
# Run with clover XML for CI tools
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php \
--coverage-filter galette/lib \
--coverage-clover tests/clover.xml \
tests/Galette/📚 Detailed E2E documentation: tests/e2e/README.md
E2E tests use Playwright and require a running PHP built-in server.
# 1. Initialize test data
php tests/init_test_data.php
# 2. Set up test database (once)
GALETTE_TESTS=1 DB=mysql bin/console galette:install ...
# 3. Seed fixture data (for *.fixture.spec.ts tests)
GALETTE_TESTS=1 DB=mysql bin/console galette:seed-fixtures
# 4. Start the server (in a separate terminal or background)
DB=mysql php -S 0.0.0.0:8090 -t galette/webroot tests/router_e2e.php
# 4. Run Galette tests (choose your browser)
npm run test:chromium # Test with Chromium only
npm run test:firefox # Test with Firefox only
npm run test:full # Test with all configured browsers
npm run test:headed # Run tests in headed mode (see browser)
npm run test:debug # Run tests in debug mode (step through)
# 5. Run all tests (Galette + installed plugins)
npm run test:all # All browsers
npm run test:all:chromium # Chromium only
# 6. Run a specific plugin's tests
npx playwright test galette/plugins/plugin-oauth2/tests/e2e/specs/
# 7. View test results
npm run report # Open HTML test reportTest Structure:
- Test specs:
tests/e2e/specs/*.spec.ts(isolated tests) and*.fixture.spec.ts(tests using seeded fixtures) - Plugin test specs:
galette/plugins/*/tests/e2e/specs/*.spec.ts - Page Objects:
tests/e2e/pages/(reusable page interactions) - Configuration:
playwright.config.ts - Reports:
playwright-report/index.html
Test Organization:
*.spec.ts- Tests that create their own data (CRUD operations)*.fixture.spec.ts- Tests using pre-seeded fixture data (100+ members from Star Wars, Harry Potter, etc.)- See
tests/e2e/TEST_CREDENTIALS.mdfor fixture user credentials
Plugin E2E tests: Plugins can place their Playwright specs under
galette/plugins/<name>/tests/e2e/specs/. They are automatically discovered
by the root playwright.config.ts via testDir: './galette/plugins' and the
testMatch glob */tests/e2e/specs/**/*.spec.ts.
Shared fixtures for plugins: The tsconfig.json alias @e2e/* maps to
tests/e2e/*, so plugin specs can import Galette fixtures with:
import { test } from '@e2e/fixtures/auth.fixture';CRITICAL: Always use the tests/router_e2e.php router with php -S to ensure the correct test environment is loaded (session path, data path, etc.).
- Database must be installed via
bin/console galette:install - Database user needs full privileges: CREATE, DROP, INSERT, UPDATE, DELETE, SELECT
- Always use
--test-suffix=.phpflag - Always set
DBenvironment variable (mysql or pgsql) - Coverage requires pcov extension:
pecl install pcov
# Check what would be fixed
vendor/bin/php-cs-fixer fix --dry-run --diff
# Fix code style automatically
vendor/bin/php-cs-fixer fix
# Fix specific directory
vendor/bin/php-cs-fixer fix galette/lib/Config: .php-cs-fixer.dist.php (PSR-12 based)
Rule: ALWAYS run before committing PHP changes.
There are some changes done with rector/php-cs-fixer that cause PHPCS issues. Run phpcbf as last step.
# Check code standards
vendor/bin/phpcs
# Auto-fix where possible
vendor/bin/phpcbf
# Check specific directory
vendor/bin/phpcs galette/lib/Config: .phpcs.xml
# Run analysis
vendor/bin/phpstan analyse
# Run with maximum strictness
vendor/bin/phpstan analyse --level=max
# Generate baseline for existing issues
vendor/bin/phpstan analyse --generate-baselineConfig: phpstan.neon
Rule: Fix errors, don't ignore them (unless adding to baseline for legacy code).
# Preview changes
vendor/bin/rector process --dry-run
# Apply changes
vendor/bin/rector process
# Process specific directory
vendor/bin/rector process galette/lib/Config: rector.php
Warning: Review changes before committing. Run tests after applying.
# Check Twig templates for errors
vendor/bin/twigcs galette/templates/default --severity error --display blockingNote: This runs in CI. Fix Twig syntax errors before committing template changes.
# Check license headers in PHP files
vendor/bin/docheader check galette/config galette/lib galette/includes galette/install galette/webroot testNote: Ensures all PHP files have correct license headers.
If possible, especially when updating dependencies or adding new ones, composer commands must be run with the correct version. php --version will give you the information. You can also check for the presence of the php82, php83, php84 etc commands.
composer files are as usual at the root of the project, but vendor directory is located at galette/vendor.
The .github/workflows/ci-linux.yml workflow runs on every push/PR:
- Tests on multiple PHP versions (8.3 => 8.5)
- Tests on both MySQL and PostgreSQL
- Code style check (PHP-CS-Fixer)
- Code standards check (PHPCS)
- Static analysis (PHPStan)
- Frontend build verification
- Twig template linting (TwigCS)
- Rector refactoring check
- License header check (docheader)
- Dependency analysis
# Full CI check sequence
bin/install_deps
bin/console galette:install [options]
npm run build
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/
vendor/bin/php-cs-fixer fix --dry-run
vendor/bin/phpcs
vendor/bin/phpstan analyseIf any of these fail locally, CI will fail.
- Branch from
develop:git checkout -b feature/feature-name develop - Install dependencies:
bin/install_deps - Set up test database if needed:
bin/console galette:install [options] - Write code in
galette/lib/orgalette/templates/ - Add tests in
tests/ - If frontend changes: modify
ui/and runnpm run build - Run quality checks (PHP-CS-Fixer, PHPCS, PHPStan)
- Run tests:
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/ - Commit with clear message
- Push and create PR
- Branch from appropriate base (
developormaster) - Write failing test that reproduces bug
- Fix the bug
- Verify test passes:
DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/[TestFile].php - Run full test suite and quality checks
- Commit and create PR
- Edit files in
ui/directory (NOT ingalette/webroot/) - Build:
npm run build - Test in browser
- For development, use watch mode:
npm run watch - Built files appear in
galette/webroot/themes/default/ui/
- Create migration in
patches/following naming:YYYY-MM-DD_description.sql - Test on clean database
- Test on existing database with data
- Update model classes in
galette/lib/ - Add tests for schema changes
- Test on both MySQL and PostgreSQL if possible
Writable directories (production):
galette/config/- Only during installationgalette/data/- Always writable (attachments, cache, logs, photos, exports, imports, files, tempimages)
Security: Only expose galette/webroot/ to the web server.
php -d memory_limit=512M $(which composer) installrm -rf node_modules package-lock.json
npm install
npm run build- Verify database server is running
- Run:
bin/console galette:install [options] - Check database credentials
- Ensure
DBenvironment variable is set
composer dump-autoloadThis is expected when switching branches. Run and commit:
vendor/bin/php-cs-fixer fix# Install pcov (not xdebug)
pecl install pcov
# Verify it's enabled
php -m | grep pcov- Follow PSR-12
- Use type declarations (parameters and return types)
- Document public methods with PHPDoc
- Keep methods under 50 lines when possible
- Write tests for all new features
- Test names should be descriptive:
testMethodNameDoesExpectedBehaviorWhenCondition() - Mock external dependencies in unit tests
- Aim for high coverage on business logic
- Branch from
developfor features - Use descriptive names:
feature/add-export,fix/email-validation - Write clear commit messages (what and why)
- Keep PRs focused (one feature/fix per PR)
- Squash small "fix" commits before merging
- Always use prepared statements
- Never concatenate SQL strings
- Test migrations on both empty and populated databases
- Include rollback capability when possible
- Edit source files in
ui/, not built files - Always run
npm run buildafter changes - Test in multiple browsers if possible
- Galette is used by organizations with thousands of members
- Optimize database queries (use EXPLAIN on complex queries)
- Avoid N+1 query problems (use eager loading)
- Consider pagination for large datasets
- Cache expensive operations when appropriate
- Translation files:
galette/lang/ - Format: gettext (.po/.mo files)
- Managed via Weblate: https://hosted.weblate.org/projects/galette/
- After updating translatable strings:
bin/update_strings.sh
- galette/config/behavior.inc.php - Application behavior customization
- galette/config/config.inc.php - Main application configuration (generated during install)
- gulpfile.js - Build task definitions
- semantic.json - Semantic UI theme configuration
- ui/semantic/src/theme.config - Theme selection
- .php-cs-fixer.dist.php - Code style rules (PSR-12 based)
- .phpcs.xml - CodeSniffer rules
- phpstan.neon - Static analysis level and rules
- rector.php - Automated refactoring rules
- phpunit.xml.dist - Test suite configuration
- playwright.config.ts - E2E test configuration
- Bug Tracker: https://bugs.galette.eu/projects/galette
- Official Website: https://galette.eu
- Documentation: https://doc.galette.eu/
- Documentation Repo: https://github.com/galette/galettedoc (reStructuredText, built with Sphinx, hosted on ReadTheDocs)
-
Follow these instructions first. Only search for additional information if these instructions are incomplete or contradictory.
-
Use provided scripts. Always use
bin/install_depsfor dependencies (it's what CI uses). -
Database is required for tests. Set it up with
bin/console galette:installbefore testing. -
Use correct test command. Always include
DB=mysql(orpgsql) and--test-suffix=.php:DB=mysql galette/vendor/bin/phpunit --test-suffix=.php tests/Galette/
-
Code quality is mandatory. Run PHP-CS-Fixer, PHPCS, and PHPStan before every commit.
-
Build frontend when needed. If you modify
ui/, runnpm run build. -
Check CI workflows for examples. Look at
.github/workflows/ci-linux.ymlfor reference commands. -
Test on appropriate database. Use the database type relevant to the task (MySQL or PostgreSQL).
-
Read error messages carefully. They usually explain what's wrong.
-
Consider performance. Galette handles thousands of members; optimize accordingly.
-
Create migrations for schema changes. Never modify database structure without a migration file in
patches/. -
Work on develop branch. Unless told otherwise, branch from and merge to
develop. -
Prefer LSP over Grep for code navigation. Warn the user if you do not have access. Use LSP operations (
goToDefinition,findReferences,hover,documentSymbol,workspaceSymbol,incomingCalls,outgoingCalls) for symbol navigation. Fall back to Grep only for non-symbol searches (string literals, comments, regex patterns) or when LSP is unavailable.