SolidInvoice - AI Assistant Guide
This document provides comprehensive guidance for AI assistants working with the SolidInvoice codebase. It covers the architecture, conventions, workflows, and best practices to help you understand and effectively contribute to this project.
SolidInvoice - AI Assistant Guide
This document provides comprehensive guidance for AI assistants working with the SolidInvoice codebase. It covers the architecture, conventions, workflows, and best practices to help you understand and effectively contribute to this project.
Table of Contents
- Project Overview
- Technology Stack
- Codebase Structure
- Architecture & Design Patterns
- Development Workflow
- Testing Strategy
- Code Quality & Standards
- Common Tasks & Commands
- Key Conventions
- Database & ORM
- API Development
- Frontend Development
- Security Considerations
Project Overview
SolidInvoice is a sophisticated open-source invoicing application designed for small businesses and freelancers. It provides comprehensive billing operations including:
- Client and contact management
- Quote creation and management
- Invoice generation and tracking (including recurring invoices)
- Online payment processing (multiple gateways via Payum)
- Tax and discount handling
- RESTful API for integrations
- Multi-channel notifications (email, SMS, webhooks)
Current Version: 2.3.11 License: MIT Primary Author: Pierre du Plessis
Current Status
The current branch is in the process of a UI rewrite from AdminLTE (Bootstrap 4) to Tabler (Bootstrap 5.3). Any changes to templates or frontend code should be made in accordance with the new Tabler design system.
Technology Stack
Backend
| Component | Technology | Version |
|---|---|---|
| Framework | Symfony | 7.1+ |
| Platform | SolidWorx/Platform | dev-main |
| PHP | PHP | 8.4+ |
| ORM | Doctrine ORM | 2.15+ |
| Migrations | Doctrine Migrations | 3.5+ |
| Database | MySQL/PostgreSQL/SQLite | MySQL 8.0+ recommended |
| API Framework | API Platform | 4.0+ |
| PDF Generation | mPDF | 8.0+ |
| Money Handling | moneyphp/money | 4.5+ |
| Task Scheduling | Symfony Schedule | 7.1+ |
| Payment Processing | Payum | 1.7+ |
| Workflow | Symfony Workflow | 7.1+ |
Frontend
| Component | Technology | Version |
|---|---|---|
| Build Tool | Webpack (Symfony Encore) | 5.3+ |
| CSS Preprocessor | Sass | 1.63+ |
| JavaScript Framework | Stimulus | 3.2+ |
| UI Framework | Tabler (Bootstrap) | 1.4+ |
| Icons | FontAwesome | 6.4+ |
| Package Manager | Bun | 1.3+ |
Development Tools
- Static Analysis: PHPStan (Level 6)
- Coding Standards: EasyCodingStandard (Symplify)
- Code Refactoring: Rector (PHP 8.4+)
- Testing: PHPUnit 10.4+, Mockery, Symfony Panther
- Fixtures: Foundry
- CI/CD: GitHub Actions
Distribution
- Docker: Official SolidInvoice Docker images available on Docker Hub (solidinvoice/solidinvoice). Runs the FrankenPHP binary inside the container.
- FrankenPHP: Official recommended installation method. Application is built into a single binary, which contains PHP, all required extensions, the web server, and the application code.
- Archive: ZIP/TAR archives for manual installation (all assets pre-compiled)
Codebase Structure
Root Directory Layout
/home/user/SolidInvoice/
├── assets/ # Frontend JavaScript and SCSS
│ ├── controllers/ # Stimulus controllers
│ ├── img/ # Images and icons
│ ├── scss/ # Sass stylesheets
│ ├── controllers.json # Stimulus config
│ └── core.ts # Main application entry
├── bin/ # Executables (console, phpunit, etc.)
├── config/ # Symfony configuration
│ ├── packages/ # Package configurations
│ ├── routes/ # Route definitions
│ └── services.php # Service container config
├── docker/ # Docker configuration
├── frankenphp/ # FrankenPHP code and config (Go files and shell scripts to build and compile the binary)
├── migrations/ # Database migrations
├── public/ # Web-accessible files
├── scripts/ # Shell scripts for various tasks
├── src/ # Application source code (18 bundles)
├── templates/ # Twig templates which overrides external bundle templates
├── tests/ # Test bootstrap and utilities
├── var/ # Runtime data (cache, logs)
├── vendor/ # Composer dependencies
Bundle Organization (src/)
SolidInvoice uses a modular bundle architecture with 18 bundles:
Business Logic Bundles
- InvoiceBundle - Invoice management, recurring invoices, cloning, state transitions
- QuoteBundle - Quote creation, management, conversion to invoices
- ClientBundle - Client and contact management with address tracking
- PaymentBundle - Payment processing with Payum integration
- TaxBundle - Tax rate management and calculations
User & Security
- UserBundle - User management, API tokens, authentication
System & Infrastructure
- CoreBundle - Core utilities, entities, billing logic, PDF generation, Twig extensions
- ApiBundle - REST API implementation with API Platform
- MailerBundle - Email configuration and delivery
- SettingsBundle - Application configuration management
- InstallBundle - Installation wizard and setup
- CronBundle - Scheduled task management
UI & Presentation
- DashboardBundle - Dashboard widgets and analytics
- DataGridBundle - Data grid/table rendering
- FormBundle - Form customizations
Specialized Services
- NotificationBundle - Multi-channel notifications (email, SMS, webhooks)
- MoneyBundle - Money type handling with moneyphp/money library
- SaasBundle - SaaS features like subscriptions and usage tracking
Bundle Internal Structure
Each bundle follows this pattern:
BundleNameBundle/
├── Action/ # Action classes (entry points for HTTP requests)
├── Entity/ # Doctrine ORM entities
├── Form/ # Symfony Form types and handlers
├── (Listener|EventSubscriber)/ # Event listeners and subscribers
├── Manager/ # Complex business logic managers
├── Repository/ # Database access objects
├── Resources/ # Configuration, templates, assets
│ ├── config/ # Bundle-specific configs
│ │ ├── routing/ # Route configuration
│ │ └── services/ # DI container services
│ ├── translations/ # Translation files
│ └── views/ # Twig templates
├── Tests/ # Unit and functional tests
│ ├── Functional/ # Functional tests
│ └── Unit/ # Unit tests (not in a `Unit` directory, but just in the top-level Tests directory)
└── BundleNameBundle.php
Architecture & Design Patterns
Core Patterns
1. Modular Bundle Architecture
- Each feature has its own bundle with clear boundaries
- Bundles communicate via events, not direct coupling
- Dependency injection for all services
2. Action Pattern (Not Controllers)
- Entry points for HTTP requests are Action classes
- Single responsibility per action
- Located in
Action/directory of each bundle
Example:
// src/InvoiceBundle/Action/CreateAction.php
class CreateAction
{
public function __invoke(Request $request): Response
{
// Handle invoice creation
}
}
3. Repository Pattern
- Custom repositories extending Doctrine EntityRepository
- Query optimization and complex business logic isolation
- Located in
Repository/directory
4. Event-Driven Architecture
- Extensive use of Symfony EventDispatcher
- Events for state transitions, entity lifecycle
- Listeners in
Listener/orEventSubscriber/directory
Key events:
InvoiceEvent- Invoice lifecycle eventsPaymentCompleteListener- Payment completion handling- Doctrine lifecycle callbacks
5. Manager Pattern
- Complex domain operations encapsulated in Manager classes
- Examples:
InvoiceManager,PaymentSettingsManager - Located in
Manager/directory
6. State Machine (Workflow)
- Symfony Workflow for invoice state management
- States: draft, pending, recurring, paid, sent, viewed, cancelled
- Graph-based workflow configuration
7. Platform
This application is built using SolidWorx/Platform, which provides foundational services, base entities, and utilities to streamline development. SolidWorx/Platform is built in conjunction with SolidInvoice and is designed to be reusable across multiple projects. For any UI functionality, use the SolidWorx/PlatformUI package which provides Twig templates and components for common styles. In cases where a specific UI component is not available in PlatformUI, mention what is needed so that it can be added to the PlatformUI package for future use.
- All repositories should extend from
SolidWorx\Platform\PlatformBundle\Repository\EntityRepository. - All commands should extend from
SolidWorx\Platform\PlatformBundle\Console\Command.
Entity Traits (Cross-Cutting Concerns)
Common traits used across entities:
// Can archive entities
trait Archivable {
private bool $archived = false;
}
// Automatic timestamps
trait TimeStampable {
private DateTimeInterface $created;
private DateTimeInterface $updated;
}
// Multi-tenancy
trait CompanyAware {
private Company $company;
}
// Money value objects
trait Money {
// Money object fields
}
Dependency Injection
- All services use constructor injection
- Configuration in
config/services.phpand bundle-specific configs - Auto-wiring enabled for most services
Development Workflow
Initial Setup
-
Clone the repository:
git clone https://github.com/SolidInvoice/SolidInvoice.git cd SolidInvoice -
Install PHP dependencies:
composer install -
Install frontend dependencies:
bun install -
Build frontend assets:
bun run dev # Development mode # or bun run build # Production build -
Setup database:
bin/console doctrine:database:create bin/console doctrine:migrations:migrate
Development Commands
# Frontend development
bun run dev # Build assets in dev mode with watch
bun run build # Production optimized build
bun run lint:js # ESLint JavaScript validation
bun run lint:css # StyleLint CSS validation
# Backend development
bin/console cache:clear # Clear cache
bin/console doctrine:migrations:migrate # Run migrations
bin/console doctrine:schema:validate # Validate database schema
# Code quality
bin/ecs check # Check coding standards
bin/ecs check --fix # Fix coding standards
bin/phpstan analyse # Run static analysis
bin/rector process --dry-run # Preview refactoring changes
bin/rector process # Apply refactoring changes
# Testing
bin/phpunit # Run all tests
bin/phpunit --coverage-html coverage # Generate coverage report
Git Workflow
- Branch naming: Feature branches should be descriptive
- Commit messages: Follow conventional commits style
- Pull requests: Must pass all CI checks (tests, CS, static analysis)
CI/CD Pipeline (GitHub Actions)
Every pull request triggers:
-
Unit Tests (
unit-tests.yml)- PHP 8.4 and 8.5
- MySQL 8.0
- Code coverage reporting (Codecov)
- E2E tests with Symfony Panther
-
Coding Standards (
cs.yml)- EasyCodingStandard (PHP)
- Composer normalize
- Super-Linter (YAML, JSON, XML, Markdown, CSS, JavaScript)
-
Static Analysis (
static-analysis.yml)- PHPStan (Level 6)
- Qodana code quality
-
Security Checks (
security-checker.yml)- Composer security vulnerabilities
- CodeQL analysis
Testing Strategy
Test Structure
src/BundleNameBundle/Tests/
├── Functional/
│ ├── Api/ # API endpoint tests
│ └── ...
├── Form/ # Form type tests
├── Repository/ # Repository tests
└── ...
PHPUnit Configuration
Key settings from phpunit.xml.dist:
- Execution: Random order (
executionOrder="random") - Strict mode: All warnings treated as failures
- Database isolation: DAMA/DoctrineTestBundle for transaction wrapping
- E2E testing: Symfony Panther for browser testing
- Environment: Test environment with
.env.test
Test Types
1. Unit Tests
- Test individual classes in isolation
- Use Mockery for mocking dependencies
- Fast execution, no database required
use Mockery as m;
class InvoiceManagerTest extends TestCase
{
public function testCreateInvoice(): void
{
$repository = m::mock(InvoiceRepository::class);
// Test logic
}
}
2. Functional Tests
- Test full request/response cycle
- Use database for realistic scenarios
- Located in
Tests/Functional/
3. API Tests
- Test REST API endpoints
- Extend
ApiTestCasebase class - JSON-LD/HAL response validation
Fixtures
Foundry - Factory-based fixtures
Running Tests
# All tests
bin/phpunit
# Specific bundle
bin/phpunit src/InvoiceBundle/Tests
# Specific test file
bin/phpunit src/InvoiceBundle/Tests/Unit/Manager/InvoiceManagerTest.php
# With coverage
bin/phpunit --coverage-html coverage
# Filter by test name
bin/phpunit --filter testCreateInvoice
Code Quality & Standards
Coding Standards (ECS)
Configuration: ecs.php
Standards Applied:
- PSR-12
- Symfony coding standards
- PHPUnit standards
- Clean code principles
File Header Required:
<?php
declare(strict_types=1);
/*
* This file is part of SolidInvoice project.
*
* (c) Pierre du Plessis <open-source@solidworx.co>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
Commands:
bin/ecs check # Check standards
bin/ecs check --fix # Auto-fix issues
Static Analysis (PHPStan)
Configuration: phpstan.neon
Settings:
- Level: 6
- Symfony container XML analysis
- Doctrine plugin enabled
- Baseline:
phpstan-baseline.neon
Commands:
bin/phpstan analyse # Analyze with baseline
bin/phpstan analyse --no-baseline # Analyze without baseline
Code Refactoring (Rector)
Configuration: rector.php
Rules Applied:
- PHP upgrades
- Symfony best practices
- Doctrine improvements
- PHPUnit modernization
- Code quality improvements
Commands:
bin/rector process --dry-run # Preview changes
bin/rector process # Apply changes
Pre-commit Checklist
Before committing code:
- ✅ Run coding standards:
bin/ecs check --fix - ✅ Run static analysis:
bin/phpstan analyse - ✅ Run tests:
bin/phpunit - ✅ Ensure proper file headers
- ✅ Ensure strict types declaration:
declare(strict_types=1);
Common Tasks & Commands
Creating a New Entity
-
Use Symfony Maker (if available):
bin/console make:entity -
Or manually create in appropriate bundle's
Entity/directory -
Add common traits as needed:
use SolidInvoice\CoreBundle\Traits\Entity\Archivable; use SolidInvoice\CoreBundle\Traits\Entity\TimeStampable; use SolidInvoice\CoreBundle\Traits\Entity\CompanyAware; -
Generate migration:
bin/console doctrine:migrations:diff -
Run migration:
bin/console doctrine:migrations:migrate
Creating a New API Endpoint
-
Add
#[ApiResource]attribute to entity:use ApiPlatform\Core\Annotation\ApiResource; #[ApiResource] class MyEntity { // ... } -
Configure serialization groups if needed
-
Test the endpoint at
/api/my-entities
Adding a New Event Listener
- Create listener class in
Listener/directory - Implement the listener logic
- Use auto-configuration to register the entity
- Tag with appropriate event name if not using auto-configuration
Working with Money Values
Always use Money objects, never raw floats:
use Money\Money;
use Money\Currency;
$amount = Money::USD(1000); // $10.00 (amounts in cents)
$currency = new Currency('USD');
$price = new Money(5000, $currency); // $50.00
Currencies are configured on the Client entity, and should always be used for formatting.
Never use a default currency.
PDF Generation
Use the PDF manager service:
use SolidInvoice\CoreBundle\Pdf\Generator;
$generator->generate($html, $filename);
Sending Emails
Use Symfony Mailer:
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
$email = (new Email())
->to($recipient)
->subject('Invoice #1234')
->html($content);
$mailer->send($email);
Key Conventions
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Entities | Singular noun | Invoice, Quote, Client |
| Repositories | Entity name + Repository | InvoiceRepository |
| Form Types | Name + Type | InvoiceType, ClientType |
| Listeners | Purpose + Listener | InvoicePaidListener |
| Actions | Verb or purpose | CreateAction, EditAction, IndexAction |
| Managers | Entity + Manager | InvoiceManager, PaymentManager |
| Events | Entity + Event | InvoiceEvent, PaymentEvent |
File Organization
- One class per file
- Filename matches class name
- Namespace reflects directory structure
- Use statement ordering: const, class, function
PHP Standards
- Always use strict types:
declare(strict_types=1); - Type hints: Always specify parameter and return types
- Final classes: Prefer
finalclasses unless inheritance needed - Visibility: Always specify (public, private, protected)
- Enums: Use PHP 8.1+ backed enums for fixed sets of values (status, type, etc.), NEVER class constants
- Constants: Use class constants for configuration values, not for enum-like values
Doctrine Best Practices
- Use attributes for mapping (PHP 8+)
- Repository methods should return typed arrays or collections
- Query optimization: Use joins to avoid N+1 queries
- Use filters for soft deletes (ArchivableFilter) and multi-tenancy (CompanyFilter)
Enum Usage (PHP 8.1+)
ALWAYS use backed enums for fixed sets of values:
// GOOD - Use Enum
enum InvoiceStatus: string
{
case Draft = 'draft';
case Pending = 'pending';
case Paid = 'paid';
case Cancelled = 'cancelled';
}
// In entity
#[ORM\Column(enumType: InvoiceStatus::class)]
private InvoiceStatus $status;
// Usage
$invoice->setStatus(InvoiceStatus::Paid);
if ($invoice->getStatus() === InvoiceStatus::Paid) {
// ...
}
// BAD - Don't use class constants for enum-like values
class Invoice
{
public const STATUS_DRAFT = 'draft'; // ❌ Wrong
public const STATUS_PENDING = 'pending'; // ❌ Wrong
public const STATUS_PAID = 'paid'; // ❌ Wrong
}
When to use enums:
- Entity status fields (draft, published, archived)
- Entity type fields (pre_due, overdue_1, overdue_7)
- Fixed categories or classifications
- Any field with a predetermined set of values
When to use constants:
- Configuration values (API_VERSION, MAX_UPLOAD_SIZE)
- Table names (TABLE_NAME)
- Fixed string values that aren't enum-like
Symfony Best Practices
- Constructor injection for dependencies
- Environment variables for configuration
- Twig for all templates
- Form types for all forms
- Validation via annotations/attributes
Database & ORM
Configuration
ORM: Doctrine ORM 2.15+ DBAL: Doctrine DBAL 3.4+ Mapping: PHP 8 Attributes
Database Support
- MySQL 5.7+, 8.0+ (recommended)
- PostgreSQL 10+
- SQLite (Recommended)
UUID Primary Keys
All entities use UUID binary ordered time for primary keys:
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;
#[ORM\Column(name: 'id', type: UlidType::NAME)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UlidGenerator::class)]
private Ulid $id;
Global Doctrine Filters
Two filters are always enabled:
- CompanyFilter - Multi-tenancy: Automatically filters queries by company_id
- ArchivableFilter - Soft deletes: Excludes archived records
Migrations
Location: /migrations/
-
Migrations don't use raw SQL queries but instead use the Doctrine Schema tool. All newly created migrations should use the Schema tool to update the database schema.
-
Migrations don't use the standard naming convention from Doctrine. Instead, use a migration file per version. For example, for version 2.3.11, the migration file should be named
Version203011.php. -
From version 2.4 onwards, migrations are split into separate files using the following naming convention:
Version{major}{minor}{patch}_{partNumber}.php. For example, for version 2.4.0, the migration files would be namedVersion20400_1.php,Version20400_2.php, etc.
Commands:
# Generate migration
bin/console doctrine:migrations:diff
# Run migrations
bin/console doctrine:migrations:migrate
# Check status
bin/console doctrine:migrations:status
# Rollback
bin/console doctrine:migrations:migrate prev
Custom Doctrine Types
json_array- Legacy JSON storageuuid- Standard UUID type- Custom hydrators for Money objects
API Development
Framework
API Platform 4.0+ with full REST API support
Authentication
Token-based authentication via X-API-TOKEN header:
curl -H "X-API-TOKEN: your-token-here" https://example.com/api/invoices
API Endpoints
Main resources:
/api/invoices- Invoice CRUD/api/quotes- Quote CRUD/api/clients- Client CRUD with sub-resources/api/contacts- Contact management/api/payments- Payment records/api/tax- Tax rates
Supported Formats
- JSON-LD (default)
- JSON-HAL
- JSON
- XML
- HTML (API documentation)
Pagination
Default: 30 items per page
Query parameters:
page- Page numberitemsPerPage- Items per page (max 100)
Example:
GET /api/invoices?page=2&itemsPerPage=50
Serialization
Custom normalizers for complex types:
MoneyNormalizer- Money objectsCreditNormalizer- Client creditsDiscountNormalizer- Discount valuesAdditionalContactDetailsNormalizer- Contact details
Serialization groups:
invoice_api- Invoice API representationclient_api- Client API representationDefault- Default serialization
Creating API Resources
use ApiPlatform\Core\Annotation\ApiResource;
#[ApiResource(
collectionOperations: ['get', 'post'],
itemOperations: ['get', 'put', 'delete'],
normalizationContext: ['groups' => ['invoice_api']],
denormalizationContext: ['groups' => ['invoice_write']]
)]
class Invoice
{
// ...
}
Frontend Development
Build System
Webpack 5 via Symfony Encore
Configuration: webpack.config.js
JavaScript Architecture
Framework: Stimulus Pattern: Stimulus controllers for modular JS
Entry Points:
assets/core.ts- Global core functionality
Asset Organization
assets/
├── core.ts # Main entry point
└── scss/ # Stylesheets
├── app.scss # Main styles
├── email.scss # Email templates
└── pdf.scss # PDF styles
Styling
Framework: Tabler 1.4+ (Bootstrap 5.3) Preprocessor: Sass Admin Template: Tabler
Build Commands
# Development
bun run dev # Single build
bun run watch # Watch mode
bun run dev-server # Dev server with HMR
# Production
bun run build # Optimized build
# Linting
bun run lint:js # ESLint
bun run lint:css # StyleLint
Adding New JavaScript
-
Create file in appropriate location:
- Global code:
assets/core.ts
- Global code:
-
Rebuild assets:
bun run dev
Security Considerations
Authentication
- Username/password authentication
- API token authentication
- User invitation system
Authorization
- Role-based access control (RBAC)
- Symfony Security component
- Voter pattern for complex permissions
Multi-Tenancy
- Company-based data isolation
- Automatic filtering via CompanyFilter
- All company-aware entities use
CompanyAwaretrait
Payment Security
- PCI-compliant payment processing via Payum
- Secure token storage
- No raw card data storage
API Security
- Token-based authentication required
- Token history tracking for audit
- Rate limiting (configure as needed)
Sensitive Data
- Never commit credentials
- Use environment variables for secrets
- Encrypted values use defuse/php-encryption
Best Practices
- Input Validation: Always validate user input
- Output Escaping: Twig auto-escapes, but be careful with
rawfilter - SQL Injection: Use Doctrine ORM/DBAL, never raw queries
- CSRF Protection: Enabled by default on forms
- XSS Protection: Validate and sanitize all user input
Additional Resources
Documentation
Important Files
CONTRIBUTING.md- Contribution guidelinesREADME.md- Project overview and installationCHANGELOG.md- Version historySECURITY.md- Security policyUPGRADE.md- Upgrade instructions
Project Links
Quick Reference for AI Assistants
When Adding Features
- ✅ Identify the appropriate bundle (or create new if necessary)
- ✅ Follow the bundle internal structure (Action, Entity, Repository, etc.)
- ✅ Add proper type hints and strict types
- ✅ Include file header comment
- ✅ Write unit tests
- ✅ Update API resources if needed
- ✅ Run code quality tools (ECS, PHPStan)
- ✅ Generate and run migrations if database changes
When Fixing Bugs
- ✅ Add a failing test that reproduces the bug
- ✅ Fix the bug
- ✅ Ensure the test passes
- ✅ Run full test suite
- ✅ Run static analysis
When Refactoring
- ✅ Ensure tests exist and pass
- ✅ Consider using Rector for automated refactoring
- ✅ Maintain backward compatibility unless major version
- ✅ Update documentation if API changes
- ✅ Verify all tests still pass
Code Review Checklist
- Strict types declared
- Proper type hints (parameters and return types)
- File header present
- Follows PSR-12 and project standards
- Tests included
- No hardcoded values (use configuration)
- Proper error handling
- No security vulnerabilities
- Documentation updated if needed
- Passes all CI checks
Design System Guide
This section provides comprehensive guidelines for implementing consistent, modern UI across all SolidInvoice pages. All UI changes MUST follow these guidelines.
Design Philosophy
SolidInvoice follows a Clean & Minimal design aesthetic:
- Content-focused: Reduce visual noise, let data speak
- Consistent spacing: Use the 8px-based spacing scale
- Subtle interactions: Purposeful animations, no decorative effects
- Accessible by default: Proper contrast, focus states, ARIA attributes
Design Tokens
All design values are defined as CSS custom properties with the --swp- prefix in /assets/scss/design-system/_tokens.scss.
Color Palette
| Token | Value | Usage |
|---|---|---|
--swp-primary | #2e963a | Main CTAs, links, active states |
--swp-primary-dark | #1f6c29 | Hover/active states |
--swp-primary-light | #e8f5e9 | Backgrounds, badges |
--swp-secondary | #f0a015 | Accent color (use sparingly) |
--swp-success | #10b981 | Success states, confirmations |
--swp-danger | #ef4444 | Errors, destructive actions |
--swp-warning | #f59e0b | Warnings, cautions |
--swp-info | #3b82f6 | Informational content |
Gray Scale (Slate-based):
--swp-gray-50to--swp-gray-900for text and backgrounds--swp-text-primary,--swp-text-secondary,--swp-text-mutedfor text hierarchy
Spacing Scale (8px base)
| Token | Value | Usage |
|---|---|---|
--swp-space-1 | 0.25rem (4px) | Tiny gaps |
--swp-space-2 | 0.5rem (8px) | Icon gaps, tight spacing |
--swp-space-3 | 0.75rem (12px) | Button padding |
--swp-space-4 | 1rem (16px) | Standard form spacing |
--swp-space-6 | 1.5rem (24px) | Card padding |
--swp-space-8 | 2rem (32px) | Section spacing |
Border Radius
| Token | Value | Usage |
|---|---|---|
--swp-radius-sm | 6px | Small elements, badges |
--swp-radius-md | 8px | Buttons, form controls |
--swp-radius-lg | 12px | Cards |
--swp-radius-xl | 16px | Modals |
Shadows
| Token | Usage |
|---|---|
--swp-shadow-sm | Cards, subtle elevation |
--swp-shadow-md | Hover states, dropdowns |
--swp-shadow-lg | Modals, popovers |
--swp-shadow-primary | Primary button glow |
Typography Guidelines
| Element | Size Token | Weight | Color |
|---|---|---|---|
| Page title | --swp-text-2xl | --swp-font-semibold | --swp-text-primary |
| Card title | --swp-text-lg | --swp-font-semibold | --swp-text-primary |
| Section title | --swp-text-md | --swp-font-semibold | --swp-text-primary |
| Body text | --swp-text-base | --swp-font-normal | --swp-body-color |
| Help text | --swp-text-sm | --swp-font-normal | --swp-text-muted |
| Labels | --swp-text-sm | --swp-font-medium | --swp-text-secondary |
| Table headers | --swp-text-xs | --swp-font-semibold | --swp-text-muted |
Platform UI Components (REQUIRED)
Always use SolidWorx/Platform UI components when available. These are Twig components that provide consistent, accessible UI elements.
Available Components:
| Component | Location | Docs |
|---|---|---|
<twig:Ui:Alert> | vendor/solidworx/platform/src/Bundle/Ui/templates/components/Alert.html.twig | vendor/solidworx/platform/src/Bundle/Ui/Docs/Alert.md |
<twig:Ui:Card> | vendor/solidworx/platform/src/Bundle/Ui/templates/components/Card.html.twig | vendor/solidworx/platform/src/Bundle/Ui/Docs/Card.md |
<twig:Ui:Modal> | vendor/solidworx/platform/src/Bundle/Ui/templates/components/Modal.html.twig | vendor/solidworx/platform/src/Bundle/Ui/Docs/Modal.md |
Usage Examples:
{# Card Component #}
<twig:Ui:Card title="Invoice Details" subtitle="View and edit">
<p>Card body content here</p>
<twig:block name="footer">
<button class="btn btn-ghost" data-bs-dismiss="modal">Cancel</button>
<button class="btn btn-primary">{{ ux_icon('tabler:device-floppy') }} Save</button>
</twig:block>
</twig:Ui:Card>
{# Alert Component #}
<twig:Ui:Alert type="success" icon="tabler:check" title="Saved!" :dismissible="true">
Your changes have been saved successfully.
</twig:Ui:Alert>
{# Modal Component #}
<twig:Ui:Modal id="confirm-modal" title="Confirm Action" status="danger">
<p>Are you sure you want to proceed?</p>
<twig:block name="footer">
<button class="btn btn-ghost" data-bs-dismiss="modal">Cancel</button>
<button class="btn btn-danger">Confirm</button>
</twig:block>
</twig:Ui:Modal>
When a style/feature is needed but not supported:
- First, create custom HTML to achieve the desired result
- Note what feature is missing for future addition to SolidWorx/Platform/UiBundle
- New components will be added to Platform over time
Do NOT:
- Create custom implementations when a Platform component exists
- Override Platform component styles with inline styles
- Duplicate Platform component functionality
Component Usage
Buttons
Variants and when to use:
| Class | Usage |
|---|---|
btn-primary | Main page action, form submit (Save, Create, Confirm) |
btn-secondary | Secondary accent actions (rarely used) |
btn-outline-primary | Secondary actions, Cancel buttons |
btn-outline-secondary | Tertiary actions |
btn-ghost | Minimal actions, navigation-like buttons |
btn-danger | Destructive actions ONLY (Delete, Remove) |
btn-outline-danger | Less prominent destructive actions |
Icon usage in buttons:
<button class="btn btn-primary">
{{ ux_icon('tabler:device-floppy') }} Save
</button>
- Icon BEFORE text
- Use
gap-2(handled by.btnclass) - Icon size: 18px default, 16px for small, 20px for large
Button states:
- Hover: Subtle lift (
translateY(-1px)) + shadow increase - Active: Return to baseline + reduced shadow
- Disabled: 50% opacity, no pointer events
- Loading: Use
.btn-loadingclass for spinner
Cards
Standard card structure:
<div class="card">
<div class="card-header">
<h3 class="card-title">Title</h3>
<div class="card-header-actions">
<!-- Optional action buttons -->
</div>
</div>
<div class="card-body">
<!-- Content -->
</div>
<div class="card-footer">
<!-- Action buttons -->
</div>
</div>
Card variants:
- Default: White background, subtle shadow, 12px radius
.card-flat: No shadow, light border (for nested cards).card-interactive: Hover lift effect (for clickable cards).card-muted: Gray background (for secondary content).card-status-*: Colored top border indicator
Card sections (within body):
<div class="card-section">
<div class="card-section-header">
<h4 class="card-section-title">
{{ ux_icon('tabler:icon') }} Section Title
</h4>
</div>
<!-- Section content -->
</div>
Forms
Standard form field structure:
<div class="mb-4">
<label class="form-label required">Field Label</label>
<input type="text" class="form-control" />
<div class="form-help">Help text appears here</div>
</div>
Form layouts:
- Single column: Default for settings, simple forms
- Two columns: Use
.rowwith.col-md-6for related fields - Use
.form-row-2or.form-row-3for grid layouts
Toggle switches:
<div class="form-switch-field">
<div class="form-check form-switch form-switch-wrapper">
<input type="checkbox" class="form-check-input" role="switch" />
<label class="form-check-label">Toggle Label</label>
</div>
<div class="form-help">Help text</div>
</div>
Input with icon:
<div class="input-group input-icon-group">
<span class="input-group-text">
{{ ux_icon('tabler:mail', {width: 18, height: 18}) }}
</span>
<input type="email" class="form-control" />
</div>
Form Actions Pattern (CRITICAL)
Every form MUST follow this pattern:
┌─────────────────────────────────────────────────────────────────┐
│ [Cancel (btn-ghost)] [Save (btn-primary + icon)]│
└─────────────────────────────────────────────────────────────────┘
Standard implementation:
<div class="card-footer">
<div class="form-actions">
<button type="button" class="btn btn-ghost">
{{ 'Cancel'|trans }}
</button>
<button type="submit" class="btn btn-primary">
{{ ux_icon('tabler:device-floppy') }} {{ 'Save'|trans }}
</button>
</div>
</div>
Rules:
- Cancel button: Ghost or outline style, positioned LEFT or BEFORE save
- Save button: Primary style, with floppy disk icon, positioned RIGHT
- Use
.form-actions-spreadto push Cancel to far left - Danger actions (Delete): Use separate confirmation flow, NOT in main form actions
Multi-action forms:
<div class="form-actions form-actions-spread">
<button type="button" class="btn btn-ghost">Cancel</button>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-primary">Save as Draft</button>
<button type="submit" class="btn btn-primary">
{{ ux_icon('tabler:device-floppy') }} Save
</button>
</div>
</div>
Page Patterns
Settings Pages
Rules:
- Max-width: 900px, centered (use
.settings-page) - Use horizontal tabs for 2-7 sections
- Use sidebar navigation for 8+ sections
- Each settings group in its own card
- Section headers with icon + title
- Danger zone at the bottom with red border
Tab navigation:
<nav class="settings-tabs">
<a href="#company" class="settings-tab active">
{{ ux_icon('tabler:building') }} Company
</a>
<a href="#invoices" class="settings-tab">
{{ ux_icon('tabler:file-invoice') }} Invoices
</a>
</nav>
Danger zone:
<div class="settings-danger-zone">
<div class="card-header">
<div class="settings-card-icon">
{{ ux_icon('tabler:alert-triangle') }}
</div>
<div>
<h3 class="settings-card-title">Danger Zone</h3>
<p class="settings-card-description">Irreversible actions</p>
</div>
</div>
<div class="card-body">
<!-- Danger actions with confirmation -->
</div>
</div>
List Pages (DataGrid)
Structure:
<div class="list-page">
<!-- 1. Page header with title + Create button -->
<div class="list-header">
<h1 class="list-title">Invoices</h1>
<div class="list-actions">
<a href="#" class="btn btn-primary">
{{ ux_icon('tabler:plus') }} Create Invoice
</a>
</div>
</div>
<!-- 2. Search/Filter bar (optional) -->
<div class="list-filters">
<div class="list-search">...</div>
<div class="list-filter-group">...</div>
</div>
<!-- 3. Data table -->
<div class="list-content">
<table class="table">...</table>
</div>
<!-- 4. Pagination -->
<div class="list-footer">
<span class="list-footer-info">Showing 1-10 of 50</span>
<nav class="pagination">...</nav>
</div>
</div>
Empty state:
<div class="list-empty">
<div class="list-empty-icon">
{{ ux_icon('tabler:file-invoice') }}
</div>
<h3 class="list-empty-title">No invoices yet</h3>
<p class="list-empty-description">Create your first invoice to get started.</p>
<a href="#" class="btn btn-primary">
{{ ux_icon('tabler:plus') }} Create Invoice
</a>
</div>
Form Pages (Create/Edit)
Structure:
<div class="form-page">
<form>
<div class="card">
<div class="card-header">
<h3 class="card-title">Create Invoice</h3>
</div>
<div class="card-body">
<!-- Form fields -->
</div>
<div class="card-footer">
<div class="form-actions">
<button type="button" class="btn btn-ghost">Cancel</button>
<button type="submit" class="btn btn-primary">
{{ ux_icon('tabler:device-floppy') }} Save
</button>
</div>
</div>
</div>
</form>
</div>
Modals
Standard modal:
<div class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal Title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<!-- Content -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-ghost" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary">Confirm</button>
</div>
</div>
</div>
</div>
Sizes: .modal-sm (400px), default (500px), .modal-lg (800px), .modal-xl (1140px)
Danger/Delete confirmation:
<div class="modal fade modal-danger">
<div class="modal-dialog modal-confirm">
<div class="modal-content">
<div class="modal-body">
<div class="modal-confirm-icon icon-danger">
{{ ux_icon('tabler:trash') }}
</div>
<h3 class="modal-confirm-title">Delete Invoice?</h3>
<p class="modal-confirm-message">This action cannot be undone.</p>
</div>
<div class="modal-footer">
<button class="btn btn-ghost">Cancel</button>
<button class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</div>
Alerts
Types and usage:
alert-success: Confirmation of completed actionalert-danger: Error messages, failed operationsalert-warning: Cautions, important noticesalert-info: Helpful tips, neutral informationalert-primary: Brand-related notifications
Structure:
<div class="alert alert-success" role="alert">
{{ ux_icon('tabler:check') }}
<div class="alert-content">
<div class="alert-title">Success!</div>
<div class="alert-message">Invoice has been saved.</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
Tables/DataGrids
Table styling:
- Headers: Uppercase, small text (
--swp-text-xs), muted color - Rows: Adequate padding (
1rem 1.5rem), subtle hover - Borders: Light gray (
--swp-border-light), minimal - No alternating row colors (hover is enough)
Column types:
.table-actions: Right-aligned, action buttons.table-checkbox: Checkbox column (narrow).table-date: Date column (no wrap).table-amount: Right-aligned, monospace.table-id: Monospace, muted
Animation Guidelines
Transitions:
- Hover effects:
150-200ms - State changes:
200-300ms - Modal open/close:
200ms
What to animate:
- Hover: Shadow increase, subtle lift (
translateY(-1px)) - Focus: Visible focus ring with primary color
- Button press: Return to baseline
What NOT to animate:
- Text content changes
- Active states (should be instant)
- Background images
Accessibility Checklist
- All interactive elements have visible focus states
- Color contrast ratio: 4.5:1 for text, 3:1 for UI
- Form fields have associated labels
- Required fields marked with
aria-required="true" - Error messages linked with
aria-describedby - Icon-only buttons have
aria-label - Modals trap focus and close on Escape
- Loading states announced to screen readers
File Reference
Design System (SolidInvoice custom styles):
| File | Purpose |
|---|---|
/assets/scss/design-system/_tokens.scss | Design tokens (colors, spacing, shadows, transitions) |
/assets/scss/design-system/_typography.scss | Typography scale and utility classes |
/assets/scss/_forms.scss | Form field enhancements |
/assets/scss/settings.scss | Settings page specific styles |
/src/CoreBundle/Resources/views/Form/fields.html.twig | Form field templates |
Platform UI Components:
| File | Purpose |
|---|---|
vendor/solidworx/platform/src/Bundle/Ui/Docs/Card.md | Card component documentation |
vendor/solidworx/platform/src/Bundle/Ui/Docs/Alert.md | Alert component documentation |
vendor/solidworx/platform/src/Bundle/Ui/Docs/Modal.md | Modal component documentation |
Note: Button, table, modal, and alert styling comes from Tabler/Bootstrap. Do not create custom component SCSS files that duplicate framework styles.
Quick Reference Checklist
When implementing any UI:
- ✅ Use Platform UI components (
<twig:Ui:Card>,<twig:Ui:Alert>,<twig:Ui:Modal>) when available - ✅ Use design tokens for all colors, spacing, shadows
- ✅ Follow form actions pattern (Cancel left/ghost, Save right/primary with icon)
- ✅ Use appropriate button variant for the action type
- ✅ Settings pages use tabs for < 8 sections
- ✅ Tables use Tabler/Bootstrap default styling
- ✅ Accessibility: focus states, ARIA labels, proper contrast
- ✅ Transitions are subtle and functional (150-300ms)
- ✅ No hardcoded color/spacing values - use CSS variables
- ✅ Do NOT duplicate Bootstrap/Tabler styles - use framework defaults
<frontend_aesthetics> You tend to converge toward generic, "on distribution" outputs. In frontend design, this creates what users call the "AI slop" aesthetic. Avoid this: make creative, distinctive frontends that surprise and delight. Focus on:
Typography: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics.
Color & Theme: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes. Draw from IDE themes and cultural aesthetics for inspiration.
Motion: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions.
Backgrounds: Create atmosphere and depth rather than defaulting to solid colors. Layer CSS gradients, use geometric patterns, or add contextual effects that match the overall aesthetic.
Avoid generic AI-generated aesthetics:
- Overused font families (Inter, Roboto, Arial, system fonts)
- Clichéd color schemes (particularly purple gradients on white backgrounds)
- Predictable layouts and component patterns
- Cookie-cutter design that lacks context-specific character
Interpret creatively and make unexpected choices that feel genuinely designed for the context. Vary between light and dark themes, different fonts, different aesthetics. You still tend to converge on common choices (Space Grotesk, for example) across generations. Avoid this: it is critical that you think outside the box! </frontend_aesthetics>
Last Updated: 2025-12-31 Document Version: 1.1.0 SolidInvoice Version: 3.0.0-dev
Related Documents
How you work
You are a coding agent running in the Codex CLI, a terminal-based coding assistant. Codex CLI is an open source project led by OpenAI. You are expected to be precise, safe, and helpful.
内置 Agent 提示词
Claude Code 内置了 6 个子 Agent,各自有独立的系统提示词和工具权限,用于分工处理不同类型的子任务。以下是每个 Agent 的完整系统提示词。
Overture Integration for Claude Code
You have access to **Overture**, an MCP server that visualizes your execution plans as interactive flowcharts before you write any code.